mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-11-15 16:18:12 +00:00
Fix exporting of names to C++ after a lookup failure. (#7933)
If Clang encounters a lookup failure, it caches that result, creating problems with `-share-cpp-ast` where a lookup failure in one file effectively poisons the same name when looked up in a different file. Also, if Clang triggers loading a complete name table (which happens, for example, during typo correction, but Clang could do that any time it wants to), it clears out the "has external visible results" flag, which means that introducing new names in Carbon and then attempting to use them from C++ after that point does not work. Fix both of these problems by re-enabling the "has external visible results" flag on callbacks that indicate Clang just cleared it, and by not caching failed name lookups into Carbon scopes in Clang's lookup table. (They still get cached in *our* lookup table.) Assisted-by: Gemini via Antigravity
This commit is contained in:
1 parent
a045da8e67
commit
e476a2bd3b
6 files changed
+293
-29
No files matched your search
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclContextInternals.h"
|
||||
#include "clang/AST/Mangle.h"
|
||||
#include "clang/Basic/DiagnosticParse.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
@@ -271,11 +272,11 @@ auto CarbonExternalASTSource::BuildCarbonNamespace() -> void {
|
||||
clang::SourceLocation(), identifier, /*PrevDecl=*/nullptr,
|
||||
/*Nested=*/false);
|
||||
decl_context->addDecl(carbon_cpp_namespace);
|
||||
|
||||
// We provide custom lookup results within this namespace.
|
||||
carbon_cpp_namespace->setHasExternalVisibleStorage();
|
||||
}
|
||||
|
||||
// We provide custom lookup results within this namespace.
|
||||
carbon_cpp_namespace->getPrimaryContext()->setHasExternalVisibleStorage();
|
||||
|
||||
// Register this file's package scope as corresponding to the `Carbon`
|
||||
// namespace in C++.
|
||||
// TODO: For mangling purposes, include the package as a sub-namespace.
|
||||
@@ -290,24 +291,26 @@ auto CarbonExternalASTSource::BuildCarbonNamespace() -> void {
|
||||
auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
|
||||
const clang::DeclContext* decl_context, clang::DeclarationName decl_name,
|
||||
const clang::DeclContext* /*OriginalDC*/) -> bool {
|
||||
// Find the Carbon declaration corresponding to this Clang declaration.
|
||||
auto* decl = cast<clang::Decl>(
|
||||
const_cast<clang::DeclContext*>(decl_context->getPrimaryContext()));
|
||||
if (isa<clang::FunctionDecl>(decl)) {
|
||||
// Functions don't meaningfully have visible decls, but bail out early since
|
||||
// we can't form a `ClangDeclKey` for a function in the abstract.
|
||||
auto clang_decl = GetCarbonOwnedDecl(decl_context);
|
||||
if (!clang_decl) {
|
||||
return false;
|
||||
}
|
||||
auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(decl);
|
||||
auto decl_id = context_->clang_decls().LookupId(key);
|
||||
if (!decl_id.has_value()) {
|
||||
return false;
|
||||
}
|
||||
auto clang_decl = context_->clang_decls().Get(decl_id);
|
||||
if (clang_decl.is_imported) {
|
||||
// This is imported from C++, presumably from a Clang AST file, so it's not
|
||||
// our responsibility to provide its name lookup results.
|
||||
return false;
|
||||
|
||||
auto* primary_context =
|
||||
const_cast<clang::DeclContext*>(decl_context->getPrimaryContext());
|
||||
if (auto* lookup_map = primary_context->getLookupPtr()) {
|
||||
if (auto it = lookup_map->find(decl_name);
|
||||
it != lookup_map->end() && !it->second.isNull()) {
|
||||
// We already exported declarations for this name, and may have been
|
||||
// asked again after `completeVisibleDeclsMap` re-enabled external
|
||||
// visible storage. Mark external lookup complete without re-exporting.
|
||||
//
|
||||
// Note that this only sets that there are no external decls from an AST
|
||||
// file, despite its name. External visible decls already added by other
|
||||
// AST sources, such as this one, are retained.
|
||||
SetNoExternalVisibleDeclsForName(primary_context, decl_name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
llvm::SmallVector<Check::LookupScope> lookup_scopes;
|
||||
@@ -316,7 +319,7 @@ auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
|
||||
// here - completeness should've been checked by clang before this point.
|
||||
if (!AppendLookupScopesForConstant(
|
||||
*context_, SemIR::LocId::None,
|
||||
context_->constant_values().Get(clang_decl.inst_id),
|
||||
context_->constant_values().Get(clang_decl->inst_id),
|
||||
SemIR::ConstantId::None, /*extended_scope=*/false, &lookup_scopes)) {
|
||||
return false;
|
||||
}
|
||||
@@ -335,6 +338,7 @@ auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SetNoExternalVisibleDeclsForName(primary_context, decl_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -342,18 +346,26 @@ auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
|
||||
|
||||
// `required=false` so Carbon doesn't diagnose a failure, let Clang diagnose
|
||||
// it or even SFINAE.
|
||||
LookupResult result =
|
||||
LookupQualifiedName(*context_, SemIR::LocId::None, name_id, lookup_scopes,
|
||||
/*required=*/false);
|
||||
LookupResult result = LookupQualifiedName(*context_, GetCurrentCppLocId(),
|
||||
name_id, lookup_scopes,
|
||||
/*required=*/false);
|
||||
if (!result.scope_result.is_found()) {
|
||||
// Avoid caching a negative lookup, as a declaration with this name may be
|
||||
// added in Carbon later.
|
||||
if (auto* lookup_map = primary_context->getLookupPtr()) {
|
||||
if (auto it = lookup_map->find(decl_name);
|
||||
it != lookup_map->end() && it->second.isNull()) {
|
||||
lookup_map->erase(it);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map the found Carbon entity to a Clang NamedDecl.
|
||||
CARBON_KIND_SWITCH(MapInstIdToClangDeclOrType(result)) {
|
||||
case CARBON_KIND(clang::NamedDecl* clang_decl): {
|
||||
if (clang_decl) {
|
||||
SetExternalVisibleDeclsForName(decl_context, decl_name, {clang_decl});
|
||||
case CARBON_KIND(clang::NamedDecl* mapped_decl): {
|
||||
if (mapped_decl) {
|
||||
SetExternalVisibleDeclsForName(decl_context, decl_name, {mapped_decl});
|
||||
return true;
|
||||
} else {
|
||||
SetNoExternalVisibleDeclsForName(decl_context, decl_name);
|
||||
|
||||
Reference in new issue
Block a user