From cc698d78f5ebc7fdfa887a953d94e00df30dc498 Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Fri, 20 Jun 2025 18:51:58 +0200 Subject: [PATCH] When using a C++ struct as a parameter, map its type to a Carbon class type (#5538) This doesn't support actually passing the value of the struct, which is planned to be implemented using thunks. `ClangDeclId` value is now `ClangDecl` which includes the mapped Carbon instruction in addition to the Clang declaration. This allows finding the Carbon instruction for a given Clang declaration, which is necessary for mapping a Clang struct parameter type to the Carbon class without doing name lookup. We don't take the instruction as part of the hash key, as discussed in [Discord](https://discord.com/channels/655572317891461132/768530752592805919/1380575881050718469). To map the type, we also need to map namespaces. To avoid recursion for inner namespaces, we use a vector. Note that the first commit just changes the order of functions in the file to make review easier. C++ Interop Demo (that shows missing behavior): ```c++ // hello_world.h struct S { S(const S&) { x = 1; } int x; }; void hello_world(S s); ``` ```c++ // hello_world.cpp #include "hello_world.h" #include void hello_world2(S s) { printf("hello_world2: %d\n", s.x); } void hello_world(S s) { printf("hello_world: %d\n", s.x); hello_world2(s); } ``` ```carbon // main.carbon library "Main"; import Cpp library "hello_world.h"; fn Run() -> i32 { var s : Cpp.S; Cpp.hello_world(s); 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: -1108224096 hello_world2: 1 ``` Part of #5533. --- toolchain/check/import_cpp.cpp | 416 ++++++---- toolchain/check/name_lookup.cpp | 6 +- .../interop/cpp/function/class.carbon | 729 ++++++++++++++++++ .../interop/cpp/function/struct.carbon | 406 ++++++++-- toolchain/lower/file_context.cpp | 2 +- toolchain/lower/mangler.cpp | 2 +- toolchain/sem_ir/BUILD | 13 + toolchain/sem_ir/clang_decl.cpp | 17 + toolchain/sem_ir/clang_decl.h | 62 ++ toolchain/sem_ir/file.h | 4 +- toolchain/sem_ir/function.h | 1 + toolchain/sem_ir/ids.h | 12 - toolchain/sem_ir/name_scope.h | 1 + 13 files changed, 1461 insertions(+), 210 deletions(-) create mode 100644 toolchain/check/testdata/interop/cpp/function/class.carbon create mode 100644 toolchain/sem_ir/clang_decl.cpp create mode 100644 toolchain/sem_ir/clang_decl.h diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index 39f81bd18867..40195bd81d8b 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -52,7 +52,21 @@ static auto GenerateCppIncludesHeaderCode( return code; } -namespace { +// Adds the name to the scope with the given `inst_id`, if the `inst_id` is not +// `None`. +static auto AddNameToScope(Context& context, SemIR::NameScopeId scope_id, + SemIR::NameId name_id, SemIR::InstId inst_id) + -> void { + if (inst_id.has_value()) { + context.name_scopes().AddRequiredName(scope_id, name_id, inst_id); + } +} + +// Maps a Clang name to a Carbon `NameId`. +static auto AddIdentifierName(Context& context, llvm::StringRef name) + -> SemIR::NameId { + return SemIR::NameId::ForIdentifier(context.identifiers().Add(name)); +} // Adds the given source location and an `ImportIRInst` referring to it in // `ImportIRId::Cpp`. @@ -65,6 +79,8 @@ static auto AddImportIRInst(Context& context, SemIR::ImportIRInst(clang_source_loc_id)); } +namespace { + // Used to convert Clang diagnostics to Carbon diagnostics. class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { public: @@ -255,7 +271,8 @@ auto ImportCppFiles(Context& context, llvm::StringRef importing_file_path, SemIR::NameScope& name_scope = context.name_scopes().Get(name_scope_id); name_scope.set_is_closed_import(true); name_scope.set_clang_decl_context_id(context.sem_ir().clang_decls().Add( - generated_ast->getASTContext().getTranslationUnitDecl())); + {.decl = generated_ast->getASTContext().getTranslationUnitDecl(), + .inst_id = name_scope.inst_id()})); if (ast_has_error) { name_scope.set_has_error(); @@ -292,10 +309,14 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, // `TextDiagnosticPrinter` assumes we're processing a C++ source file. lookup.suppressDiagnostics(); + auto scope_clang_decl_context_id = + context.name_scopes().Get(scope_id).clang_decl_context_id(); bool found = sema.LookupQualifiedName( lookup, - clang::dyn_cast(context.sem_ir().clang_decls().Get( - context.name_scopes().Get(scope_id).clang_decl_context_id()))); + clang::dyn_cast(context.sem_ir() + .clang_decls() + .Get(scope_clang_decl_context_id) + .decl)); if (!found) { return std::nullopt; @@ -304,6 +325,174 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, return lookup; } +// 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::TypeInstId), + name_id, parent_scope_id, /*import_id=*/SemIR::InstId::None); + context.name_scopes() + .Get(result.name_scope_id) + .set_clang_decl_context_id(context.sem_ir().clang_decls().Add( + {.decl = clang_decl, .inst_id = result.inst_id})); + return result.inst_id; +} + +// Maps a C++ declaration context to a Carbon namespace. +static auto AsCarbonNamespace(Context& context, + clang::DeclContext* decl_context) + -> SemIR::InstId { + CARBON_CHECK(decl_context); + auto& clang_decls = context.sem_ir().clang_decls(); + + // Check if the decl context is already mapped to a Carbon namespace. + if (auto context_clang_decl_id = clang_decls.Lookup( + {.decl = clang::dyn_cast(decl_context), + .inst_id = SemIR::InstId::None}); + context_clang_decl_id.has_value()) { + return clang_decls.Get(context_clang_decl_id).inst_id; + } + + // We know we have at least one context to map, add all decl contexts we need + // to map. + llvm::SmallVector decl_contexts; + auto parent_decl_id = SemIR::ClangDeclId::None; + do { + decl_contexts.push_back(decl_context); + decl_context = decl_context->getParent(); + parent_decl_id = + clang_decls.Lookup({.decl = clang::dyn_cast(decl_context), + .inst_id = SemIR::InstId::None}); + } while (!parent_decl_id.has_value()); + + // We know the parent of the last decl context is mapped, map the rest. + auto namespace_inst_id = SemIR::InstId::None; + do { + decl_context = decl_contexts.pop_back_val(); + auto parent_inst_id = clang_decls.Get(parent_decl_id).inst_id; + auto parent_namespace = + context.insts().GetAs(parent_inst_id); + namespace_inst_id = ImportNamespaceDecl( + context, parent_namespace.name_scope_id, + AddIdentifierName( + context, llvm::dyn_cast(decl_context)->getName()), + clang::dyn_cast(decl_context)); + parent_decl_id = clang_decls.Add({ + .decl = clang::dyn_cast(decl_context), + .inst_id = namespace_inst_id, + }); + } while (!decl_contexts.empty()); + + return namespace_inst_id; +} + +// Creates a class declaration for the given class name in the given scope. +// Returns the `InstId` for the declaration. +static auto BuildClassDecl(Context& context, SemIR::NameScopeId parent_scope_id, + SemIR::NameId name_id) + -> std::tuple { + // Add the class declaration. + auto class_decl = SemIR::ClassDecl{.type_id = SemIR::TypeType::TypeId, + .class_id = SemIR::ClassId::None, + .decl_block_id = SemIR::InstBlockId::None}; + // TODO: Consider setting a proper location. + auto class_decl_id = AddPlaceholderInstInNoBlock( + context, SemIR::LocIdAndInst::NoLoc(class_decl)); + context.imports().push_back(class_decl_id); + + SemIR::Class class_info = { + {.name_id = name_id, + .parent_scope_id = parent_scope_id, + .generic_id = SemIR::GenericId::None, + .first_param_node_id = Parse::NodeId::None, + .last_param_node_id = Parse::NodeId::None, + .pattern_block_id = SemIR::InstBlockId::None, + .implicit_param_patterns_id = SemIR::InstBlockId::None, + .param_patterns_id = SemIR::InstBlockId::None, + .is_extern = false, + .extern_library_id = SemIR::LibraryNameId::None, + .non_owning_decl_id = SemIR::InstId::None, + .first_owning_decl_id = class_decl_id}, + {// `.self_type_id` depends on the ClassType, so is set below. + .self_type_id = SemIR::TypeId::None, + // TODO: Support Dynamic classes. + // TODO: Support Final classes. + .inheritance_kind = SemIR::Class::Base}}; + + class_decl.class_id = context.classes().Add(class_info); + + // Write the class ID into the ClassDecl. + ReplaceInstBeforeConstantUse(context, class_decl_id, class_decl); + + SetClassSelfType(context, class_decl.class_id); + + return {class_decl.class_id, class_decl_id}; +} + +// Creates a class definition for the given class name in the given scope based +// on the information in the given Clang declaration. Returns the `InstId` for +// the declaration, which is assumed to be for a class definition. Returns the +// new class id and instruction id. +static auto BuildClassDefinition(Context& context, + SemIR::NameScopeId parent_scope_id, + SemIR::NameId name_id, + clang::CXXRecordDecl* clang_decl) + -> std::tuple { + auto [class_id, class_inst_id] = + BuildClassDecl(context, parent_scope_id, name_id); + auto& class_info = context.classes().Get(class_id); + StartClassDefinition(context, class_info, class_inst_id); + + context.name_scopes() + .Get(class_info.scope_id) + .set_clang_decl_context_id(context.sem_ir().clang_decls().Add( + {.decl = clang_decl, .inst_id = class_inst_id})); + + return {class_id, class_inst_id}; +} + +// Imports a record declaration from Clang to Carbon. If successful, returns +// the new Carbon class declaration `InstId`. +// TODO: Change `clang_decl` to `const &` when lookup is using `clang::DeclID` +// and we don't need to store the decl for lookup context. +static auto ImportCXXRecordDecl(Context& context, SemIR::LocId loc_id, + SemIR::NameScopeId parent_scope_id, + SemIR::NameId name_id, + clang::CXXRecordDecl* clang_decl) + -> SemIR::InstId { + clang::CXXRecordDecl* clang_def = clang_decl->getDefinition(); + if (!clang_def) { + context.TODO(loc_id, + "Unsupported: Record declarations without a definition"); + return SemIR::ErrorInst::InstId; + } + + if (clang_def->isDynamicClass()) { + context.TODO(loc_id, "Unsupported: Dynamic Class"); + return SemIR::ErrorInst::InstId; + } + + auto [class_id, class_def_id] = + BuildClassDefinition(context, parent_scope_id, name_id, clang_def); + + // The class type is now fully defined. Compute its object representation. + ComputeClassObjectRepr(context, + // TODO: Consider having a proper location here. + Parse::ClassDefinitionId::None, class_id, + // TODO: Set fields. + /*field_decls=*/{}, + // TODO: Set vtable. + /*vtable_contents=*/{}, + // TODO: Set block. + /*body=*/{}); + + return class_def_id; +} + // Creates an integer type of the given size. static auto MakeIntType(Context& context, IntId size_id) -> TypeExpr { // TODO: Fill in a location for the type once available. @@ -312,23 +501,19 @@ static auto MakeIntType(Context& context, IntId size_id) -> TypeExpr { return ExprAsType(context, Parse::NodeId::None, type_inst_id); } -// Maps a C++ type to a Carbon type. -// TODO: Support more types. -static auto MapType(Context& context, clang::QualType type) -> TypeExpr { - const auto* builtin_type = dyn_cast(type); - if (!builtin_type) { - return {.inst_id = SemIR::ErrorInst::TypeInstId, - .type_id = SemIR::ErrorInst::TypeId}; - } +// Maps a C++ builtin type to a Carbon type. +// TODO: Support more builtin types. +static auto MapBuiltinType(Context& context, const clang::BuiltinType& type) + -> TypeExpr { // TODO: Refactor to avoid duplication. - switch (builtin_type->getKind()) { + switch (type.getKind()) { case clang::BuiltinType::Short: - if (context.ast_context().getTypeSize(type) == 16) { + if (context.ast_context().getTypeSize(&type) == 16) { return MakeIntType(context, context.ints().Add(16)); } break; case clang::BuiltinType::Int: - if (context.ast_context().getTypeSize(type) == 32) { + if (context.ast_context().getTypeSize(&type) == 32) { return MakeIntType(context, context.ints().Add(32)); } break; @@ -339,6 +524,57 @@ static auto MapType(Context& context, clang::QualType type) -> TypeExpr { .type_id = SemIR::ErrorInst::TypeId}; } +// Maps a C++ record type to a Carbon type. +// TODO: Support more record types. +static auto MapRecordType(Context& context, SemIR::LocId loc_id, + const clang::RecordType& type) -> TypeExpr { + auto* record_decl = clang::dyn_cast(type.getDecl()); + if (record_decl && record_decl->isStruct()) { + auto& clang_decls = context.sem_ir().clang_decls(); + SemIR::InstId struct_inst_id = SemIR::InstId::None; + if (auto struct_clang_decl_id = clang_decls.Lookup( + {.decl = record_decl, .inst_id = SemIR::InstId::None}); + struct_clang_decl_id.has_value()) { + struct_inst_id = clang_decls.Get(struct_clang_decl_id).inst_id; + } else { + auto parent_inst_id = + AsCarbonNamespace(context, record_decl->getDeclContext()); + auto parent_name_scope_id = + context.insts().GetAs(parent_inst_id).name_scope_id; + SemIR::NameId struct_name_id = + AddIdentifierName(context, record_decl->getName()); + struct_inst_id = ImportCXXRecordDecl( + context, loc_id, parent_name_scope_id, struct_name_id, record_decl); + AddNameToScope(context, parent_name_scope_id, struct_name_id, + struct_inst_id); + } + SemIR::TypeInstId struct_type_inst_id = + context.types().GetAsTypeInstId(struct_inst_id); + return { + .inst_id = struct_type_inst_id, + .type_id = context.types().GetTypeIdForTypeInstId(struct_type_inst_id)}; + } + + return {.inst_id = SemIR::ErrorInst::TypeInstId, + .type_id = SemIR::ErrorInst::TypeId}; +} + +// Maps a C++ type to a Carbon type. +// TODO: Support more types. +static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) + -> TypeExpr { + if (const auto* builtin_type = dyn_cast(type)) { + return MapBuiltinType(context, *builtin_type); + } + + if (const auto* record_type = clang::dyn_cast(type)) { + return MapRecordType(context, loc_id, *record_type); + } + + return {.inst_id = SemIR::ErrorInst::TypeInstId, + .type_id = SemIR::ErrorInst::TypeId}; +} + // Returns a block id for the explicit parameters of the given function // declaration. If the function declaration has no parameters, it returns // `SemIR::InstBlockId::Empty`. In the case of an unsupported parameter type, it @@ -359,7 +595,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, // Mark the start of a region of insts, needed for the type expression // created later with the call of `EndSubpatternAsExpr()`. BeginSubpattern(context); - auto [type_inst_id, type_id] = MapType(context, param_type); + auto [type_inst_id, type_id] = MapType(context, loc_id, param_type); // Type expression of the binding pattern - a single-entry/single-exit // region that allows control flow in the type expression e.g. fn F(x: if C // then i32 else i64). @@ -378,8 +614,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, // Translate an unnamed parameter to an underscore to // match Carbon's naming of unnamed/unused function params. ? SemIR::NameId::Underscore - : SemIR::NameId::ForIdentifier( - context.sem_ir().identifiers().Add(param_name)); + : AddIdentifierName(context, param_name); // TODO: Fix this once templates are supported. bool is_template = false; @@ -413,7 +648,7 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id, return SemIR::InstId::None; } - auto [type_inst_id, type_id] = MapType(context, ret_type); + auto [type_inst_id, type_id] = MapType(context, loc_id, ret_type); if (type_id == SemIR::ErrorInst::TypeId) { context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}", ret_type.getAsString())); @@ -531,7 +766,8 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, .return_slot_pattern_id = function_params_insts->return_slot_pattern_id, .virtual_modifier = SemIR::FunctionFields::VirtualModifier::None, .self_param_id = SemIR::InstId::None, - .clang_decl_id = context.sem_ir().clang_decls().Add(clang_decl)}}; + .clang_decl_id = context.sem_ir().clang_decls().Add( + {.decl = clang_decl, .inst_id = decl_id})}}; function_decl.function_id = context.functions().Add(function_info); @@ -542,127 +778,6 @@ 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::TypeInstId), - name_id, parent_scope_id, /*import_id=*/SemIR::InstId::None); - context.name_scopes() - .Get(result.name_scope_id) - .set_clang_decl_context_id( - context.sem_ir().clang_decls().Add(clang_decl)); - return result.inst_id; -} - -// Creates a class declaration for the given class name in the given scope. -// Returns the `InstId` for the declaration. -static auto BuildClassDecl(Context& context, SemIR::NameScopeId parent_scope_id, - SemIR::NameId name_id) - -> std::tuple { - // Add the class declaration. - auto class_decl = SemIR::ClassDecl{.type_id = SemIR::TypeType::TypeId, - .class_id = SemIR::ClassId::None, - .decl_block_id = SemIR::InstBlockId::None}; - // TODO: Consider setting a proper location. - auto class_decl_id = AddPlaceholderInstInNoBlock( - context, SemIR::LocIdAndInst::NoLoc(class_decl)); - context.imports().push_back(class_decl_id); - - SemIR::Class class_info = { - {.name_id = name_id, - .parent_scope_id = parent_scope_id, - .generic_id = SemIR::GenericId::None, - .first_param_node_id = Parse::NodeId::None, - .last_param_node_id = Parse::NodeId::None, - .pattern_block_id = SemIR::InstBlockId::None, - .implicit_param_patterns_id = SemIR::InstBlockId::None, - .param_patterns_id = SemIR::InstBlockId::None, - .is_extern = false, - .extern_library_id = SemIR::LibraryNameId::None, - .non_owning_decl_id = SemIR::InstId::None, - .first_owning_decl_id = class_decl_id}, - {// `.self_type_id` depends on the ClassType, so is set below. - .self_type_id = SemIR::TypeId::None, - // TODO: Support Dynamic classes. - // TODO: Support Final classes. - .inheritance_kind = SemIR::Class::Base}}; - - class_decl.class_id = context.classes().Add(class_info); - - // Write the class ID into the ClassDecl. - ReplaceInstBeforeConstantUse(context, class_decl_id, class_decl); - - SetClassSelfType(context, class_decl.class_id); - - return {class_decl.class_id, class_decl_id}; -} - -// Creates a class definition for the given class name in the given scope based -// on the information in the given Clang declaration. Returns the `InstId` for -// the declaration, which is assumed to be for a class definition. Returns the -// new class id and instruction id. -static auto BuildClassDefinition(Context& context, - SemIR::NameScopeId parent_scope_id, - SemIR::NameId name_id, - clang::CXXRecordDecl* clang_decl) - -> std::tuple { - auto [class_id, class_decl_id] = - BuildClassDecl(context, parent_scope_id, name_id); - auto& class_info = context.classes().Get(class_id); - StartClassDefinition(context, class_info, class_decl_id); - - context.name_scopes() - .Get(class_info.scope_id) - .set_clang_decl_context_id( - context.sem_ir().clang_decls().Add(clang_decl)); - - return {class_id, class_decl_id}; -} - -// Imports a record declaration from Clang to Carbon. If successful, returns -// the new Carbon class declaration `InstId`. -// TODO: Change `clang_decl` to `const &` when lookup is using `clang::DeclID` -// and we don't need to store the decl for lookup context. -static auto ImportCXXRecordDecl(Context& context, SemIR::LocId loc_id, - SemIR::NameScopeId parent_scope_id, - SemIR::NameId name_id, - clang::CXXRecordDecl* clang_decl) - -> SemIR::InstId { - clang::CXXRecordDecl* clang_def = clang_decl->getDefinition(); - if (!clang_def) { - context.TODO(loc_id, - "Unsupported: Record declarations without a definition"); - return SemIR::ErrorInst::InstId; - } - - if (clang_def->isDynamicClass()) { - context.TODO(loc_id, "Unsupported: Dynamic Class"); - return SemIR::ErrorInst::InstId; - } - - auto [class_id, class_def_id] = - BuildClassDefinition(context, parent_scope_id, name_id, clang_def); - - // The class type is now fully defined. Compute its object representation. - ComputeClassObjectRepr(context, - // TODO: Consider having a proper location here. - Parse::ClassDefinitionId::None, class_id, - // TODO: Set fields. - /*field_decls=*/{}, - // TODO: Set vtable. - /*vtable_contents=*/{}, - // TODO: Set block. - /*body=*/{}); - - return class_def_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, @@ -690,6 +805,19 @@ static auto ImportNameDecl(Context& context, SemIR::LocId loc_id, return SemIR::InstId::None; } +// Imports a `clang::NamedDecl` into Carbon and adds that name into the +// `NameScope`. +static auto ImportNameDeclIntoScope(Context& context, SemIR::LocId loc_id, + SemIR::NameScopeId scope_id, + SemIR::NameId name_id, + clang::NamedDecl* clang_decl) + -> SemIR::InstId { + SemIR::InstId inst_id = + ImportNameDecl(context, loc_id, scope_id, name_id, clang_decl); + AddNameToScope(context, scope_id, name_id, inst_id); + return inst_id; +} + auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, SemIR::NameScopeId scope_id, SemIR::NameId name_id) -> SemIR::InstId { @@ -711,11 +839,13 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, "find a single result; LookupResultKind: {0}", static_cast(lookup->getResultKind())) .str()); + context.name_scopes().AddRequiredName(scope_id, name_id, + SemIR::ErrorInst::InstId); return SemIR::ErrorInst::InstId; } - return ImportNameDecl(context, loc_id, scope_id, name_id, - lookup->getFoundDecl()); + return ImportNameDeclIntoScope(context, loc_id, scope_id, name_id, + lookup->getFoundDecl()); } } // namespace Carbon::Check diff --git a/toolchain/check/name_lookup.cpp b/toolchain/check/name_lookup.cpp index 1d9b45fbee63..60d5032ea7ca 100644 --- a/toolchain/check/name_lookup.cpp +++ b/toolchain/check/name_lookup.cpp @@ -190,10 +190,8 @@ auto LookupNameInExactScope(Context& context, SemIR::LocId loc_id, SemIR::InstId imported_inst_id = ImportNameFromCpp(context, loc_id, scope_id, name_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}); - return result; + return SemIR::ScopeLookupResult::MakeFound(imported_inst_id, + SemIR::AccessKind::Public); } } diff --git a/toolchain/check/testdata/interop/cpp/function/class.carbon b/toolchain/check/testdata/interop/cpp/function/class.carbon new file mode 100644 index 000000000000..e5154114464b --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/function/class.carbon @@ -0,0 +1,729 @@ +// 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 +// +// EXTRA-ARGS: --no-prelude-import +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/function/class.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/class.carbon + +// ============================================================================ +// Forward-declared class as parameter type +// ============================================================================ + +// --- decl_value_param_type.h + +class C; + +auto foo(C) -> void; + +// --- fail_todo_import_decl_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "decl_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // TODO: This should fail on the fact `C` is declared and not defined. + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined class without data members as parameter type +// ============================================================================ + +// --- definition_no_data_members_value_param_type.h + +class C {}; + +auto foo(C) -> void; + +// --- fail_todo_import_definition_no_data_members_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_no_data_members_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined class with a single data member as parameter type +// ============================================================================ + +// --- definition_single_data_member_value_param_type.h + +class D {}; + +class C { + D d; +}; + +auto foo(C) -> void; + +// --- fail_todo_import_definition_single_data_member_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_single_data_member_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined class with multiple data members as parameter type +// ============================================================================ + +// --- definition_multiple_data_members_value_param_type.h + +class D {}; + +class C { + D d1; + D d2; + D d3; +}; + +auto foo(C) -> void; + +// --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_multiple_data_members_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined class in namespace +// ============================================================================ + +// --- definition_in_namespace_value_param_type.h + +namespace N { class C {}; } + +auto foo(N::C) -> void; + +// --- fail_todo_import_definition_in_namespace_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_in_namespace_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_in_namespace_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class N::C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_in_namespace_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined class in relative namespace +// ============================================================================ + +// --- definition_in_relative_namespace_value_param_type.h + +namespace N1 { + namespace N2 { class C {}; } + auto foo(N2::C) -> void; +} + +// --- fail_todo_import_definition_in_relative_namespace_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_in_relative_namespace_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_in_relative_namespace_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class N1::N2::C` [SemanticsTodo] + // CHECK:STDERR: Cpp.N1.foo({}); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_in_relative_namespace_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.N1.foo({}); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + Cpp.N1.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined class and explicitly used +// ============================================================================ + +// --- definition_with_static_method.h + +class C { + static void bar(); +}; + +auto foo(C) -> void; + +// --- fail_todo_import_definition_and_static_method_call_before.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_with_static_method.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.C.bar(); + // CHECK:STDERR: fail_todo_import_definition_and_static_method_call_before.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_and_static_method_call_before.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({}); + //@dump-sem-ir-end +} + +// --- fail_todo_import_definition_and_static_method_call_after.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_with_static_method.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_and_static_method_call_after.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_and_static_method_call_after.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({}); + Cpp.C.bar(); + //@dump-sem-ir-end +} + +// ============================================================================ +// Pointer to forward-declared class as parameter type +// ============================================================================ + +// --- decl_pointer_param_type.h + +class C; + +auto foo(C*) -> void; + +// --- fail_todo_import_decl_pointer_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "decl_pointer_param_type.h"; + +// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+7]]:9: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] +// CHECK:STDERR: fn F(s: Cpp.C*) { +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+4]]:9: note: in `Cpp` name lookup for `C` [InCppNameLookup] +// CHECK:STDERR: fn F(s: Cpp.C*) { +// CHECK:STDERR: ^~~~~ +// CHECK:STDERR: +fn F(s: Cpp.C*) { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C *` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(s); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(s); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo(s); + //@dump-sem-ir-end +} + +// ============================================================================ +// Pointer to defined class as parameter type +// ============================================================================ + +// --- definition_pointer_param_type.h + +class C {}; + +auto foo(C*) -> void; + +// --- fail_todo_import_definition_pointer_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_pointer_param_type.h"; + +fn F(s: Cpp.C*) { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_pointer_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: class C *` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(s); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_pointer_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(s); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo(s); + //@dump-sem-ir-end +} + +// ============================================================================ +// Forward-declared class as return type +// ============================================================================ + +// --- decl_value_return_type.h + +class C; + +auto foo() -> C; + +// --- fail_todo_import_decl_value_return_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "decl_value_return_type.h"; + +fn F() { + // TODO: This should fail on the fact `C` is declared and not defined. + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo(); +} + +// ============================================================================ +// Defined class as return type +// ============================================================================ + +// --- definition_value_return_type.h + +class C {}; + +auto foo() -> C; + +// --- fail_todo_import_definition_value_return_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_value_return_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo(); + //@dump-sem-ir-end +} + +// ============================================================================ +// Pointer to forward-declared class as return type +// ============================================================================ + +// --- decl_pointer_return_type.h + +class C; + +auto foo() -> C*; + +// --- fail_todo_import_decl_pointer_return_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "decl_pointer_return_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C *` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo(); + //@dump-sem-ir-end +} + +// ============================================================================ +// Pointer to defined class as return type +// ============================================================================ + +// --- definition_pointer_return_type.h + +class C {}; + +auto foo() -> C*; + +// --- fail_todo_import_definition_pointer_return_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_pointer_return_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_definition_pointer_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: class C *` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_pointer_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo(); + //@dump-sem-ir-end +} + +// CHECK:STDOUT: --- fail_todo_import_decl_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc16: %empty_struct_type = struct_literal () +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_no_data_members_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_single_data_member_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_in_namespace_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_in_relative_namespace_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .N1 = %N1 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %N1: = namespace [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %N1.ref: = name_ref N1, imports.%N1 [concrete = imports.%N1] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_and_static_method_call_before.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete] +// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar] +// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref() +// CHECK:STDOUT: %Cpp.ref.loc16: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc16: %empty_struct_type = struct_literal () +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_and_static_method_call_after.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete] +// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc16: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar] +// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref() +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_decl_pointer_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%s.param: ) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc22: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %s.ref: = name_ref s, %s [concrete = ] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_pointer_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %C [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%s.param: %ptr) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %s.ref: %ptr = name_ref s, %s +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_value_return_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_decl_pointer_return_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_definition_pointer_return_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/struct.carbon b/toolchain/check/testdata/interop/cpp/function/struct.carbon index 22e8526c8818..a11752fd6ec7 100644 --- a/toolchain/check/testdata/interop/cpp/function/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/struct.carbon @@ -29,6 +29,13 @@ import Cpp library "decl_value_param_type.h"; fn F() { //@dump-sem-ir-begin // TODO: This should fail on the fact `S` is declared and not defined. + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+14]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+11]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo] // CHECK:STDERR: Cpp.foo({}); // CHECK:STDERR: ^~~~~~~ @@ -50,7 +57,7 @@ struct S {}; auto foo(S) -> void; -// --- fail_todo_import_definition_no_data_members_value_param_type.carbon +// --- import_definition_no_data_members_value_param_type.carbon library "[[@TEST_NAME]]"; @@ -58,13 +65,6 @@ import Cpp library "definition_no_data_members_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_definition_no_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end } @@ -83,7 +83,7 @@ struct S { auto foo(S) -> void; -// --- fail_todo_import_definition_single_data_member_value_param_type.carbon +// --- import_definition_single_data_member_value_param_type.carbon library "[[@TEST_NAME]]"; @@ -91,13 +91,6 @@ import Cpp library "definition_single_data_member_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end } @@ -118,7 +111,7 @@ struct S { auto foo(S) -> void; -// --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon +// --- import_definition_multiple_data_members_value_param_type.carbon library "[[@TEST_NAME]]"; @@ -126,17 +119,93 @@ import Cpp library "definition_multiple_data_members_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: struct S` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end } +// ============================================================================ +// Defined struct in namespace +// ============================================================================ + +// --- definition_in_namespace_value_param_type.h + +namespace N { struct S {}; } + +auto foo(N::S) -> void; + +// --- import_definition_in_namespace_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_in_namespace_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined struct in relative namespace +// ============================================================================ + +// --- definition_in_relative_namespace_value_param_type.h + +namespace N1 { + namespace N2 { struct S {}; } + auto foo(N2::S) -> void; +} + +// --- import_definition_in_relative_namespace_value_param_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_in_relative_namespace_value_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.N1.foo({}); + //@dump-sem-ir-end +} + +// ============================================================================ +// Defined struct and explicitly used +// ============================================================================ + +// --- definition_with_static_method.h + +struct S { + static void bar(); +}; + +auto foo(S) -> void; + +// --- import_definition_and_static_method_call_before.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_with_static_method.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.S.bar(); + Cpp.foo({}); + //@dump-sem-ir-end +} + +// --- import_definition_and_static_method_call_after.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "definition_with_static_method.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.foo({}); + Cpp.S.bar(); + //@dump-sem-ir-end +} + // ============================================================================ // Pointer to forward-declared struct as parameter type // ============================================================================ @@ -221,6 +290,13 @@ import Cpp library "decl_value_return_type.h"; fn F() { //@dump-sem-ir-begin // TODO: This should fail on the fact `S` is declared and not defined. + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+14]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+11]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: struct S` [SemanticsTodo] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~ @@ -242,7 +318,7 @@ struct S {}; auto foo() -> S; -// --- fail_todo_import_definition_value_return_type.carbon +// --- import_definition_value_return_type.carbon library "[[@TEST_NAME]]"; @@ -250,13 +326,6 @@ import Cpp library "definition_value_return_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: return type: struct S` [SemanticsTodo] - // CHECK:STDERR: Cpp.foo(); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_todo_import_definition_value_return_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo(); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: Cpp.foo(); //@dump-sem-ir-end } @@ -328,6 +397,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: .S = // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -336,70 +406,296 @@ fn F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %.loc16: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc23: %empty_struct_type = struct_literal () // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_definition_no_data_members_value_param_type.carbon +// CHECK:STDOUT: --- import_definition_no_data_members_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .S = %S.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_definition_single_data_member_value_param_type.carbon +// CHECK:STDOUT: --- import_definition_single_data_member_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .S = %S.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon +// CHECK:STDOUT: --- import_definition_multiple_data_members_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .S = %S.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_definition_in_namespace_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_definition_in_relative_namespace_value_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .N1 = %N1 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %N1: = namespace [concrete] { +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %N1.ref: = name_ref N1, imports.%N1 [concrete = imports.%N1] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_15.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_15.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_15.3: init %S = class_init (), %.loc8_15.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_15.4: ref %S = temporary %.loc8_15.2, %.loc8_15.3 +// CHECK:STDOUT: %.loc8_15.5: ref %S = converted %.loc8_15.1, %.loc8_15.4 +// CHECK:STDOUT: %.loc8_15.6: %S = bind_value %.loc8_15.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_15.6) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_definition_and_static_method_call_before.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete] +// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .S = %S.decl +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: +// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] +// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar] +// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref() +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc9_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc9_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc9_12.3: init %S = class_init (), %.loc9_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc9_12.4: ref %S = temporary %.loc9_12.2, %.loc9_12.3 +// CHECK:STDOUT: %.loc9_12.5: ref %S = converted %.loc9_12.1, %.loc9_12.4 +// CHECK:STDOUT: %.loc9_12.6: %S = bind_value %.loc9_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc9_12.6) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- import_definition_and_static_method_call_after.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] +// CHECK:STDOUT: %bar.type: type = fn_type @bar [concrete] +// CHECK:STDOUT: %bar: %bar.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .S = %S.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %bar.decl: %bar.type = fn_decl @bar [concrete = constants.%bar] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_12.5: ref %S = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_12.6: %S = bind_value %.loc8_12.5 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) +// CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] +// CHECK:STDOUT: %bar.ref: %bar.type = name_ref bar, imports.%bar.decl [concrete = constants.%bar] +// CHECK:STDOUT: %bar.call: init %empty_tuple.type = call %bar.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -456,6 +752,7 @@ fn F() { // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { // CHECK:STDOUT: .foo = +// CHECK:STDOUT: .S = // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } // CHECK:STDOUT: } @@ -467,22 +764,35 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_definition_value_return_type.carbon +// CHECK:STDOUT: --- import_definition_value_return_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .S = %S.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_11.1: ref %S = temporary_storage +// CHECK:STDOUT: %foo.call: init %S = call %foo.ref() to %.loc8_11.1 +// CHECK:STDOUT: %.loc8_11.2: ref %S = temporary %.loc8_11.1, %foo.call // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index dd520fce4458..73de32136ff6 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -675,7 +675,7 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id, CARBON_CHECK(!specific_id.has_value(), "Specific functions cannot have C++ definitions"); HandleReferencedCppFunction(clang::dyn_cast( - sem_ir().clang_decls().Get(clang_decl_id))); + sem_ir().clang_decls().Get(clang_decl_id).decl)); // TODO: Check that the signature and mangling generated by Clang and the // one we generated are the same. } diff --git a/toolchain/lower/mangler.cpp b/toolchain/lower/mangler.cpp index be9009811500..4956df37ed44 100644 --- a/toolchain/lower/mangler.cpp +++ b/toolchain/lower/mangler.cpp @@ -152,7 +152,7 @@ auto Mangler::Mangle(SemIR::FunctionId function_id, } if (function.clang_decl_id.has_value()) { return MangleCppClang(llvm::dyn_cast( - sem_ir().clang_decls().Get(function.clang_decl_id))); + sem_ir().clang_decls().Get(function.clang_decl_id).decl)); } RawStringOstream os; os << "_C"; diff --git a/toolchain/sem_ir/BUILD b/toolchain/sem_ir/BUILD index d05f90ee4901..88ff5df34964 100644 --- a/toolchain/sem_ir/BUILD +++ b/toolchain/sem_ir/BUILD @@ -57,6 +57,18 @@ cc_test( ], ) +cc_library( + name = "clang_decl", + srcs = ["clang_decl.cpp"], + hdrs = ["clang_decl.h"], + deps = [ + ":typed_insts", + "//common:hashtable_key_context", + "//common:ostream", + "@llvm-project//clang:ast", + ], +) + cc_library( name = "file", srcs = [ @@ -107,6 +119,7 @@ cc_library( ], deps = [ ":block_value_store", + ":clang_decl", ":typed_insts", "//common:check", "//common:enum_base", diff --git a/toolchain/sem_ir/clang_decl.cpp b/toolchain/sem_ir/clang_decl.cpp new file mode 100644 index 000000000000..a8dbcc736abc --- /dev/null +++ b/toolchain/sem_ir/clang_decl.cpp @@ -0,0 +1,17 @@ +// 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 + +#include "toolchain/sem_ir/clang_decl.h" + +#include "clang/AST/DeclBase.h" + +namespace Carbon::SemIR { + +auto ClangDecl::Print(llvm::raw_ostream& out) const -> void { + out << "{decl: "; + decl->print(out); + out << ", inst_id: " << inst_id << "}"; +} + +} // namespace Carbon::SemIR diff --git a/toolchain/sem_ir/clang_decl.h b/toolchain/sem_ir/clang_decl.h new file mode 100644 index 000000000000..d918f92b4978 --- /dev/null +++ b/toolchain/sem_ir/clang_decl.h @@ -0,0 +1,62 @@ +// 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 + +#ifndef CARBON_TOOLCHAIN_SEM_IR_CLANG_DECL_H_ +#define CARBON_TOOLCHAIN_SEM_IR_CLANG_DECL_H_ + +#include "common/hashtable_key_context.h" +#include "common/ostream.h" +#include "toolchain/sem_ir/ids.h" + +// NOLINTNEXTLINE(readability-identifier-naming) +namespace clang { + +// Forward declare indexed types, for integration with ValueStore. +class Decl; + +} // namespace clang + +namespace Carbon::SemIR { + +// A Clang declaration mapped to a Carbon instruction. +// Using custom hashing since the declaration is keyed by the `decl` member for +// lookup. +// TODO: Avoid custom hashing by either having the data structure support keying +// or create a dedicated mapping. See +// https://discord.com/channels/655572317891461132/768530752592805919/1384999468293947537 +struct ClangDecl : public Printable { + auto Print(llvm::raw_ostream& out) const -> void; + + friend auto CarbonHashtableEq(const ClangDecl& lhs, const ClangDecl& rhs) + -> bool { + return HashtableEq(lhs.decl, rhs.decl); + } + + // Hashing for ClangDecl. See common/hashing.h. + friend auto CarbonHashValue(const ClangDecl& value, uint64_t seed) + -> HashCode { + return HashValue(value.decl, seed); + } + + // The Clang declaration pointing to the Clang AST. + // TODO: Ensure we can easily serialize/deserialize this. Consider + // `clang::LazyDeclPtr`. + clang::Decl* decl = nullptr; + + // The instruction the Clang declaration is mapped to. + InstId inst_id; +}; + +// The ID of a `ClangDecl`. +struct ClangDeclId : public IdBase { + static constexpr llvm::StringLiteral Label = "clang_decl_id"; + + using ValueType = ClangDecl; + + using IdBase::IdBase; +}; + +} // namespace Carbon::SemIR + +#endif // CARBON_TOOLCHAIN_SEM_IR_CLANG_DECL_H_ diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index b57b5b2373e5..5a93d07cb862 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -335,7 +335,9 @@ class File : public Printable { // `Cpp` imports. clang::ASTUnit* cpp_ast_ = nullptr; - // Clang AST declarations pointing to the AST. + // Clang AST declarations pointing to the AST and their mapped Carbon + // instructions. When calling `Lookup()`, `inst_id` is ignored. `Add()` will + // not add multiple entries with the same `decl` and different `inst_id`. CanonicalValueStore clang_decls_; // All instructions. The first entries will always be the singleton diff --git a/toolchain/sem_ir/function.h b/toolchain/sem_ir/function.h index 02c469bf1f89..1ce04c19d3c7 100644 --- a/toolchain/sem_ir/function.h +++ b/toolchain/sem_ir/function.h @@ -7,6 +7,7 @@ #include "clang/AST/Decl.h" #include "toolchain/sem_ir/builtin_function_kind.h" +#include "toolchain/sem_ir/clang_decl.h" #include "toolchain/sem_ir/entity_with_params_base.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst_categories.h" diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 1b89231223e3..f14c6a039f95 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -18,7 +18,6 @@ namespace clang { // Forward declare indexed types, for integration with ValueStore. -class Decl; class SourceLocation; } // namespace clang @@ -788,17 +787,6 @@ struct TypeId : public IdBase { auto Print(llvm::raw_ostream& out) const -> void; }; -// The ID of a Clang `Decl` pointer, pointing to the Clang AST. -struct ClangDeclId : public IdBase { - static constexpr llvm::StringLiteral Label = "clang_decl_id"; - - // TODO: Ensure we can easily serialize/deserialize this. Consider - // `clang::LazyDeclPtr`. - using ValueType = clang::Decl*; - - using IdBase::IdBase; -}; - // The ID of a Clang Source Location. struct ClangSourceLocId : public IdBase { static constexpr llvm::StringLiteral Label = "clang_source_loc"; diff --git a/toolchain/sem_ir/name_scope.h b/toolchain/sem_ir/name_scope.h index b7bb50e07074..6d8d850da416 100644 --- a/toolchain/sem_ir/name_scope.h +++ b/toolchain/sem_ir/name_scope.h @@ -7,6 +7,7 @@ #include "clang/AST/DeclBase.h" #include "common/map.h" +#include "toolchain/sem_ir/clang_decl.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h"