diff --git a/toolchain/check/import.cpp b/toolchain/check/import.cpp index af20bb8a7627..abbd41e8e9d0 100644 --- a/toolchain/check/import.cpp +++ b/toolchain/check/import.cpp @@ -89,12 +89,53 @@ static auto CopyNameFromImportIR(Context& context, return import_name_id; } +// Returns the LocIdandInst for the namespace. +static auto MakeImportedNamespaceLocIdAndInst(Context& context, + SemIR::InstId import_id, + SemIR::Namespace namespace_inst) + -> SemIR::LocIdAndInst { + if (import_id.has_value()) { + SemIR::LocId import_loc_id = context.insts().GetLocId(import_id); + return import_loc_id.is_import_ir_inst_id() + ? MakeImportedLocIdAndInst( + context, import_loc_id.import_ir_inst_id(), namespace_inst) + // TODO: Check that this actually is an `AnyNamespaceId`. + : SemIR::LocIdAndInst( + Parse::AnyNamespaceId::UnsafeMake(import_loc_id.node_id()), + namespace_inst); + } + + // TODO: Associate the namespace with a proper location. This is related to: + // https://github.com/carbon-language/carbon-lang/issues/4666. + return SemIR::LocIdAndInst::NoLoc(namespace_inst); +} + auto AddImportNamespace(Context& context, SemIR::TypeId namespace_type_id, SemIR::NameId name_id, SemIR::NameScopeId parent_scope_id, - bool diagnose_duplicate_namespace, - llvm::function_ref make_import_id) - -> AddImportNamespaceResult { + SemIR::InstId import_id) -> AddImportNamespaceResult { + auto namespace_inst = + SemIR::Namespace{.type_id = namespace_type_id, + .name_scope_id = SemIR::NameScopeId::None, + .import_id = import_id}; + auto namespace_inst_and_loc = + MakeImportedNamespaceLocIdAndInst(context, import_id, namespace_inst); + AddImportNamespaceResult result = { + .name_scope_id = SemIR::NameScopeId::None, + .inst_id = AddPlaceholderInstInNoBlock(context, namespace_inst_and_loc)}; + context.import_ref_ids().push_back(result.inst_id); + namespace_inst.name_scope_id = + context.name_scopes().Add(result.inst_id, name_id, parent_scope_id); + result.name_scope_id = namespace_inst.name_scope_id; + ReplaceInstBeforeConstantUse(context, result.inst_id, namespace_inst); + return result; +} + +auto AddImportNamespaceToScope( + Context& context, SemIR::TypeId namespace_type_id, SemIR::NameId name_id, + SemIR::NameScopeId parent_scope_id, bool diagnose_duplicate_namespace, + llvm::function_ref make_import_id) + -> AddImportNamespaceToScopeResult { auto* parent_scope = &context.name_scopes().Get(parent_scope_id); auto [inserted, entry_id] = parent_scope->LookupOrAdd( name_id, @@ -113,8 +154,8 @@ auto AddImportNamespace(Context& context, SemIR::TypeId namespace_type_id, // id to get more accurate location. DiagnoseDuplicateName(context, name_id, import_id, prev_inst_id); } - return {.name_scope_id = namespace_inst->name_scope_id, - .inst_id = prev_inst_id, + return {.add_result = {.name_scope_id = namespace_inst->name_scope_id, + .inst_id = prev_inst_id}, .is_duplicate_of_namespace_in_current_package = true}; } } @@ -122,47 +163,29 @@ auto AddImportNamespace(Context& context, SemIR::TypeId namespace_type_id, auto import_id = make_import_id(); CARBON_CHECK(import_id.has_value()); - auto import_loc_id = context.insts().GetLocId(import_id); - auto namespace_inst = - SemIR::Namespace{.type_id = namespace_type_id, - .name_scope_id = SemIR::NameScopeId::None, - .import_id = import_id}; - auto namespace_inst_and_loc = - import_loc_id.is_import_ir_inst_id() - ? MakeImportedLocIdAndInst(context, import_loc_id.import_ir_inst_id(), - namespace_inst) - // TODO: Check that this actually is an `AnyNamespaceId`. - : SemIR::LocIdAndInst( - Parse::AnyNamespaceId::UnsafeMake(import_loc_id.node_id()), - namespace_inst); - auto namespace_id = - AddPlaceholderInstInNoBlock(context, namespace_inst_and_loc); - context.import_ref_ids().push_back(namespace_id); - namespace_inst.name_scope_id = - context.name_scopes().Add(namespace_id, name_id, parent_scope_id); - ReplaceInstBeforeConstantUse(context, namespace_id, namespace_inst); + AddImportNamespaceToScopeResult result = { + .add_result = AddImportNamespace(context, namespace_type_id, name_id, + parent_scope_id, import_id), + .is_duplicate_of_namespace_in_current_package = false}; // Note we have to get the parent scope freshly, creating the imported // namespace may invalidate the pointer above. parent_scope = &context.name_scopes().Get(parent_scope_id); - // Diagnose if there's a name conflict, but still produce the namespace to - // supersede the name conflict in order to avoid repeat diagnostics. Names are - // poisoned optimistically by name lookup before checking for imports, so we - // may be overwriting a poisoned entry here. - auto& result = parent_scope->GetEntry(entry_id).result; - if (!result.is_poisoned() && !inserted) { - // TODO: Pass the import namespace name location instead of the namespace id - // to get more accurate location. - DiagnoseDuplicateName(context, name_id, namespace_id, - result.target_inst_id()); + // supersede the name conflict in order to avoid repeat diagnostics. Names + // are poisoned optimistically by name lookup before checking for imports, + // so we may be overwriting a poisoned entry here. + auto& lookup_result = parent_scope->GetEntry(entry_id).result; + if (!lookup_result.is_poisoned() && !inserted) { + // TODO: Pass the import namespace name location instead of the namespace + // id to get more accurate location. + DiagnoseDuplicateName(context, name_id, result.add_result.inst_id, + lookup_result.target_inst_id()); } - result = SemIR::ScopeLookupResult::MakeFound(namespace_id, - SemIR::AccessKind::Public); - return {.name_scope_id = namespace_inst.name_scope_id, - .inst_id = namespace_id, - .is_duplicate_of_namespace_in_current_package = false}; + lookup_result = SemIR::ScopeLookupResult::MakeFound( + result.add_result.inst_id, SemIR::AccessKind::Public); + return result; } // Adds a copied namespace to the cache. @@ -185,7 +208,7 @@ static auto CopySingleNameScopeFromImportIR( Map* copied_namespaces, SemIR::ImportIRId ir_id, SemIR::InstId import_inst_id, SemIR::NameScopeId import_scope_id, SemIR::NameScopeId parent_scope_id, - SemIR::NameId name_id) -> AddImportNamespaceResult { + SemIR::NameId name_id) -> AddImportNamespaceToScopeResult { // Produce the namespace for the entry. auto make_import_id = [&]() { auto entity_name_id = context.entity_names().Add( @@ -201,17 +224,18 @@ static auto CopySingleNameScopeFromImportIR( context.import_ref_ids().push_back(inst_id); return inst_id; }; - AddImportNamespaceResult result = AddImportNamespace( + AddImportNamespaceToScopeResult result = AddImportNamespaceToScope( context, namespace_type_id, name_id, parent_scope_id, /*diagnose_duplicate_namespace=*/false, make_import_id); - auto namespace_const_id = context.constant_values().Get(result.inst_id); + auto namespace_const_id = + context.constant_values().Get(result.add_result.inst_id); context.import_ir_constant_values()[ir_id.index].Set(import_inst_id, namespace_const_id); if (copied_namespaces) { CacheCopiedNamespace(*copied_namespaces, import_scope_id, - result.name_scope_id); + result.add_result.name_scope_id); } return result; } @@ -261,7 +285,7 @@ static auto CopyAncestorNameScopesFromImportIR( CopySingleNameScopeFromImportIR( context, namespace_type_id, &copied_namespaces, ir_id, import_scope.inst_id(), import_scope_id, scope_cursor, name_id) - .name_scope_id; + .add_result.name_scope_id; } return scope_cursor; @@ -432,7 +456,7 @@ auto ImportApiFile(Context& context, SemIR::TypeId namespace_type_id, SemIR::ImportIRId::ApiForImpl, todo_scope.api_inst_id, todo_scope.api_scope_id, todo_scope.impl_parent_scope_id, todo_scope.impl_name_id) - .name_scope_id; + .add_result.name_scope_id; ImportScopeFromApiFile(context, api_sem_ir, todo_scope.api_scope_id, impl_scope_id, todo_scopes); } @@ -496,12 +520,13 @@ auto ImportLibrariesFromOtherPackage(Context& context, auto name_id = SemIR::NameId::ForPackageName(package_id); - AddImportNamespaceResult result = AddImportNamespace( + AddImportNamespaceToScopeResult result = AddImportNamespaceToScope( context, namespace_type_id, name_id, SemIR::NameScopeId::Package, /*diagnose_duplicate_namespace=*/true, [&] { return import_decl_id; }); - auto namespace_const_id = context.constant_values().Get(result.inst_id); + auto namespace_const_id = + context.constant_values().Get(result.add_result.inst_id); - auto& scope = context.name_scopes().Get(result.name_scope_id); + auto& scope = context.name_scopes().Get(result.add_result.name_scope_id); scope.set_is_closed_import( !result.is_duplicate_of_namespace_in_current_package); for (auto import_ir : import_irs) { @@ -563,14 +588,14 @@ static auto AddNamespaceFromOtherPackage(Context& context, -> SemIR::InstId { auto namespace_type_id = GetSingletonType(context, SemIR::NamespaceType::SingletonInstId); - AddImportNamespaceResult result = CopySingleNameScopeFromImportIR( + AddImportNamespaceToScopeResult result = CopySingleNameScopeFromImportIR( context, namespace_type_id, /*copied_namespaces=*/nullptr, import_ir_id, import_inst_id, import_ns.name_scope_id, parent_scope_id, name_id); - auto& scope = context.name_scopes().Get(result.name_scope_id); + auto& scope = context.name_scopes().Get(result.add_result.name_scope_id); scope.set_is_closed_import( !result.is_duplicate_of_namespace_in_current_package); scope.AddImportIRScope({import_ir_id, import_ns.name_scope_id}); - return result.inst_id; + return result.add_result.inst_id; } auto ImportNameFromOtherPackage( diff --git a/toolchain/check/import.h b/toolchain/check/import.h index 443d77b7e8b8..d2cda095560f 100644 --- a/toolchain/check/import.h +++ b/toolchain/check/import.h @@ -12,21 +12,42 @@ namespace Carbon::Check { struct AddImportNamespaceResult { + // The namespace scope id. SemIR::NameScopeId name_scope_id; + + // The namespace instruction id. SemIR::InstId inst_id; - bool is_duplicate_of_namespace_in_current_package; }; -// Adds a namespace to the IR. The bool on return is true if there was a name -// conflict. diagnose_duplicate_namespace is used when handling a cross-package -// import, where an existing namespace is in the current package and the new -// namespace is a different package. +// Adds a namespace to the IR. Associates the namespace with the import referred +// in `import_id`, if any. Do not try to add the namespace `name_id` to the +// scope and don't check if it already exists. Used when the name is added +// afterwards. auto AddImportNamespace(Context& context, SemIR::TypeId namespace_type_id, SemIR::NameId name_id, SemIR::NameScopeId parent_scope_id, - bool diagnose_duplicate_namespace, - llvm::function_ref make_import_id) - -> AddImportNamespaceResult; + SemIR::InstId import_id) -> AddImportNamespaceResult; + +struct AddImportNamespaceToScopeResult { + AddImportNamespaceResult add_result; + + // When trying to add the namespace name, whether it already exists and refers + // to a namespace. + bool is_duplicate_of_namespace_in_current_package = false; +}; + +// Adds a namespace to the IR. Associates the namespace with the import returned +// from `make_import_id`, which must return a value. Tries to add the namespace +// `name_id` to the scope. If the name already exists, diagnose only if +// `diagnose_duplicate_namespace` is true or if it doesn't refer to a namespace. +// `diagnose_duplicate_namespace` is used when handling a cross-package import, +// where an existing namespace is in the current package and the new namespace +// is a different package. +auto AddImportNamespaceToScope( + Context& context, SemIR::TypeId namespace_type_id, SemIR::NameId name_id, + SemIR::NameScopeId parent_scope_id, bool diagnose_duplicate_namespace, + llvm::function_ref make_import_id) + -> AddImportNamespaceToScopeResult; // Imports the API file's name lookup information into a corresponding // implementation file. Only information for the current package will be copied; diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index 79ff2676f4ca..c229ea5ad5d6 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -22,6 +22,7 @@ #include "toolchain/check/type.h" #include "toolchain/diagnostics/diagnostic.h" #include "toolchain/diagnostics/format_providers.h" +#include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/name_scope.h" @@ -102,7 +103,7 @@ static auto AddNamespace(Context& context, PackageNameId cpp_package_id, {.node_id = import.node_id, .library_id = import.library_id}); } - return AddImportNamespace( + return AddImportNamespaceToScope( context, GetSingletonType(context, SemIR::NamespaceType::SingletonInstId), SemIR::NameId::ForPackageName(cpp_package_id), @@ -112,7 +113,7 @@ static auto AddNamespace(Context& context, PackageNameId cpp_package_id, return AddInst( context, imports.front().node_id, {}); }) - .name_scope_id; + .add_result.name_scope_id; } auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, @@ -136,7 +137,8 @@ auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, auto name_scope_id = AddNamespace(context, package_id, imports); SemIR::NameScope& name_scope = context.name_scopes().Get(name_scope_id); name_scope.set_is_closed_import(true); - name_scope.set_is_cpp_scope(true); + name_scope.set_cpp_decl_context( + generated_ast->getASTContext().getTranslationUnitDecl()); context.sem_ir().set_cpp_ast(generated_ast.get()); @@ -147,10 +149,10 @@ auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, return std::move(generated_ast); } -// Look ups the given name in the Clang AST. Returns the lookup result if lookup -// was successful. +// Look ups the given name in the Clang AST in a specific scope. Returns the +// lookup result if lookup was successful. static auto ClangLookup(Context& context, SemIR::LocId loc_id, - SemIR::NameId name_id) + SemIR::NameScopeId scope_id, SemIR::NameId name_id) -> std::optional { std::optional name = context.names().GetAsStringIfIdentifier(name_id); @@ -172,7 +174,7 @@ static auto ClangLookup(Context& context, SemIR::LocId loc_id, clang::Sema::LookupNameKind::LookupOrdinaryName); bool found = sema.LookupQualifiedName( - lookup, ast->getASTContext().getTranslationUnitDecl()); + lookup, context.name_scopes().Get(scope_id).cpp_decl_context()); if (lookup.isClassLookup()) { // TODO: To support class lookup, also return the AccessKind for storage. @@ -250,17 +252,37 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, return decl_id; } +// Imports a namespace declaration from Clang to Carbon. If successful, returns +// the new Carbon namespace declaration `InstId`. +static auto ImportNamespaceDecl(Context& context, + SemIR::NameScopeId parent_scope_id, + SemIR::NameId name_id, + clang::NamespaceDecl* clang_decl) + -> SemIR::InstId { + auto result = AddImportNamespace( + context, GetSingletonType(context, SemIR::NamespaceType::SingletonInstId), + name_id, parent_scope_id, /*import_id=*/SemIR::InstId::None); + context.name_scopes() + .Get(result.name_scope_id) + .set_cpp_decl_context(clang_decl); + return result.inst_id; +} + // Imports a declaration from Clang to Carbon. If successful, returns the // instruction for the new Carbon declaration. static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, SemIR::NameScopeId scope_id, SemIR::NameId name_id, - const clang::NamedDecl* clang_decl) - -> SemIR::InstId { + clang::NamedDecl* clang_decl) -> SemIR::InstId { if (const auto* clang_function_decl = clang::dyn_cast(clang_decl)) { return ImportFunctionDecl(context, loc_id, scope_id, name_id, clang_function_decl); } + if (auto* clang_namespace_decl = + clang::dyn_cast(clang_decl)) { + return ImportNamespaceDecl(context, scope_id, name_id, + clang_namespace_decl); + } context.TODO(loc_id, llvm::formatv("Unsupported: Declaration type {0}", clang_decl->getDeclKindName()) @@ -271,7 +293,7 @@ static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, SemIR::NameScopeId scope_id, SemIR::NameId name_id) -> SemIR::InstId { - auto lookup = ClangLookup(context, loc_id, name_id); + auto lookup = ClangLookup(context, loc_id, scope_id, name_id); if (!lookup) { return SemIR::InstId::None; } diff --git a/toolchain/check/name_lookup.cpp b/toolchain/check/name_lookup.cpp index e4f777fe2d5f..0122add48857 100644 --- a/toolchain/check/name_lookup.cpp +++ b/toolchain/check/name_lookup.cpp @@ -181,7 +181,9 @@ auto LookupNameInExactScope(Context& context, SemIR::LocId loc_id, if (imported_inst_id.has_value()) { SemIR::ScopeLookupResult result = SemIR::ScopeLookupResult::MakeFound( imported_inst_id, SemIR::AccessKind::Public); - scope.AddRequired({.name_id = name_id, .result = result}); + // `ImportNameFromCpp()` can invalidate `scope`, so we do a scope lookup. + context.name_scopes().Get(scope_id).AddRequired( + {.name_id = name_id, .result = result}); return result; } } diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/bad_import.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/bad_import.carbon index a2f14247028f..0a421d4c00b1 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/bad_import.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/bad_import.carbon @@ -58,6 +58,7 @@ import Cpp library "\"foo.h\""; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/cpp_diagnostics.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/cpp_diagnostics.carbon index a4fba236ac63..4241ce94029a 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/cpp_diagnostics.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/cpp_diagnostics.carbon @@ -219,6 +219,7 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -236,6 +237,7 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -252,7 +254,9 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: --- import_cpp_file_with_one_warning.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -267,7 +271,9 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: --- import_cpp_file_with_multiple_warnings.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -283,6 +289,7 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -300,6 +307,7 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -316,7 +324,9 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: --- import_multiple_cpp_files_with_warnings.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -333,6 +343,7 @@ import Cpp library "multiple_errors_and_multiple_warnings.h"; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/cpp_namespace.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/cpp_namespace.carbon index 7d71dd40fe89..18c192e13618 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/cpp_namespace.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/cpp_namespace.carbon @@ -72,7 +72,9 @@ import Cpp library "header.h"; // CHECK:STDOUT: --- fail_duplicate_cpp_name.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -82,13 +84,17 @@ import Cpp library "header.h"; // CHECK:STDOUT: %Cpp.import_cpp = import_cpp { // CHECK:STDOUT: import Cpp "header.h" // CHECK:STDOUT: } -// CHECK:STDOUT: %Cpp: = namespace [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- cpp_in_inner_namespace.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -108,7 +114,9 @@ import Cpp library "header.h"; // CHECK:STDOUT: --- alias.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -134,6 +142,7 @@ import Cpp library "header.h"; // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .C = file.%C.decl +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -158,7 +167,9 @@ import Cpp library "header.h"; // CHECK:STDOUT: --- api_and_impl.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -174,7 +185,9 @@ import Cpp library "header.h"; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Main.Cpp: = import_ref Main//api_and_impl, Cpp, loaded -// CHECK:STDOUT: %Cpp: = namespace %Main.Cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace %Main.Cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/file_not_found.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/file_not_found.carbon index 51115c4ebd35..d00a189f4d3c 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/file_not_found.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/file_not_found.carbon @@ -26,6 +26,7 @@ import Cpp library "not_found.h"; // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: has_error // CHECK:STDOUT: } // CHECK:STDOUT: } diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/function_decl.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/function_decl.carbon index 0e0efa92781d..f83b9c64fd98 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/function_decl.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/function_decl.carbon @@ -186,6 +186,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = @MyF.%foo.decl +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -221,6 +222,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .bar = +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -250,7 +252,9 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -284,6 +288,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .r#base = @MyF.%base.decl +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -319,6 +324,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -350,6 +356,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -381,6 +388,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -412,6 +420,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: @@ -443,6 +452,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/include.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/include.carbon index cebf79c2c051..2648d469d1b0 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/include.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/include.carbon @@ -25,7 +25,9 @@ import Cpp library "including_file.h"; // CHECK:STDOUT: --- import_function_decl.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/multiple_imports.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/multiple_imports.carbon index 1053eede3204..975e8d6db270 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/multiple_imports.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/multiple_imports.carbon @@ -26,7 +26,9 @@ import Cpp library "file2.h"; // CHECK:STDOUT: --- multiple_imports.carbon // CHECK:STDOUT: // CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] {} +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/namespace.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/namespace.carbon new file mode 100644 index 000000000000..4075777617bb --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/no_prelude/namespace.carbon @@ -0,0 +1,369 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/no_prelude/namespace.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/no_prelude/namespace.carbon + +// --- namespace.h + +namespace my_namespace { void foo(); } + +// --- import_namespace.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "namespace.h"; + +fn MyF() { + Cpp.my_namespace.foo(); +} + +// --- multiple_namespaces.h + +namespace my_namespace1 { + void foo1(); + namespace my_namespace2 { + void foo2(); + namespace my_namespace3 { + void foo3(); + } + } +} + +// --- import_multiple_namespaces.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "multiple_namespaces.h"; + +fn MyF() { + Cpp.my_namespace1.foo1(); + Cpp.my_namespace1.my_namespace2.foo2(); + Cpp.my_namespace1.my_namespace2.my_namespace3.foo3(); +} + +// --- fail_import_namespace_wrong_name_in_namespace.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "namespace.h"; + +fn MyF() { + // CHECK:STDERR: fail_import_namespace_wrong_name_in_namespace.carbon:[[@LINE+4]]:3: error: member name `not_foo` not found in `Cpp.my_namespace` [MemberNameNotFoundInScope] + // CHECK:STDERR: Cpp.my_namespace.not_foo(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.my_namespace.not_foo(); +} + +// --- fail_import_namespace_use_different_name.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "namespace.h"; + +fn MyF() { + // CHECK:STDERR: fail_import_namespace_use_different_name.carbon:[[@LINE+4]]:3: error: member name `not_my_namespace` not found in `Cpp` [MemberNameNotFoundInScope] + // CHECK:STDERR: Cpp.not_my_namespace.foo(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.not_my_namespace.foo(); +} + +// --- namespace_special_name_decl.h + +namespace base { void foo(); } + +// --- fail_import_namespace_special_name_decl.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "namespace_special_name_decl.h"; + +fn MyF() { + // CHECK:STDERR: fail_import_namespace_special_name_decl.carbon:[[@LINE+4]]:3: error: member name `base` not found in `Cpp` [MemberNameNotFoundInScope] + // CHECK:STDERR: Cpp.base.foo(); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + Cpp.base.foo(); +} + +// --- import_namespace_escaped_special_name_decl.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "namespace_special_name_decl.h"; + +fn MyF() { + Cpp.r#base.foo(); +} + +// CHECK:STDOUT: --- import_namespace.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .my_namespace = %my_namespace +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %my_namespace: = namespace [concrete] { +// CHECK:STDOUT: .foo = @MyF.%foo.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .MyF = %MyF.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "namespace.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MyF() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %my_namespace.ref: = name_ref my_namespace, imports.%my_namespace [concrete = imports.%my_namespace] +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {} {} +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, %foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @foo[](); +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_multiple_namespaces.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] +// CHECK:STDOUT: %foo1.type: type = fn_type @foo1 [concrete] +// CHECK:STDOUT: %foo1: %foo1.type = struct_value () [concrete] +// CHECK:STDOUT: %foo2.type: type = fn_type @foo2 [concrete] +// CHECK:STDOUT: %foo2: %foo2.type = struct_value () [concrete] +// CHECK:STDOUT: %foo3.type: type = fn_type @foo3 [concrete] +// CHECK:STDOUT: %foo3: %foo3.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .my_namespace1 = %my_namespace1 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %my_namespace1: = namespace [concrete] { +// CHECK:STDOUT: .foo1 = @MyF.%foo1.decl +// CHECK:STDOUT: .my_namespace2 = %my_namespace2 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %my_namespace2: = namespace [concrete] { +// CHECK:STDOUT: .foo2 = @MyF.%foo2.decl +// CHECK:STDOUT: .my_namespace3 = %my_namespace3 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %my_namespace3: = namespace [concrete] { +// CHECK:STDOUT: .foo3 = @MyF.%foo3.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .MyF = %MyF.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "multiple_namespaces.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MyF() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc7: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %my_namespace1.ref.loc7: = name_ref my_namespace1, imports.%my_namespace1 [concrete = imports.%my_namespace1] +// CHECK:STDOUT: %foo1.decl: %foo1.type = fn_decl @foo1 [concrete = constants.%foo1] {} {} +// CHECK:STDOUT: %foo1.ref: %foo1.type = name_ref foo1, %foo1.decl [concrete = constants.%foo1] +// CHECK:STDOUT: %foo1.call: init %empty_tuple.type = call %foo1.ref() +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %my_namespace1.ref.loc8: = name_ref my_namespace1, imports.%my_namespace1 [concrete = imports.%my_namespace1] +// CHECK:STDOUT: %my_namespace2.ref.loc8: = name_ref my_namespace2, imports.%my_namespace2 [concrete = imports.%my_namespace2] +// CHECK:STDOUT: %foo2.decl: %foo2.type = fn_decl @foo2 [concrete = constants.%foo2] {} {} +// CHECK:STDOUT: %foo2.ref: %foo2.type = name_ref foo2, %foo2.decl [concrete = constants.%foo2] +// CHECK:STDOUT: %foo2.call: init %empty_tuple.type = call %foo2.ref() +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %my_namespace1.ref.loc9: = name_ref my_namespace1, imports.%my_namespace1 [concrete = imports.%my_namespace1] +// CHECK:STDOUT: %my_namespace2.ref.loc9: = name_ref my_namespace2, imports.%my_namespace2 [concrete = imports.%my_namespace2] +// CHECK:STDOUT: %my_namespace3.ref: = name_ref my_namespace3, imports.%my_namespace3 [concrete = imports.%my_namespace3] +// CHECK:STDOUT: %foo3.decl: %foo3.type = fn_decl @foo3 [concrete = constants.%foo3] {} {} +// CHECK:STDOUT: %foo3.ref: %foo3.type = name_ref foo3, %foo3.decl [concrete = constants.%foo3] +// CHECK:STDOUT: %foo3.call: init %empty_tuple.type = call %foo3.ref() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @foo1[](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @foo2[](); +// CHECK:STDOUT: +// CHECK:STDOUT: fn @foo3[](); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_import_namespace_wrong_name_in_namespace.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] +// CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .my_namespace = %my_namespace +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %my_namespace: = namespace [concrete] { +// CHECK:STDOUT: .not_foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .MyF = %MyF.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "namespace.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MyF() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %my_namespace.ref: = name_ref my_namespace, imports.%my_namespace [concrete = imports.%my_namespace] +// CHECK:STDOUT: %not_foo.ref: = name_ref not_foo, [concrete = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_import_namespace_use_different_name.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] +// CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .not_my_namespace = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .MyF = %MyF.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "namespace.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MyF() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %not_my_namespace.ref: = name_ref not_my_namespace, [concrete = ] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_import_namespace_special_name_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] +// CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .MyF = %MyF.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "namespace_special_name_decl.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MyF() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %base.ref: = name_ref base, [concrete = ] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_namespace_escaped_special_name_decl.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .r#base = %base +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %base: = namespace [concrete] { +// CHECK:STDOUT: .foo = @MyF.%foo.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .MyF = %MyF.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "namespace_special_name_decl.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MyF() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %base.ref: = name_ref r#base, imports.%base [concrete = imports.%base] +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {} {} +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, %foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @foo[](); +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/no_prelude/unsupported_decl_type.carbon b/toolchain/check/testdata/interop/cpp/no_prelude/unsupported_decl_type.carbon index c331a88ba9ee..edbdc74a5349 100644 --- a/toolchain/check/testdata/interop/cpp/no_prelude/unsupported_decl_type.carbon +++ b/toolchain/check/testdata/interop/cpp/no_prelude/unsupported_decl_type.carbon @@ -43,6 +43,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 3748f202ecdf..b122dbd3c185 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -663,7 +663,8 @@ class FormatterImpl { const auto& scope = sem_ir_->name_scopes().Get(id); if (scope.entries().empty() && scope.extended_scopes().empty() && - scope.import_ir_scopes().empty() && !scope.has_error()) { + scope.import_ir_scopes().empty() && !scope.is_cpp_scope() && + !scope.has_error()) { // Name scope is empty. return; } @@ -723,6 +724,11 @@ class FormatterImpl { out_ << "import " << label << "\n"; } + if (scope.is_cpp_scope()) { + Indent(); + out_ << "import Cpp//...\n"; + } + if (scope.has_error()) { Indent(); out_ << "has_error\n"; diff --git a/toolchain/sem_ir/name_scope.h b/toolchain/sem_ir/name_scope.h index 554c133c4f38..1a044c4df536 100644 --- a/toolchain/sem_ir/name_scope.h +++ b/toolchain/sem_ir/name_scope.h @@ -5,6 +5,7 @@ #ifndef CARBON_TOOLCHAIN_SEM_IR_NAME_SCOPE_H_ #define CARBON_TOOLCHAIN_SEM_IR_NAME_SCOPE_H_ +#include "clang/AST/DeclBase.h" #include "common/map.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" @@ -212,10 +213,15 @@ class NameScope : public Printable { is_closed_import_ = is_closed_import; } - auto is_cpp_scope() const -> bool { return is_cpp_scope_; } + auto is_cpp_scope() const -> bool { return cpp_decl_context(); } - auto set_is_cpp_scope(bool is_cpp_scope) -> void { - is_cpp_scope_ = is_cpp_scope; + auto cpp_decl_context() const -> const clang::DeclContext* { + return cpp_decl_context_; + } + auto cpp_decl_context() -> clang::DeclContext* { return cpp_decl_context_; } + + auto set_cpp_decl_context(clang::DeclContext* cpp_decl_context) -> void { + cpp_decl_context_ = cpp_decl_context; } // Returns true if this name scope describes an imported package. @@ -288,8 +294,13 @@ class NameScope : public Printable { // True if this is a closed namespace created by importing a package. bool is_closed_import_ = false; - // True if this is the `Cpp` namescope used when importing C++ code. - bool is_cpp_scope_ = false; + // Set if this is the `Cpp` scope or a scope inside `Cpp`. Points to the + // matching Clang declaration context to look for names. This is mutable since + // `clang::Sema::LookupQualifiedName()` requires a mutable `DeclContext`. + // TODO: Ensure we can easily serialize/deserialize this. Consider decl ID to + // point into the AST. This is related to: + // https://github.com/carbon-language/carbon-lang/issues/4666. + clang::DeclContext* cpp_decl_context_ = nullptr; // True if this is the scope of an interface definition, where associated // entities will be bound to the interface's `Self` symbolic type.