Add support for importing C++ namespaces (#5103)

This adds support for having different C++ `NameScope`s (and not just
the main `Cpp` scope), and we keep a pointer to `clang::DeclContext`
these scopes so we can look up C++ names in the right part of the AST.

C++ Interop Demo with a namespace:

```c++
// hello_world.h

namespace some_namespace {

void hello_world();

}  // namespace some_namespace
```

```c++
// hello_world.cpp

#include <cstdio>

namespace some_namespace {

void hello_world() { printf("Hello World!\n"); }

}  // namespace some_namespace
```

```carbon
// main.carbon

library "Main";

import Cpp library "hello_world.h";

fn Run() -> i32 {
  Cpp.some_namespace.hello_world();
  return 0;
}
```

```shell
$ clang -c hello_world.cpp
$ bazel-bin/toolchain/carbon compile main.carbon
$ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo
$ ./demo
Hello World!
```

Closes #5102
This commit is contained in:
Boaz Brickner
2025-03-15 20:41:48 +00:00
committed by GitHub
parent fdedbb037d
commit fcd38a4d7f
15 changed files with 585 additions and 88 deletions
+76 -51
View File
@@ -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<SemIR::InstId()> 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<SemIR::InstId()> 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<SemIR::NameScopeId, SemIR::NameScopeId>* 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(
+29 -8
View File
@@ -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<SemIR::InstId()> 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<SemIR::InstId()> 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;
+32 -10
View File
@@ -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<SemIR::ImportCppDecl>(
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<clang::LookupResult> {
std::optional<llvm::StringRef> 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::FunctionDecl>(clang_decl)) {
return ImportFunctionDecl(context, loc_id, scope_id, name_id,
clang_function_decl);
}
if (auto* clang_namespace_decl =
clang::dyn_cast<clang::NamespaceDecl>(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;
}
+3 -1
View File
@@ -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;
}
}
@@ -58,6 +58,7 @@ import Cpp library "\"foo.h\"";
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: has_error
// CHECK:STDOUT: }
// CHECK:STDOUT: }
@@ -219,6 +219,7 @@ import Cpp library "multiple_errors_and_multiple_warnings.h";
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = 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> = 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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = 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> = 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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: has_error
// CHECK:STDOUT: }
// CHECK:STDOUT: }
@@ -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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = namespace [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = 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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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: <namespace> = import_ref Main//api_and_impl, Cpp, loaded
// CHECK:STDOUT: %Cpp: <namespace> = namespace %Main.Cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = namespace %Main.Cpp, [concrete] {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -26,6 +26,7 @@ import Cpp library "not_found.h";
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: has_error
// CHECK:STDOUT: }
// CHECK:STDOUT: }
@@ -186,6 +186,7 @@ fn F() {
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .bar = <poisoned>
// 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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = 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> = 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <error>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -350,6 +356,7 @@ fn F() {
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <error>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -381,6 +388,7 @@ fn F() {
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <error>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -412,6 +420,7 @@ fn F() {
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <error>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -443,6 +452,7 @@ fn F() {
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <error>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -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> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -26,7 +26,9 @@ import Cpp library "file2.h";
// CHECK:STDOUT: --- multiple_imports.carbon
// CHECK:STDOUT:
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {}
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
@@ -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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .my_namespace = %my_namespace
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %my_namespace: <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> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %my_namespace.ref: <namespace> = 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .my_namespace1 = %my_namespace1
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %my_namespace1: <namespace> = 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> = 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> = 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> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %my_namespace1.ref.loc7: <namespace> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %my_namespace1.ref.loc8: <namespace> = name_ref my_namespace1, imports.%my_namespace1 [concrete = imports.%my_namespace1]
// CHECK:STDOUT: %my_namespace2.ref.loc8: <namespace> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %my_namespace1.ref.loc9: <namespace> = name_ref my_namespace1, imports.%my_namespace1 [concrete = imports.%my_namespace1]
// CHECK:STDOUT: %my_namespace2.ref.loc9: <namespace> = name_ref my_namespace2, imports.%my_namespace2 [concrete = imports.%my_namespace2]
// CHECK:STDOUT: %my_namespace3.ref: <namespace> = 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .my_namespace = %my_namespace
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %my_namespace: <namespace> = namespace [concrete] {
// CHECK:STDOUT: .not_foo = <poisoned>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %my_namespace.ref: <namespace> = name_ref my_namespace, imports.%my_namespace [concrete = imports.%my_namespace]
// CHECK:STDOUT: %not_foo.ref: <error> = name_ref not_foo, <error> [concrete = <error>]
// 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .not_my_namespace = <poisoned>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %not_my_namespace.ref: <error> = name_ref not_my_namespace, <error> [concrete = <error>]
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
// 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: file {
// CHECK:STDOUT: package: <namespace> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %base.ref: <error> = name_ref base, <error> [concrete = <error>]
// CHECK:STDOUT: %foo.ref: <error> = name_ref foo, <error> [concrete = <error>]
// 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> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .r#base = %base
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: %base: <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> = 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: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
// CHECK:STDOUT: %base.ref: <namespace> = 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:
@@ -43,6 +43,7 @@ fn F() {
// CHECK:STDOUT: imports {
// CHECK:STDOUT: %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
// CHECK:STDOUT: .foo = <poisoned>
// CHECK:STDOUT: import Cpp//...
// CHECK:STDOUT: }
// CHECK:STDOUT: }
// CHECK:STDOUT:
+7 -1
View File
@@ -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";
+16 -5
View File
@@ -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<NameScope> {
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<NameScope> {
// 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.