mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 18:01:07 +01:00
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:
+76
-51
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user