Fix Carbon:: name leakage across files. (#7973)

Split the `Carbon::` namespace into one semantic namespace tree, plus
one separate lookup-only namespace tree per Carbon file. Use the
semantic namespaces as the parents of entities, but use the lookup-only
namespaces when C++ name lookup names a Carbon namespace, in order to
use a different C++ name lookup table in each Carbon file.

Assisted-by: Gemini via Antigravity
This commit is contained in:
Richard Smith authored and GitHub committed 2026-10-16 20:59:16 +00:00
1 parent 0d3b606a56
commit d08805f1a6
10 files changed
+299 -79

No files matched your search

+3
View File
@@ -94,6 +94,9 @@ auto CheckUnit::Run() -> void {
if (!ProcessNodeIds()) {
context_.sem_ir().set_has_errors(true);
// TODO: Are there more steps from `FinishRun` we should be doing here?
FinishAst(context_);
return;
}
+20
View File
@@ -9,15 +9,18 @@
#include "clang/Basic/SourceLocation.h"
#include "common/check.h"
#include "common/map.h"
#include "llvm/ADT/SmallVector.h"
#include "toolchain/check/cpp/diagnostic_listener.h"
#include "toolchain/sem_ir/cpp_domain.h"
#include "toolchain/sem_ir/ids.h"
namespace clang {
class ASTContext;
class CompilerInstance;
class FunctionDecl;
class MangleContext;
class NamespaceDecl;
class Parser;
class Sema;
} // namespace clang
@@ -48,6 +51,17 @@ class CppContext {
return carbon_file_locations_;
}
auto carbon_lookup_namespace() const -> clang::NamespaceDecl* {
return carbon_lookup_namespace_;
}
void set_carbon_lookup_namespace(clang::NamespaceDecl* decl) {
carbon_lookup_namespace_ = decl;
}
auto lookup_namespaces() -> Map<SemIR::NameScopeId, clang::NamespaceDecl*>& {
return lookup_namespaces_;
}
auto placement_new_decl() const -> clang::FunctionDecl* {
return placement_new_decl_;
}
@@ -59,6 +73,12 @@ class CppContext {
// The C++ compilation domain.
SemIR::CppDomain* domain_;
// The per-file lookup-only `::Carbon` namespace and child namespaces.
// These are only used for C++ name lookup within this Carbon file, and are
// never used as the parent `DeclContext` for exported Carbon entities.
clang::NamespaceDecl* carbon_lookup_namespace_ = nullptr;
Map<SemIR::NameScopeId, clang::NamespaceDecl*> lookup_namespaces_;
// TODO: All of the below state that is not specific to a particular
// Check::Context or SemIR::File should be moved into CppDomain.
+97 -30
View File
@@ -91,25 +91,105 @@ static auto ExportClassToCppInDeclContext(Context& context,
return record_decl;
}
auto ExportPackageNamespaceToCpp(Context& context,
clang::DeclContext* carbon_namespace,
clang::IdentifierInfo* package_identifier)
auto CreateSemanticNamespace(Context& context,
clang::DeclContext* parent_context,
clang::IdentifierInfo* identifier)
-> clang::NamespaceDecl* {
auto& package_namespaces =
context.cpp_context()->domain().package_namespaces();
auto [it, inserted] =
package_namespaces.try_emplace(package_identifier->getName(), nullptr);
if (inserted) {
// TODO: Provide a source location.
auto* namespace_decl = clang::NamespaceDecl::Create(
context.ast_context(), parent_context, /*Inline=*/false,
clang::SourceLocation(), clang::SourceLocation(), identifier,
/*PrevDecl=*/nullptr, /*Nested=*/false);
// This declaration should never be made visible to name lookups. Clear its
// set of associated identifier namespaces, which indicates that it should not
// be found by any kind of lookup.
namespace_decl->clearIdentifierNamespace();
parent_context->addHiddenDecl(namespace_decl);
return namespace_decl;
}
auto ExportNamespaceToCpp(Context& context, clang::DeclContext* parent_context,
clang::IdentifierInfo* identifier)
-> clang::NamespaceDecl* {
auto& namespaces = context.cpp_context()->domain().semantic_namespaces();
auto result = namespaces.Insert(std::pair{parent_context, identifier}, [&] {
return CreateSemanticNamespace(context, parent_context, identifier);
});
return result.value();
}
auto ExportLookupNamespaceToCpp(Context& context, SemIR::LocId loc_id,
SemIR::NameScopeId name_scope_id)
-> clang::DeclContext* {
auto& lookup_namespaces = context.cpp_context()->lookup_namespaces();
llvm::SmallVector<SemIR::NameScopeId> name_scope_ids_to_create;
// Collect all the enclosing Carbon namespaces that don't have a corresponding
// C++ namespace.
clang::DeclContext* decl_context = nullptr;
while (true) {
if (auto lookup = lookup_namespaces.Lookup(name_scope_id)) {
decl_context = lookup.value();
break;
}
const auto& name_scope = context.name_scopes().Get(name_scope_id);
if (name_scope.is_cpp_scope()) {
decl_context = GetClangDeclContextForScope(context, name_scope_id);
CARBON_CHECK(decl_context);
break;
}
CARBON_CHECK(context.name_scopes().InstIs<SemIR::Namespace>(name_scope_id),
"Parent of namespace is non-namespace {0}",
context.name_scopes().GetInstIfValid(name_scope_id).second);
name_scope_ids_to_create.push_back(name_scope_id);
name_scope_id = name_scope.parent_scope_id();
CARBON_CHECK(
name_scope_id.has_value(),
"Reached the top level without finding a scope mapped into C++");
}
// Build each new lookup namespace, from the outermost one inwards. The
// enclosing namespaces aren't necessary semantically, but they allow Clang to
// produce diagnostics that match the way we want the contents of namespace
// `Carbon` to be named.
for (auto name_scope_id : llvm::reverse(name_scope_ids_to_create)) {
const auto& name_scope = context.name_scopes().Get(name_scope_id);
auto* identifier_info =
GetClangIdentifierInfo(context, name_scope.name_id());
if (!identifier_info) {
// TODO: Handle keyword package names like `Cpp` and `Core`. These can
// be named from C++ via an alias.
context.TODO(loc_id, "interop with non-identifier package name");
return nullptr;
}
// TODO: Provide a source location.
auto* namespace_decl = clang::NamespaceDecl::Create(
context.ast_context(), carbon_namespace, /*Inline=*/false,
clang::SourceLocation(), clang::SourceLocation(), package_identifier,
context.ast_context(), decl_context, /*Inline=*/false,
clang::SourceLocation(), clang::SourceLocation(), identifier_info,
/*PrevDecl=*/nullptr, /*Nested=*/false);
carbon_namespace->addHiddenDecl(namespace_decl);
it->second = namespace_decl;
// Add the declaration to the enclosing scope. We are providing lookup
// results in that enclosing scope, so don't add it to Clang's name lookup
// table.
decl_context->addHiddenDecl(namespace_decl);
// Notify Clang that we are providing lookup results in the new namespace
// too.
namespace_decl->setHasExternalVisibleStorage();
auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(namespace_decl);
context.clang_decls().Add({.key = key, .inst_id = name_scope.inst_id()});
lookup_namespaces.Insert(name_scope_id, namespace_decl);
decl_context = namespace_decl;
}
it->second->getPrimaryContext()->setHasExternalVisibleStorage();
return it->second;
return decl_context;
}
auto ExportNameScopeToCpp(Context& context, SemIR::LocId loc_id,
@@ -136,9 +216,7 @@ auto ExportNameScopeToCpp(Context& context, SemIR::LocId loc_id,
if (name_scope.is_imported_package()) {
// Imported packages are exported as sub-namespaces of `::Carbon`, not of
// the current package's sub-namespace.
decl_context =
GetClangDeclContextForScope(context, SemIR::NameScopeId::Package)
->getParent();
decl_context = context.cpp_context()->domain().carbon_namespace();
break;
}
name_scope_id = name_scope.parent_scope_id();
@@ -167,17 +245,8 @@ auto ExportNameScopeToCpp(Context& context, SemIR::LocId loc_id,
return nullptr;
}
if (name_scope.is_imported_package()) {
decl_context =
ExportPackageNamespaceToCpp(context, decl_context, identifier_info);
} else {
// TODO: Provide a source location.
auto* namespace_decl = clang::NamespaceDecl::Create(
context.ast_context(), decl_context, false, clang::SourceLocation(),
clang::SourceLocation(), identifier_info, nullptr, false);
decl_context->addHiddenDecl(namespace_decl);
decl_context = namespace_decl;
}
decl_context =
ExportNamespaceToCpp(context, decl_context, identifier_info);
} else if (auto class_type =
context.insts().TryGetAs<SemIR::ClassType>(const_inst_id)) {
const auto& class_info = context.classes().Get(class_type->class_id);
@@ -188,8 +257,6 @@ auto ExportNameScopeToCpp(Context& context, SemIR::LocId loc_id,
return nullptr;
}
decl_context->setHasExternalVisibleStorage();
auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(
cast<clang::Decl>(decl_context));
auto clang_decl_id = context.clang_decls().Add(
+25 -5
View File
@@ -17,13 +17,33 @@ class CXXRecordDecl;
namespace Carbon::Check {
// Exports a Carbon package into C++ as a sub-namespace of `carbon_namespace`,
// or returns the existing namespace if already exported in this C++ domain.
auto ExportPackageNamespaceToCpp(Context& context,
clang::DeclContext* carbon_namespace,
clang::IdentifierInfo* package_identifier)
// Creates a namespace to use as a semantic parent for exported C++ entities.
// This is used for the root `Carbon` namespace, the package namespaces within
// it, and any nested namespaces within those packages. Does not register the
// namespace as corresponding to any particular Carbon entity.
auto CreateSemanticNamespace(Context& context,
clang::DeclContext* parent_context,
clang::IdentifierInfo* identifier)
-> clang::NamespaceDecl*;
// Exports a Carbon namespace into C++ as a semantic sub-namespace of
// `parent_context` (used as the parent `DeclContext` of exported Carbon
// entities), or returns the existing namespace if already exported in this C++
// domain.
auto ExportNamespaceToCpp(Context& context, clang::DeclContext* parent_context,
clang::IdentifierInfo* identifier)
-> clang::NamespaceDecl*;
// Exports a Carbon namespace into C++ as a per-file lookup-only
// `NamespaceDecl`, or returns the C++ declaration context if it was imported
// from C++. Lookup-only namespaces are only used for C++ name lookup in the
// current Carbon file, and are never the parent `DeclContext` of anything
// other than child lookup-only namespaces, so that references to Carbon
// entities are mangled consistently.
auto ExportLookupNamespaceToCpp(Context& context, SemIR::LocId loc_id,
SemIR::NameScopeId name_scope_id)
-> clang::DeclContext*;
// Exports a Carbon name scope into C++ as a namespace or class, or returns the
// C++ namespace or class declaration that it was imported from.
//
+64 -30
View File
@@ -214,8 +214,8 @@ auto CarbonExternalASTSource::MapInstIdToClangDeclOrType(LookupResult lookup)
CARBON_KIND_SWITCH(target_inst) {
case CARBON_KIND(SemIR::Namespace namespace_info): {
auto* decl_context =
ExportNameScopeToCpp(*context_, SemIR::LocId(target_inst_id),
namespace_info.name_scope_id);
ExportLookupNamespaceToCpp(*context_, SemIR::LocId(target_inst_id),
namespace_info.name_scope_id);
if (!decl_context) {
return nullptr;
}
@@ -258,39 +258,28 @@ auto CarbonExternalASTSource::BuildCarbonNamespace() -> void {
auto& ast_context = context_->ast_context();
auto* identifier = &ast_context.Idents.get(carbon_namespace_name);
auto* decl_context = ast_context.getTranslationUnitDecl();
auto* tu_decl = ast_context.getTranslationUnitDecl();
// Check if it already exists.
clang::NamespaceDecl* carbon_cpp_namespace = nullptr;
auto lookup_result = decl_context->lookup(identifier);
if (!lookup_result.empty()) {
carbon_cpp_namespace = cast<clang::NamespaceDecl>(lookup_result.front());
} else {
// Create it if it doesn't exist.
carbon_cpp_namespace = clang::NamespaceDecl::Create(
ast_context, decl_context, /*Inline=*/false, clang::SourceLocation(),
clang::SourceLocation(), identifier, /*PrevDecl=*/nullptr,
/*Nested=*/false);
decl_context->addDecl(carbon_cpp_namespace);
// Create or find the semantic `::Carbon` namespace for this C++ domain, which
// is used as the parent `DeclContext` for package sub-namespaces.
auto& domain = context_->cpp_context()->domain();
auto* semantic_carbon_namespace = domain.carbon_namespace();
if (!semantic_carbon_namespace) {
semantic_carbon_namespace =
CreateSemanticNamespace(*context_, tu_decl, identifier);
domain.set_carbon_namespace(semantic_carbon_namespace);
}
// We provide custom lookup results within this namespace.
carbon_cpp_namespace->getPrimaryContext()->setHasExternalVisibleStorage();
// Create or find the sub-namespace for this file's package, which is used as
// the parent `DeclContext` for package-scope entities so that the package
// name is included in C++ mangled names.
// Create or find the semantic sub-namespace for this file's package, which is
// used as the parent `DeclContext` for package-scope entities so that the
// package name is included in C++ mangled names.
auto& package_scope =
context_->name_scopes().Get(SemIR::NameScopeId::Package);
auto package_name = context_->names().GetIRBaseName(package_scope.name_id());
auto* package_identifier = &ast_context.Idents.get(package_name);
auto* package_cpp_namespace = ExportPackageNamespaceToCpp(
*context_, carbon_cpp_namespace, package_identifier);
auto* package_cpp_namespace = ExportNamespaceToCpp(
*context_, semantic_carbon_namespace, package_identifier);
// Register this file's package scope as corresponding to the package
// sub-namespace in C++, and also map the `Carbon` namespace itself to the
// package scope so that C++ lookups in `Carbon` find package-scope entities
// directly (and do not find the current package name).
auto package_key =
SemIR::ClangDeclKey::ForNonFunctionDecl(package_cpp_namespace);
auto package_clang_decl_id = context_->clang_decls().Add(
@@ -298,8 +287,22 @@ auto CarbonExternalASTSource::BuildCarbonNamespace() -> void {
package_scope.set_clang_decl_context_id(package_clang_decl_id,
/*is_cpp_scope=*/false);
// Create a per-file lookup-only `::Carbon` namespace, mapped to the package
// scope so that C++ lookups in `Carbon` find package-scope entities directly
// (and do not find the current package name), and are isolated to this file.
auto* lookup_carbon_namespace = clang::NamespaceDecl::Create(
ast_context, tu_decl, /*Inline=*/false, clang::SourceLocation(),
clang::SourceLocation(), identifier, /*PrevDecl=*/nullptr,
/*Nested=*/false);
tu_decl->addDecl(lookup_carbon_namespace);
lookup_carbon_namespace->setHasExternalVisibleStorage();
context_->cpp_context()->set_carbon_lookup_namespace(lookup_carbon_namespace);
context_->cpp_context()->lookup_namespaces().Insert(
SemIR::NameScopeId::Package, lookup_carbon_namespace);
auto carbon_key =
SemIR::ClangDeclKey::ForNonFunctionDecl(carbon_cpp_namespace);
SemIR::ClangDeclKey::ForNonFunctionDecl(lookup_carbon_namespace);
context_->clang_decls().Add(
{.key = carbon_key, .inst_id = SemIR::Namespace::PackageInstId});
}
@@ -394,14 +397,30 @@ auto CarbonExternalASTSource::FindExternalVisibleDeclsByName(
}
case CARBON_KIND(clang::QualType type): {
// Create a typedef declaration to model the type result.
// Create a typedef declaration to model the type result. We create the
// typedef declaration in whatever name context the lookup was performed
// in, since we don't have a Carbon declaration to take a name scope from.
// But if that context was a namespace, map from the lookup-only namespace
// to the corresponding semantic namespace so that lookup-only
// NamespaceDecls are never the parent DeclContext of exported entities.
// TODO: If the type is a tag type that was declared with this name in
// this context, use the tag decl directly.
auto* semantic_decl_context = decl_context;
if (auto namespace_info = context_->insts().TryGetAs<SemIR::Namespace>(
clang_decl->inst_id)) {
semantic_decl_context = ExportNameScopeToCpp(
*context_, SemIR::LocId(result.scope_result.target_inst_id()),
namespace_info->name_scope_id);
if (!semantic_decl_context) {
SetNoExternalVisibleDeclsForName(decl_context, decl_name);
return false;
}
}
auto& ast_context = context_->ast_context();
auto loc = GetCppLocation(
*context_, SemIR::LocId(result.scope_result.target_inst_id()));
auto* typedef_decl = clang::TypedefDecl::Create(
ast_context, decl_context, loc, loc, identifier,
ast_context, semantic_decl_context, loc, loc, identifier,
ast_context.getTrivialTypeSourceInfo(type, loc));
if (isa<clang::CXXRecordDecl>(decl_context)) {
typedef_decl->setAccess(
@@ -1097,6 +1116,21 @@ auto FinishAst(Context& context) -> void {
*context.cpp_context()->sema().getDiagnostics().getClient());
context.emitter().Flush();
// Hide the per-file lookup-only `::Carbon` namespace from the further lookup
// results and remove it from the translation unit's name lookup table if it's
// already there, so that subsequent files in a shared C++ AST domain do not
// see it.
if (auto* lookup_ns = context.cpp_context()->carbon_lookup_namespace()) {
lookup_ns->clearIdentifierNamespace();
auto* tu_decl = context.ast_context().getTranslationUnitDecl();
if (auto* lookup = tu_decl->getLookupPtr()) {
if (auto it = lookup->find(lookup_ns->getDeclName());
it != lookup->end()) {
it->second.remove(lookup_ns);
}
}
}
// Remove the `CarbonExternalASTSource` installed in `GenerateAst` and
// replace it with a `ReadOnlyASTSource`. This is necessary because
// the source may be accessed later during lowering, but the
@@ -71,9 +71,20 @@ template <typename T> void Accept(T) {}
''';
class SameName {}
alias TypeAlias = i32;
namespace N;
class N.SameNested {}
fn TestPkgA(s: SameName) {
inline Cpp '''
void CheckPkgA(Carbon::SameName, Carbon::N::SameNested) {
Carbon::TypeAlias x = 0;
static_assert(sizeof(x) == 4);
}
''';
fn TestPkgA(s: SameName, n: N.SameNested) {
Cpp.Accept(s);
Cpp.CheckPkgA(s, n);
}
// --- pkg_b.carbon
@@ -83,9 +94,20 @@ template <typename T> void Accept(T) {}
''';
class SameName {}
alias TypeAlias = i64;
namespace N;
class N.SameNested {}
fn TestPkgB(s: SameName) {
inline Cpp '''
void CheckPkgB(Carbon::SameName, Carbon::N::SameNested) {
Carbon::TypeAlias x = 0;
static_assert(sizeof(x) == 8);
}
''';
fn TestPkgB(s: SameName, n: N.SameNested) {
Cpp.Accept(s);
Cpp.CheckPkgB(s, n);
}
// --- use_both_packages.carbon
@@ -93,8 +115,41 @@ library "[[@TEST_NAME]]";
import PkgA;
import PkgB;
import Cpp inline '''
// SameName in PkgA and PkgB have distinct C++ DeclContexts (Carbon::PkgA vs
// Carbon::PkgB), so overloading on them in C++ succeeds.
// SameName and N::SameNested in PkgA and PkgB have distinct C++ DeclContexts
// (Carbon::PkgA vs Carbon::PkgB), so overloading on them in C++ succeeds.
void OverloadByPackage(Carbon::PkgA::SameName*) {}
void OverloadByPackage(Carbon::PkgB::SameName*) {}
void OverloadNestedByPackage(Carbon::PkgA::N::SameNested*) {}
void OverloadNestedByPackage(Carbon::PkgB::N::SameNested*) {}
''';
// --- export_in_c.carbon
library "[[@TEST_NAME]]";
import Cpp;
class ExportedClass {}
namespace N;
class N.ExportedNested {}
inline Cpp '''
using UseExported = Carbon::ExportedClass;
using UseNested = Carbon::N::ExportedNested;
''';
// --- fail_carbon_export_does_not_leak.carbon
library "[[@TEST_NAME]]";
import Cpp;
namespace N;
inline Cpp '''
// CHECK:STDERR: fail_carbon_export_does_not_leak.carbon:[[@LINE+2]]:23: error: no type named 'ExportedClass' in namespace 'Carbon' [CppInteropParseError]
// CHECK:STDERR:
using Leak1 = Carbon::ExportedClass;
// CHECK:STDERR: fail_carbon_export_does_not_leak.carbon:[[@LINE+2]]:26: error: no type named 'ExportedNested' in namespace 'Carbon::N' [CppInteropParseError]
// CHECK:STDERR:
using Leak2 = Carbon::N::ExportedNested;
// CHECK:STDERR: fail_carbon_export_does_not_leak.carbon:[[@LINE+2]]:23: error: no member named 'PkgA' in namespace 'Carbon' [CppInteropParseError]
// CHECK:STDERR:
using Leak3 = Carbon::PkgA::SameName;
''';
@@ -13,7 +13,7 @@
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/export/thunk_ast.carbon
// CHECK:STDOUT: TranslationUnitDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc>
// CHECK:STDOUT: |-EmptyDecl {{0x[a-f0-9]+}} <<carbon Cpp imports>:1:1> col:1
// CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> referenced Carbon external-linkage
// CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Carbon external-linkage
// CHECK:STDOUT: | `-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Main external-linkage
// --- thunk_with_args_and_return.carbon
@@ -40,17 +40,18 @@ fn F(i: i32) -> i32 {
// CHECK:STDOUT: | | `-DeclRefExpr {{0x[a-f0-9]+}} <col:21> 'int' lvalue Var {{0x[a-f0-9]+}} 'return_storage' 'int'
// CHECK:STDOUT: | |-AlwaysInlineAttr {{0x[a-f0-9]+}} <<invalid sloc>> Implicit always_inline
// CHECK:STDOUT: | `-InternalLinkageAttr {{0x[a-f0-9]+}} <<invalid sloc>> Implicit
// CHECK:STDOUT: |-FunctionDecl {{0x[a-f0-9]+}} <line:39:1, line:41:1> line:39:5 in thunk_with_args_and_return.carbon hidden G 'int (int)' external-linkage
// CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> referenced Carbon external-linkage
// CHECK:STDOUT: |-FunctionDecl {{0x[a-f0-9]+}} <line:40:1, line:42:1> line:40:5 in thunk_with_args_and_return.carbon hidden G 'int (int)' external-linkage
// CHECK:STDOUT: | |-ParmVarDecl {{0x[a-f0-9]+}} <col:7, col:11> col:11 in thunk_with_args_and_return.carbon hidden used i 'int'
// CHECK:STDOUT: | `-CompoundStmt {{0x[a-f0-9]+}} <col:14, line:41:1>
// CHECK:STDOUT: | `-ReturnStmt {{0x[a-f0-9]+}} <line:40:3, col:21>
// CHECK:STDOUT: | `-CompoundStmt {{0x[a-f0-9]+}} <col:14, line:42:1>
// CHECK:STDOUT: | `-ReturnStmt {{0x[a-f0-9]+}} <line:41:3, col:21>
// CHECK:STDOUT: | `-CallExpr {{0x[a-f0-9]+}} <col:10, col:21> 'int'
// CHECK:STDOUT: | |-ImplicitCastExpr {{0x[a-f0-9]+}} <col:10, col:18> 'int (*)(int)' <FunctionToPointerDecay>
// CHECK:STDOUT: | | `-DeclRefExpr {{0x[a-f0-9]+}} <col:10, col:18> 'int (int)' lvalue Function {{0x[a-f0-9]+}} 'F' 'int (int)'
// CHECK:STDOUT: | | `-NestedNameSpecifier Namespace {{0x[a-f0-9]+}} 'Carbon'
// CHECK:STDOUT: | `-ImplicitCastExpr {{0x[a-f0-9]+}} <col:20> 'int' <LValueToRValue>
// CHECK:STDOUT: | `-DeclRefExpr {{0x[a-f0-9]+}} <col:20> 'int' lvalue ParmVar {{0x[a-f0-9]+}} 'i' 'int'
// CHECK:STDOUT: `-ImportDecl {{0x[a-f0-9]+}} <line:42:4> col:4 in thunk_with_args_and_return.carbon implicit thunk_with_args_and_return.carbon
// CHECK:STDOUT: `-ImportDecl {{0x[a-f0-9]+}} <line:43:4> col:4 in thunk_with_args_and_return.carbon implicit thunk_with_args_and_return.carbon
return i;
}
@@ -15,6 +15,7 @@
// CHECK:STDOUT: |-EmptyDecl {{0x[a-f0-9]+}} <<carbon Cpp imports>:1:1> col:1
// CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Carbon external-linkage
// CHECK:STDOUT: | `-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Main external-linkage
// CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Carbon external-linkage
// --- thunk_required.h
@@ -46,11 +47,12 @@ fn F() {
Cpp.foo(1 as i16);
}
// CHECK:STDOUT: `-ImportDecl {{0x[a-f0-9]+}} <import_thunk_required.carbon:[[@LINE+4]]:104> col:104 in import_thunk_required.carbon implicit import_thunk_required.carbon
// CHECK:STDOUT: `-ImportDecl {{0x[a-f0-9]+}} <import_thunk_required.carbon:[[@LINE+5]]:104> col:104 in import_thunk_required.carbon implicit import_thunk_required.carbon
// CHECK:STDOUT: TranslationUnitDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc>
// CHECK:STDOUT: |-EmptyDecl {{0x[a-f0-9]+}} <<carbon Cpp imports>:1:1> col:1
// CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Carbon external-linkage
// CHECK:STDOUT: | `-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Main external-linkage
// CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <<invalid sloc>> <invalid sloc> Carbon external-linkage
// --- return_thunk_required.h
auto foo() -> short;
@@ -64,7 +64,7 @@ void TestLookupFailureInNested() {
// second is a Carbon error for declaring a poisoned name. Normally we would
// suppress the first error when we produce the second, but we don't do that
// when the first error is produced by Clang.
// CHECK:STDERR: fail_declare_after_poisoning_with_lookup_failure.carbon:[[@LINE+3]]:19-31: error: no member named 'LaterInNested' in namespace 'Carbon::Main::Nested' [CppInteropParseError]
// CHECK:STDERR: fail_declare_after_poisoning_with_lookup_failure.carbon:[[@LINE+3]]:19-31: error: no member named 'LaterInNested' in namespace 'Carbon::Nested' [CppInteropParseError]
// CHECK:STDERR:
// CHECK:STDERR: fail_declare_after_poisoning_with_lookup_failure.carbon:[[@LINE+1]]:19: error: name `LaterInNested` used before it was declared [NameUseBeforeDecl]
Carbon::Nested::LaterInNested();
+21 -3
View File
@@ -6,6 +6,7 @@
#define CARBON_TOOLCHAIN_SEM_IR_CPP_DOMAIN_H_
#include <memory>
#include <utility>
#include "common/check.h"
#include "common/map.h"
@@ -16,6 +17,8 @@
namespace clang {
class CodeGenerator;
class CompilerInstance;
class DeclContext;
class IdentifierInfo;
class Module;
class NamespaceDecl;
class Parser;
@@ -42,6 +45,14 @@ struct CppInputFile {
// parse more code into that domain. May be shared across multiple Carbon files.
class CppDomain {
public:
// A map from parent context and namespace name to semantic namespace, for
// cross-file deduplication of exported packages and namespaces. We use the
// same semantic C++ namespace for the same Carbon package and namespace path
// in every file.
using SemanticNamespacesMap =
Map<std::pair<clang::DeclContext*, clang::IdentifierInfo*>,
clang::NamespaceDecl*>;
explicit CppDomain(std::shared_ptr<clang::CompilerInstance> clang_instance,
std::unique_ptr<clang::Parser> parser,
llvm::ArrayRef<CppInputFile> inputs,
@@ -68,8 +79,14 @@ class CppDomain {
auto header_modules() -> llvm::StringMap<clang::Module*>& {
return header_modules_;
}
auto package_namespaces() -> llvm::StringMap<clang::NamespaceDecl*>& {
return package_namespaces_;
auto carbon_namespace() const -> clang::NamespaceDecl* {
return carbon_namespace_;
}
auto set_carbon_namespace(clang::NamespaceDecl* carbon_namespace) -> void {
carbon_namespace_ = carbon_namespace;
}
auto semantic_namespaces() -> SemanticNamespacesMap& {
return semantic_namespaces_;
}
private:
@@ -78,7 +95,8 @@ class CppDomain {
Map<CheckIRId, clang::CodeGenerator*> code_generators_;
Map<CheckIRId, clang::Module*> modules_;
llvm::StringMap<clang::Module*> header_modules_;
llvm::StringMap<clang::NamespaceDecl*> package_namespaces_;
clang::NamespaceDecl* carbon_namespace_ = nullptr;
SemanticNamespacesMap semantic_namespaces_;
llvm::LLVMContext* llvm_context_ = nullptr;
};