From 36f0a730925b5f19f137290f10f01b58eaffe0bc Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 25 Jul 2025 17:09:24 -0400 Subject: [PATCH] Initial support for interop with class/struct/union fields. (#5849) Add a new type, `custom_layout_type`, representing a struct type whose size, alignment, and field offsets can be manually controlled. Use this as the object representation type for imported C++ class types (which also includes struct and union types), allowing us to model C++ class type layouts. In passing, also add support for incomplete C++ class types, mapping them into incomplete Carbon class types. Map C++ fields into Carbon field declarations, allowing direct access to C++ fields from Carbon. So far, no support is added for base classes nor anonymous struct or union declarations; those will be added in subsequent PRs. Also, we don't map C++ access control into Carbon yet, so all C++ fields are accessible regardless of their access control. For now we still use a `struct_type` as the object representation for empty C++ classes, in order to continue to support our existing tests that convert `{}` to empty C++ class types. This is temporary and should be removed once we support interop with C++ class initialization. --- toolchain/check/BUILD | 1 + toolchain/check/context.h | 3 + toolchain/check/convert.cpp | 4 + toolchain/check/import.cpp | 40 ++ toolchain/check/import.h | 24 + toolchain/check/import_cpp.cpp | 265 +++++-- toolchain/check/import_ref.cpp | 36 +- toolchain/check/import_ref.h | 24 - .../testdata/interop/cpp/class/class.carbon | 140 ++-- .../testdata/interop/cpp/class/field.carbon | 670 ++++++++++++++++++ .../testdata/interop/cpp/class/method.carbon | 24 +- .../testdata/interop/cpp/class/struct.carbon | 204 ++++-- .../testdata/interop/cpp/class/union.carbon | 96 +-- .../interop/cpp/function/class.carbon | 157 ++-- .../interop/cpp/function/in_template.carbon | 1 - .../interop/cpp/function/pointer.carbon | 3 - .../interop/cpp/function/struct.carbon | 149 ++-- .../interop/cpp/function/union.carbon | 106 ++- .../testdata/interop/cpp/namespace.carbon | 1 - toolchain/check/type_completion.cpp | 18 + toolchain/lower/file_context.cpp | 7 + toolchain/lower/function_context.cpp | 2 + toolchain/lower/handle_aggregates.cpp | 49 +- .../lower/testdata/interop/cpp/field.carbon | 234 ++++++ toolchain/sem_ir/expr_info.cpp | 1 + toolchain/sem_ir/file.h | 9 + toolchain/sem_ir/formatter.cpp | 17 + toolchain/sem_ir/formatter.h | 6 +- toolchain/sem_ir/id_kind.h | 1 + toolchain/sem_ir/ids.h | 20 + toolchain/sem_ir/import_ir.cpp | 10 +- toolchain/sem_ir/inst_categories.h | 11 + toolchain/sem_ir/inst_fingerprinter.cpp | 10 + toolchain/sem_ir/inst_kind.def | 1 + toolchain/sem_ir/stringify.cpp | 6 + toolchain/sem_ir/typed_insts.h | 14 + 36 files changed, 1772 insertions(+), 592 deletions(-) create mode 100644 toolchain/check/testdata/interop/cpp/class/field.carbon create mode 100644 toolchain/lower/testdata/interop/cpp/field.carbon diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index a56629750d48..200845a08cb1 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -136,6 +136,7 @@ cc_library( "//toolchain/sem_ir:file", "//toolchain/sem_ir:formatter", "//toolchain/sem_ir:typed_insts", + "@llvm-project//clang:ast", "@llvm-project//clang:basic", "@llvm-project//clang:frontend", "@llvm-project//clang:lex", diff --git a/toolchain/check/context.h b/toolchain/check/context.h index cb1189ebbd7e..b4ea5ce3c270 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -275,6 +275,9 @@ class Context { auto struct_type_fields() -> SemIR::StructTypeFieldsStore& { return sem_ir().struct_type_fields(); } + auto custom_layouts() -> SemIR::CustomLayoutStore& { + return sem_ir().custom_layouts(); + } auto types() -> SemIR::TypeStore& { return sem_ir().types(); } // Instructions should be added with `AddInst` or `AddInstInNoBlock` from // `inst.h`. This is `const` to prevent accidental misuse. diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index 01e226df61aa..2c8f58925d73 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -574,6 +574,10 @@ static auto ConvertStructToClass( if (object_repr_id == SemIR::ErrorInst::TypeId) { return SemIR::ErrorInst::InstId; } + if (context.types().Is(object_repr_id)) { + // Builtin conversion does not apply. + return value_id; + } auto dest_struct_type = context.types().GetAs(object_repr_id); diff --git a/toolchain/check/import.cpp b/toolchain/check/import.cpp index 7ea3b914fafd..196a61d21d00 100644 --- a/toolchain/check/import.cpp +++ b/toolchain/check/import.cpp @@ -700,4 +700,44 @@ auto ImportNameFromOtherPackage( return result_id; } +// Returns whether a parse node associated with an imported instruction of kind +// `imported_kind` is usable as the location of a corresponding local +// instruction of kind `local_kind`. +static auto HasCompatibleImportedNodeKind(SemIR::InstKind imported_kind, + SemIR::InstKind local_kind) -> bool { + if (imported_kind == local_kind) { + return true; + } + if (imported_kind == SemIR::ImportDecl::Kind && + local_kind == SemIR::Namespace::Kind) { + static_assert( + std::is_convertible_v); + return true; + } + return false; +} + +namespace Internal { + +auto CheckCompatibleImportedNodeKind(Context& context, + SemIR::ImportIRInstId imported_loc_id, + SemIR::InstKind kind) -> void { + auto& import_ir_inst = context.import_ir_insts().Get(imported_loc_id); + if (import_ir_inst.ir_id() == SemIR::ImportIRId::Cpp) { + // We don't require a matching node kind if the location is in C++, because + // there isn't a node. + return; + } + const auto* import_ir = + context.import_irs().Get(import_ir_inst.ir_id()).sem_ir; + auto imported_kind = import_ir->insts().Get(import_ir_inst.inst_id()).kind(); + CARBON_CHECK( + HasCompatibleImportedNodeKind(imported_kind, kind), + "Node of kind {0} created with location of imported node of kind {1}", + kind, imported_kind); +} + +} // namespace Internal + } // namespace Carbon::Check diff --git a/toolchain/check/import.h b/toolchain/check/import.h index 6c1e53bceded..fc89754ff7fb 100644 --- a/toolchain/check/import.h +++ b/toolchain/check/import.h @@ -93,6 +93,30 @@ auto ImportNameFromOtherPackage( import_ir_scopes, SemIR::NameId name_id) -> SemIR::InstId; +namespace Internal { + +// Checks that the provided imported location has a node kind that is +// compatible with that of the given instruction. +auto CheckCompatibleImportedNodeKind(Context& context, + SemIR::ImportIRInstId imported_loc_id, + SemIR::InstKind kind) -> void; +} // namespace Internal + +// Returns a LocIdAndInst for an instruction with an imported location. Checks +// that the imported location is compatible with the kind of instruction being +// created. +template + requires SemIR::Internal::HasNodeId +auto MakeImportedLocIdAndInst(Context& context, + SemIR::ImportIRInstId imported_loc_id, InstT inst) + -> SemIR::LocIdAndInst { + if constexpr (!SemIR::Internal::HasUntypedNodeId) { + Internal::CheckCompatibleImportedNodeKind(context, imported_loc_id, + InstT::Kind); + } + return SemIR::LocIdAndInst::UncheckedLoc(imported_loc_id, inst); +} + } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_IMPORT_H_ diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index bf057cd5f1fe..439fb87af8a2 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -10,6 +10,8 @@ #include #include +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/Basic/FileManager.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" @@ -42,6 +44,7 @@ #include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/clang_decl.h" #include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/name_scope.h" #include "toolchain/sem_ir/typed_insts.h" @@ -105,9 +108,9 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { public: // Creates an instance with the location that triggers calling Clang. // `context` must not be null. - explicit CarbonClangDiagnosticConsumer(Context* context, - clang::CompilerInvocation* invocation) - : context_(context), invocation_(invocation) {} + explicit CarbonClangDiagnosticConsumer( + Context* context, std::shared_ptr invocation) + : context_(context), invocation_(std::move(invocation)) {} // Generates a Carbon warning for each Clang warning and a Carbon error for // each Clang error or fatal. @@ -185,7 +188,7 @@ class CarbonClangDiagnosticConsumer : public clang::DiagnosticConsumer { Context* context_; // The compiler invocation that is producing the diagnostics. - clang::CompilerInvocation* invocation_; + std::shared_ptr invocation_; // Information on a Clang diagnostic that can be converted to a Carbon // diagnostic. @@ -219,11 +222,11 @@ static auto GenerateAst(Context& context, std::shared_ptr invocation) -> std::pair, bool> { // Build a diagnostics engine. - CarbonClangDiagnosticConsumer diagnostics_consumer(&context, - invocation.get()); + auto diagnostics_consumer = + std::make_unique(&context, invocation); llvm::IntrusiveRefCntPtr diags( clang::CompilerInstance::createDiagnostics( - *fs, invocation->getDiagnosticOpts(), &diagnostics_consumer, + *fs, invocation->getDiagnosticOpts(), diagnostics_consumer.get(), /*ShouldOwnClient=*/false)); // Extract the input from the frontend invocation and make sure it makes @@ -247,9 +250,6 @@ static auto GenerateAst(Context& context, invocation, std::make_shared(), nullptr, diags, new clang::FileManager(invocation->getFileSystemOpts(), fs)); - // Remove link to the diagnostics consumer before its destruction. - ast->getDiagnostics().setClient(nullptr); - // Remove remapped file before its underlying storage is destroyed. invocation->getPreprocessorOpts().clearRemappedFiles(); @@ -259,9 +259,15 @@ static auto GenerateAst(Context& context, context.sem_ir().set_cpp_ast(ast.get()); // Emit any diagnostics we queued up while building the AST. - diagnostics_consumer.EmitDiagnostics(); + diagnostics_consumer->EmitDiagnostics(); + bool any_errors = diagnostics_consumer->getNumErrors() > 0; - return {std::move(ast), !ast || diagnostics_consumer.getNumErrors() > 0}; + // Transfer ownership of the consumer to the AST unit, in case more + // diagnostics are produced by AST queries. + ast->getDiagnostics().setClient(diagnostics_consumer.release(), + /*ShouldOwnClient=*/true); + + return {std::move(ast), !ast || any_errors}; } // Adds a namespace for the `Cpp` import and returns its `NameScopeId`. @@ -373,7 +379,10 @@ static auto ClangLookup(Context& context, SemIR::NameScopeId scope_id, // Returns whether `decl` already mapped to an instruction. static auto IsClangDeclImported(const Context& context, clang::Decl* decl) -> bool { - return context.sem_ir().clang_decls().Lookup(decl).has_value(); + return context.sem_ir() + .clang_decls() + .Lookup(decl->getCanonicalDecl()) + .has_value(); } // If `decl` already mapped to an instruction, returns that instruction. @@ -381,7 +390,7 @@ static auto IsClangDeclImported(const Context& context, clang::Decl* decl) static auto LookupClangDeclInstId(const Context& context, clang::Decl* decl) -> SemIR::InstId { const auto& clang_decls = context.sem_ir().clang_decls(); - if (auto context_clang_decl_id = clang_decls.Lookup(decl); + if (auto context_clang_decl_id = clang_decls.Lookup(decl->getCanonicalDecl()); context_clang_decl_id.has_value()) { return clang_decls.Get(context_clang_decl_id).inst_id; } @@ -442,22 +451,27 @@ static auto ImportNamespaceDecl(Context& context, 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})); + {.decl = clang_decl->getCanonicalDecl(), .inst_id = result.inst_id})); return result.inst_id; } +static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) + -> TypeExpr; + // 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, +static auto BuildClassDecl(Context& context, + SemIR::ImportIRInstId import_ir_inst_id, + SemIR::NameScopeId parent_scope_id, SemIR::NameId name_id) - -> std::tuple { + -> 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, + SemIR::LocIdAndInst::UncheckedLoc(import_ir_inst_id, class_decl)); context.imports().push_back(class_decl_id); SemIR::Class class_info = { @@ -486,76 +500,159 @@ static auto BuildClassDecl(Context& context, SemIR::NameScopeId parent_scope_id, SetClassSelfType(context, class_decl.class_id); - return {class_decl.class_id, class_decl_id}; + return {class_decl.class_id, context.types().GetAsTypeInstId(class_decl_id)}; +} + +// Checks that the specified finished class definition is valid and builds and +// returns a corresponding complete type witness instruction. +// TODO: Remove recursion into mapping field types. +// NOLINTNEXTLINE(misc-no-recursion) +static auto ImportClassObjectRepr(Context& context, + SemIR::ImportIRInstId import_ir_inst_id, + SemIR::TypeInstId class_type_inst_id, + const clang::CXXRecordDecl* clang_def) + -> SemIR::TypeInstId { + // For now, if the class is empty, produce an empty struct as the object + // representation. This allows our tests to continue to pass while we don't + // properly support initializing imported C++ classes. + // TODO: Remove this. + if (clang_def->isEmpty()) { + return context.types().GetAsTypeInstId(AddInst( + context, + MakeImportedLocIdAndInst( + context, import_ir_inst_id, + SemIR::StructType{.type_id = SemIR::TypeType::TypeId, + .fields_id = SemIR::StructTypeFieldsId::Empty}))); + } + + const auto& clang_layout = + context.ast_context().getASTRecordLayout(clang_def); + + llvm::SmallVector layout; + llvm::SmallVector fields; + + static_assert(SemIR::CustomLayoutId::SizeIndex == 0); + layout.push_back(clang_layout.getSize().getQuantity()); + + static_assert(SemIR::CustomLayoutId::AlignIndex == 1); + layout.push_back(clang_layout.getAlignment().getQuantity()); + + static_assert(SemIR::CustomLayoutId::FirstFieldIndex == 2); + + // TODO: Import vptr(s). + // TODO: Import bases. + + // Import fields. + for (auto* field : clang_def->fields()) { + if (field->isBitField()) { + // TODO: Add a representation for named bitfield members. + continue; + } + if (field->isAnonymousStructOrUnion()) { + // TODO: Visit IndirectFieldDecls and add them to the layout. + continue; + } + + auto field_name_id = AddIdentifierName(context, field->getName()); + auto [field_type_inst_id, field_type_id] = + MapType(context, import_ir_inst_id, field->getType()); + + // Create a field now, as we know the index to use. + // TODO: Consider doing this lazily instead. + auto field_decl_id = AddInst( + context, MakeImportedLocIdAndInst( + context, import_ir_inst_id, + SemIR::FieldDecl{ + .type_id = GetUnboundElementType( + context, class_type_inst_id, field_type_inst_id), + .name_id = field_name_id, + .index = SemIR::ElementIndex(fields.size())})); + context.sem_ir().clang_decls().Add( + {.decl = field->getCanonicalDecl(), .inst_id = field_decl_id}); + + layout.push_back(context.ast_context() + .toCharUnitsFromBits(clang_layout.getFieldOffset( + field->getFieldIndex())) + .getQuantity()); + fields.push_back( + {.name_id = field_name_id, .type_inst_id = field_type_inst_id}); + } + + // TODO: Add a field to prevent tail padding reuse if necessary. + + return AddTypeInst( + context, import_ir_inst_id, + {.type_id = SemIR::TypeType::TypeId, + .fields_id = context.struct_type_fields().Add(fields), + .layout_id = context.custom_layouts().Add(layout)}); } // Creates a class definition based on the information in the given Clang -// declaration, which is assumed to be for a class definition. Returns the new -// class id and instruction id. +// declaration, which is assumed to be for a class definition. +// TODO: Remove recursion into mapping field types. +// NOLINTNEXTLINE(misc-no-recursion) static auto BuildClassDefinition(Context& context, - clang::CXXRecordDecl* clang_decl) - -> std::tuple { - auto [class_id, class_inst_id] = - BuildClassDecl(context, GetParentNameScopeId(context, clang_decl), - AddIdentifierName(context, clang_decl->getName())); + SemIR::ImportIRInstId import_ir_inst_id, + SemIR::ClassId class_id, + SemIR::TypeInstId class_inst_id, + SemIR::ClangDeclId clang_decl_id, + clang::CXXRecordDecl* clang_def) -> void { auto& class_info = context.classes().Get(class_id); StartClassDefinition(context, class_info, class_inst_id); + // Name lookup into the Carbon class looks in the C++ class definition. 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})); + .set_clang_decl_context_id(clang_decl_id); - return {class_id, class_inst_id}; + context.inst_block_stack().Push(); + + // Compute the class's object representation. + auto object_repr_id = ImportClassObjectRepr(context, import_ir_inst_id, + class_inst_id, clang_def); + class_info.complete_type_witness_id = AddInst( + context, import_ir_inst_id, + {.type_id = GetSingletonType(context, SemIR::WitnessType::TypeInstId), + .object_repr_type_inst_id = object_repr_id}); + + class_info.body_block_id = context.inst_block_stack().Pop(); } // Mark the given `Decl` as failed in `clang_decls`. static auto MarkFailedDecl(Context& context, clang::Decl* clang_decl) { - context.sem_ir().clang_decls().Add( - {.decl = clang_decl, .inst_id = SemIR::ErrorInst::InstId}); + context.sem_ir().clang_decls().Add({.decl = clang_decl->getCanonicalDecl(), + .inst_id = SemIR::ErrorInst::InstId}); } // 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, +// TODO: Remove recursion into mapping field types. +// NOLINTNEXTLINE(misc-no-recursion) +static auto ImportCXXRecordDecl(Context& context, 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"); - MarkFailedDecl(context, clang_decl); - return SemIR::ErrorInst::InstId; + if (clang_def) { + clang_decl = clang_def; + } + auto import_ir_inst_id = AddImportIRInst(context, clang_decl->getLocation()); + + auto [class_id, class_inst_id] = BuildClassDecl( + context, import_ir_inst_id, GetParentNameScopeId(context, clang_decl), + AddIdentifierName(context, clang_decl->getName())); + + // TODO: The caller does the same lookup. Avoid doing it twice. + auto clang_decl_id = context.sem_ir().clang_decls().Add( + {.decl = clang_decl->getCanonicalDecl(), .inst_id = class_inst_id}); + + if (clang_def) { + BuildClassDefinition(context, import_ir_inst_id, class_id, class_inst_id, + clang_decl_id, clang_def); } - if (clang_def->isDynamicClass()) { - context.TODO(loc_id, "Unsupported: Dynamic Class"); - MarkFailedDecl(context, clang_decl); - return SemIR::ErrorInst::InstId; - } - - if (clang_def->isUnion() && !clang_def->fields().empty()) { - context.TODO(loc_id, "Unsupported: Non-empty union"); - MarkFailedDecl(context, clang_decl); - return SemIR::ErrorInst::InstId; - } - - auto [class_id, class_def_id] = BuildClassDefinition(context, 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; + return class_inst_id; } // Creates an integer type of the given size. @@ -587,8 +684,10 @@ static auto MapBuiltinType(Context& context, clang::QualType qual_type, // 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 { +// TODO: Remove recursion mapping fields of class types. +// NOLINTNEXTLINE(misc-no-recursion) +static auto MapRecordType(Context& context, const clang::RecordType& type) + -> TypeExpr { auto* record_decl = clang::dyn_cast(type.getDecl()); if (!record_decl) { return {.inst_id = SemIR::TypeInstId::None, .type_id = SemIR::TypeId::None}; @@ -597,7 +696,7 @@ static auto MapRecordType(Context& context, SemIR::LocId loc_id, // Check if the declaration is already mapped. SemIR::InstId record_inst_id = LookupClangDeclInstId(context, record_decl); if (!record_inst_id.has_value()) { - record_inst_id = ImportCXXRecordDecl(context, loc_id, record_decl); + record_inst_id = ImportCXXRecordDecl(context, record_decl); } SemIR::TypeInstId record_type_inst_id = context.types().GetAsTypeInstId(record_inst_id); @@ -609,14 +708,16 @@ static auto MapRecordType(Context& context, SemIR::LocId loc_id, // Maps a C++ type that is not a wrapper type such as a pointer to a Carbon // type. // TODO: Support more types. -static auto MapNonWrapperType(Context& context, SemIR::LocId loc_id, - clang::QualType type) -> TypeExpr { +// TODO: Remove recursion mapping fields of class types. +// NOLINTNEXTLINE(misc-no-recursion) +static auto MapNonWrapperType(Context& context, clang::QualType type) + -> TypeExpr { if (const auto* builtin_type = type->getAs()) { return MapBuiltinType(context, type, *builtin_type); } if (const auto* record_type = type->getAs()) { - return MapRecordType(context, loc_id, *record_type); + return MapRecordType(context, *record_type); } CARBON_CHECK(!type.hasQualifiers() && !type->isPointerType(), @@ -673,6 +774,8 @@ static auto MapPointerType(Context& context, SemIR::LocId loc_id, // Maps a C++ type to a Carbon type. `type` should not be canonicalized because // we check for pointer nullability and nullability will be lost by // canonicalization. +// TODO: Remove recursion mapping fields of class types. +// NOLINTNEXTLINE(misc-no-recursion) static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) -> TypeExpr { // Unwrap any type modifiers and wrappers. @@ -689,7 +792,7 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) wrapper_types.push_back(orig_type); } - auto mapped = MapNonWrapperType(context, loc_id, type); + auto mapped = MapNonWrapperType(context, type); for (auto wrapper : llvm::reverse(wrapper_types)) { if (!mapped.inst_id.has_value() || @@ -961,6 +1064,7 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, MarkFailedDecl(context, clang_decl); return SemIR::ErrorInst::InstId; } + if (clang_decl->getTemplatedKind() == clang::FunctionDecl::TK_FunctionTemplate) { context.TODO(loc_id, "Unsupported: Template function"); @@ -968,6 +1072,14 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, return SemIR::ErrorInst::InstId; } + if (auto* method_decl = dyn_cast(clang_decl)) { + if (method_decl->isVirtual()) { + context.TODO(loc_id, "Unsupported: Virtual function"); + MarkFailedDecl(context, clang_decl); + return SemIR::ErrorInst::InstId; + } + } + context.scope_stack().PushForDeclName(); context.inst_block_stack().Push(); context.pattern_block_stack().Push(); @@ -1047,6 +1159,7 @@ static auto GetDependentUnimportedTypeDecls(const Context& context, if (!IsClangDeclImported(context, record_decl)) { return {record_decl}; } + // TODO: Also collect field types. } } @@ -1115,6 +1228,16 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id, } return type_inst_id; } + if (clang::isa(clang_decl)) { + // Usable fields get imported as a side effect of importing the class. + if (SemIR::InstId existing_inst_id = + LookupClangDeclInstId(context, clang_decl); + existing_inst_id.has_value()) { + return existing_inst_id; + } + context.TODO(loc_id, "Unsupported: Unhandled kind of field declaration"); + return SemIR::InstId::None; + } context.TODO(loc_id, llvm::formatv("Unsupported: Declaration type {0}", clang_decl->getDeclKindName()) diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 1d125ed018b9..b025af0e0b4a 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -15,6 +15,7 @@ #include "toolchain/check/context.h" #include "toolchain/check/eval.h" #include "toolchain/check/generic.h" +#include "toolchain/check/import.h" #include "toolchain/check/inst.h" #include "toolchain/check/name_lookup.h" #include "toolchain/check/type.h" @@ -3440,39 +3441,4 @@ auto ImportImpl(Context& context, SemIR::ImportIRId import_ir_id, .first_decl_id()); } -// Returns whether a parse node associated with an imported instruction of kind -// `imported_kind` is usable as the location of a corresponding local -// instruction of kind `local_kind`. -static auto HasCompatibleImportedNodeKind(SemIR::InstKind imported_kind, - SemIR::InstKind local_kind) -> bool { - if (imported_kind == local_kind) { - return true; - } - if (imported_kind == SemIR::ImportDecl::Kind && - local_kind == SemIR::Namespace::Kind) { - static_assert( - std::is_convertible_v); - return true; - } - return false; -} - -namespace Internal { - -auto CheckCompatibleImportedNodeKind(Context& context, - SemIR::ImportIRInstId imported_loc_id, - SemIR::InstKind kind) -> void { - auto& import_ir_inst = context.import_ir_insts().Get(imported_loc_id); - const auto* import_ir = - context.import_irs().Get(import_ir_inst.ir_id()).sem_ir; - auto imported_kind = import_ir->insts().Get(import_ir_inst.inst_id()).kind(); - CARBON_CHECK( - HasCompatibleImportedNodeKind(imported_kind, kind), - "Node of kind {0} created with location of imported node of kind {1}", - kind, imported_kind); -} - -} // namespace Internal - } // namespace Carbon::Check diff --git a/toolchain/check/import_ref.h b/toolchain/check/import_ref.h index fc84ae8e51fb..5ddc78b96741 100644 --- a/toolchain/check/import_ref.h +++ b/toolchain/check/import_ref.h @@ -52,30 +52,6 @@ auto ImportImplsFromApiFile(Context& context) -> void; auto ImportImpl(Context& context, SemIR::ImportIRId import_ir_id, SemIR::ImplId impl_id) -> void; -namespace Internal { - -// Checks that the provided imported location has a node kind that is -// compatible with that of the given instruction. -auto CheckCompatibleImportedNodeKind(Context& context, - SemIR::ImportIRInstId imported_loc_id, - SemIR::InstKind kind) -> void; -} // namespace Internal - -// Returns a LocIdAndInst for an instruction with an imported location. Checks -// that the imported location is compatible with the kind of instruction being -// created. -template - requires SemIR::Internal::HasNodeId -auto MakeImportedLocIdAndInst(Context& context, - SemIR::ImportIRInstId imported_loc_id, InstT inst) - -> SemIR::LocIdAndInst { - if constexpr (!SemIR::Internal::HasUntypedNodeId) { - Internal::CheckCompatibleImportedNodeKind(context, imported_loc_id, - InstT::Kind); - } - return SemIR::LocIdAndInst::UncheckedLoc(imported_loc_id, inst); -} - } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_IMPORT_REF_H_ diff --git a/toolchain/check/testdata/interop/cpp/class/class.carbon b/toolchain/check/testdata/interop/cpp/class/class.carbon index 174c585858a4..92fdf49964c6 100644 --- a/toolchain/check/testdata/interop/cpp/class/class.carbon +++ b/toolchain/check/testdata/interop/cpp/class/class.carbon @@ -18,23 +18,32 @@ class Bar; -// --- fail_todo_import_declaration.carbon +// --- import_declaration.carbon library "[[@TEST_NAME]]"; import Cpp library "declaration.h"; //@dump-sem-ir-begin -// CHECK:STDERR: fail_todo_import_declaration.carbon:[[@LINE+7]]:13: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fail_todo_import_declaration.carbon:[[@LINE+4]]:13: note: in `Cpp` name lookup for `Bar` [InCppNameLookup] -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); //@dump-sem-ir-end +// --- fail_use_declaration_as_definition.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "declaration.h"; + +fn MyF() { + // CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+6]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl] + // CHECK:STDERR: var bar: Cpp.Bar; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./declaration.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: + var bar: Cpp.Bar; +} + // ============================================================================ // Definition // ============================================================================ @@ -158,28 +167,17 @@ fn MyF() { class Bar { public: - Bar* foo; + Bar* _Nonnull foo; }; -// --- fail_todo_import_public_data_member.carbon +// --- import_public_data_member.carbon library "[[@TEST_NAME]]"; -import Cpp library "public_static_data_member.h"; +import Cpp library "public_data_member.h"; //@dump-sem-ir-begin fn MyF(bar : Cpp.Bar*) { - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+11]]:27: error: semantics TODO: `Unsupported: Declaration type Var` [SemanticsTodo] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+8]]:27: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+4]]:27: error: member name `foo` not found in `Cpp.Bar` [MemberNameNotFoundInInstScope] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; } //@dump-sem-ir-end @@ -230,7 +228,7 @@ library "[[@TEST_NAME]]"; import Cpp library "inheritance_pointers.h"; //@dump-sem-ir-begin -fn MyF1(bar : Cpp.Bar1*); +fn MyF1(bar: Cpp.Bar1*); // TODO: Support C++ inheritance. // CHECK:STDERR: fail_todo_import_inheritance_pointers.carbon:[[@LINE+10]]:33: error: cannot implicitly convert expression of type `Cpp.Bar2*` to `Cpp.Bar1*` [ConversionFailure] // CHECK:STDERR: fn MyF2(bar : Cpp.Bar2*) { MyF1(bar); } @@ -239,8 +237,8 @@ fn MyF1(bar : Cpp.Bar1*); // CHECK:STDERR: fn MyF2(bar : Cpp.Bar2*) { MyF1(bar); } // CHECK:STDERR: ^~~ // CHECK:STDERR: fail_todo_import_inheritance_pointers.carbon:[[@LINE-8]]:9: note: initializing function parameter [InCallToFunctionParam] -// CHECK:STDERR: fn MyF1(bar : Cpp.Bar1*); -// CHECK:STDERR: ^~~~~~~~~~~~~~~ +// CHECK:STDERR: fn MyF1(bar: Cpp.Bar1*); +// CHECK:STDERR: ^~~~~~~~~~~~~~ // CHECK:STDERR: fn MyF2(bar : Cpp.Bar2*) { MyF1(bar); } //@dump-sem-ir-end @@ -256,21 +254,14 @@ class Bar { virtual ~Bar(); }; -// --- fail_todo_import_dynamic.carbon +// --- import_dynamic.carbon library "[[@TEST_NAME]]"; import Cpp library "dynamic.h"; //@dump-sem-ir-begin -// CHECK:STDERR: fail_todo_import_dynamic.carbon:[[@LINE+7]]:14: error: semantics TODO: `Unsupported: Dynamic Class` [SemanticsTodo] -// CHECK:STDERR: fn MyF(bar : Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fail_todo_import_dynamic.carbon:[[@LINE+4]]:14: note: in `Cpp` name lookup for `Bar` [InCppNameLookup] -// CHECK:STDERR: fn MyF(bar : Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: -fn MyF(bar : Cpp.Bar*); +fn MyF(bar: Cpp.Bar*); //@dump-sem-ir-end // ============================================================================ @@ -355,36 +346,40 @@ import Cpp library "template.h"; fn MyF(bar: Cpp.Bar*); //@dump-sem-ir-end -// CHECK:STDOUT: --- fail_todo_import_declaration.carbon +// CHECK:STDOUT: --- import_declaration.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %pattern_type: type = pattern_type %ptr [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .Bar = +// CHECK:STDOUT: .Bar = %Bar.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %Bar.decl: type = class_decl @Bar [concrete = constants.%Bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] { -// CHECK:STDOUT: %bar.patt: = binding_pattern bar [concrete] -// CHECK:STDOUT: %bar.param_patt: = value_param_pattern %bar.patt, call_param0 [concrete] +// CHECK:STDOUT: %bar.patt: %pattern_type = binding_pattern bar [concrete] +// CHECK:STDOUT: %bar.param_patt: %pattern_type = value_param_pattern %bar.patt, call_param0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %bar.param: = value_param call_param0 -// CHECK:STDOUT: %.loc14: type = splice_block %ptr [concrete = ] { +// CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 +// CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref: = name_ref Bar, [concrete = ] -// CHECK:STDOUT: %ptr: type = ptr_type [concrete = ] +// CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } -// CHECK:STDOUT: %bar: = bind_name bar, %bar.param +// CHECK:STDOUT: %bar: %ptr = bind_name bar, %bar.param // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @MyF(%bar.param: ); +// CHECK:STDOUT: fn @MyF(%bar.param: %ptr); // CHECK:STDOUT: // CHECK:STDOUT: --- import_definition.carbon // CHECK:STDOUT: @@ -412,7 +407,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } @@ -448,7 +442,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } @@ -479,7 +472,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: fn @MyF() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %foo.ref: %Bar.foo.type = name_ref foo, imports.%Bar.foo.decl [concrete = constants.%Bar.foo] // CHECK:STDOUT: %Bar.foo.call: init %empty_tuple.type = call %foo.ref() @@ -512,7 +504,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] // CHECK:STDOUT: %.loc19: type = splice_block %ptr [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref.loc19_12: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref.loc19_15: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref.loc19_15 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -520,11 +511,12 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_public_data_member.carbon +// CHECK:STDOUT: --- import_public_data_member.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] // CHECK:STDOUT: %ptr.f68: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %Bar.elem: type = unbound_element_type %Bar, %ptr.f68 [concrete] // CHECK:STDOUT: %pattern_type: type = pattern_type %ptr.f68 [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] @@ -546,7 +538,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr.f68 = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr.loc7 [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref.loc7: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref.loc7: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr.loc7: type = ptr_type %Bar.ref.loc7 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -560,14 +551,16 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %foo_bar.patt: %pattern_type = binding_pattern foo_bar [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: %bar.ref: %ptr.f68 = name_ref bar, %bar -// CHECK:STDOUT: %.loc19_30: ref %Bar = deref %bar.ref -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %.loc19_23: type = splice_block %ptr.loc19 [concrete = constants.%ptr.f68] { -// CHECK:STDOUT: %Cpp.ref.loc19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref.loc19: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] -// CHECK:STDOUT: %ptr.loc19: type = ptr_type %Bar.ref.loc19 [concrete = constants.%ptr.f68] +// CHECK:STDOUT: %.loc8_30.1: ref %Bar = deref %bar.ref +// CHECK:STDOUT: %foo.ref: %Bar.elem = name_ref foo, @Bar.%.1 [concrete = @Bar.%.1] +// CHECK:STDOUT: %.loc8_30.2: ref %ptr.f68 = class_element_access %.loc8_30.1, element0 +// CHECK:STDOUT: %.loc8_23: type = splice_block %ptr.loc8 [concrete = constants.%ptr.f68] { +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Bar.ref.loc8: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr.loc8: type = ptr_type %Bar.ref.loc8 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } -// CHECK:STDOUT: %foo_bar: %ptr.f68 = bind_name foo_bar, [concrete = ] +// CHECK:STDOUT: %.loc8_30.3: %ptr.f68 = bind_value %.loc8_30.2 +// CHECK:STDOUT: %foo_bar: %ptr.f68 = bind_name foo_bar, %.loc8_30.3 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -598,12 +591,10 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: fn @MyF() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar1.ref: type = name_ref Bar1, imports.%Bar1.decl [concrete = constants.%Bar1] // CHECK:STDOUT: %foo1.ref.loc8: %Bar1.foo1.type = name_ref foo1, imports.%Bar1.foo1.decl [concrete = constants.%Bar1.foo1] // CHECK:STDOUT: %Bar1.foo1.call.loc8: init %empty_tuple.type = call %foo1.ref.loc8() // CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar2.ref.loc9: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] // CHECK:STDOUT: %foo1.ref.loc9: %Bar1.foo1.type = name_ref foo1, imports.%Bar1.foo1.decl [concrete = constants.%Bar1.foo1] // CHECK:STDOUT: %Bar1.foo1.call.loc9: init %empty_tuple.type = call %foo1.ref.loc9() @@ -648,7 +639,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr.f68 = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar1.ref: type = name_ref Bar1, imports.%Bar1.decl [concrete = constants.%Bar1] // CHECK:STDOUT: %ptr: type = ptr_type %Bar1.ref [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -661,7 +651,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr.eca = value_param call_param0 // CHECK:STDOUT: %.loc19_23: type = splice_block %ptr [concrete = constants.%ptr.eca] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar2.ref: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] // CHECK:STDOUT: %ptr: type = ptr_type %Bar2.ref [concrete = constants.%ptr.eca] // CHECK:STDOUT: } @@ -680,36 +669,40 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_dynamic.carbon +// CHECK:STDOUT: --- import_dynamic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %pattern_type: type = pattern_type %ptr [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .Bar = +// CHECK:STDOUT: .Bar = %Bar.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %Bar.decl: type = class_decl @Bar [concrete = constants.%Bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] { -// CHECK:STDOUT: %bar.patt: = binding_pattern bar [concrete] -// CHECK:STDOUT: %bar.param_patt: = value_param_pattern %bar.patt, call_param0 [concrete] +// CHECK:STDOUT: %bar.patt: %pattern_type = binding_pattern bar [concrete] +// CHECK:STDOUT: %bar.param_patt: %pattern_type = value_param_pattern %bar.patt, call_param0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %bar.param: = value_param call_param0 -// CHECK:STDOUT: %.loc14: type = splice_block %ptr [concrete = ] { +// CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 +// CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref: = name_ref Bar, [concrete = ] -// CHECK:STDOUT: %ptr: type = ptr_type [concrete = ] +// CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } -// CHECK:STDOUT: %bar: = bind_name bar, %bar.param +// CHECK:STDOUT: %bar: %ptr = bind_name bar, %bar.param // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @MyF(%bar.param: ); +// CHECK:STDOUT: fn @MyF(%bar.param: %ptr); // CHECK:STDOUT: // CHECK:STDOUT: --- import_to_inherit_public.carbon // CHECK:STDOUT: @@ -742,12 +735,11 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: // CHECK:STDOUT: class @Derived { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %.loc8: %Derived.elem = base_decl %Bar.ref, element0 [concrete] // CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %Bar} [concrete = constants.%struct_type.base.36d] -// CHECK:STDOUT: %complete_type.loc9: = complete_type_witness %struct_type.base [concrete = constants.%complete_type.fff] -// CHECK:STDOUT: complete_type_witness = %complete_type.loc9 +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.base [concrete = constants.%complete_type.fff] +// CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%Derived diff --git a/toolchain/check/testdata/interop/cpp/class/field.carbon b/toolchain/check/testdata/interop/cpp/class/field.carbon new file mode 100644 index 000000000000..473436a1d6f4 --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/class/field.carbon @@ -0,0 +1,670 @@ +// 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-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon +// EXTRA-ARGS: --dump-sem-ir-ranges=ignore +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/field.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/field.carbon + +// --- struct.h + +struct Struct { + int a; + int b; + int* _Nonnull p; +}; + +// --- use_struct_fields.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "struct.h"; + +fn F(s: Cpp.Struct) -> (i32, i32, i32) { + //@dump-sem-ir-begin + return (s.a, s.b, *s.p); + //@dump-sem-ir-end +} + +// --- union.h + +union Union { + int a; + int b; + int* _Nonnull p; +}; + +// --- use_union_fields.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "union.h"; + +fn F(u: Cpp.Union) -> i32 { + //@dump-sem-ir-begin + return u.a; + //@dump-sem-ir-end +} + +fn G(u: Cpp.Union) -> i32 { + //@dump-sem-ir-begin + return u.b; + //@dump-sem-ir-end +} + +fn H(u: Cpp.Union) -> i32 { + //@dump-sem-ir-begin + return *u.p; + //@dump-sem-ir-end +} + +// --- with_bitfields.h + +struct Struct { + int a; + int b : 2; +}; + +union Union { + int c; + int d : 3; +}; + +// --- use_non_bitfields_in_type_with_bitfields.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "with_bitfields.h"; + +fn F(s: Cpp.Struct) -> i32 { + //@dump-sem-ir-begin + return s.a; + //@dump-sem-ir-end +} + +fn G(s: Cpp.Union) -> i32 { + //@dump-sem-ir-begin + return s.c; + //@dump-sem-ir-end +} + +// --- fail_todo_use_bitfields.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "with_bitfields.h"; + +fn F(s: Cpp.Struct) -> i32 { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_use_bitfields.carbon:[[@LINE+11]]:10: error: semantics TODO: `Unsupported: Unhandled kind of field declaration` [SemanticsTodo] + // CHECK:STDERR: return s.b; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: fail_todo_use_bitfields.carbon:[[@LINE+8]]:10: note: in `Cpp` name lookup for `b` [InCppNameLookup] + // CHECK:STDERR: return s.b; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_use_bitfields.carbon:[[@LINE+4]]:10: error: member name `b` not found in `Cpp.Struct` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: return s.b; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + return s.b; + //@dump-sem-ir-end +} + +fn G(s: Cpp.Union) -> i32 { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_use_bitfields.carbon:[[@LINE+11]]:10: error: semantics TODO: `Unsupported: Unhandled kind of field declaration` [SemanticsTodo] + // CHECK:STDERR: return s.d; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: fail_todo_use_bitfields.carbon:[[@LINE+8]]:10: note: in `Cpp` name lookup for `d` [InCppNameLookup] + // CHECK:STDERR: return s.d; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_use_bitfields.carbon:[[@LINE+4]]:10: error: member name `d` not found in `Cpp.Union` [MemberNameNotFoundInInstScope] + // CHECK:STDERR: return s.d; + // CHECK:STDERR: ^~~ + // CHECK:STDERR: + return s.d; + //@dump-sem-ir-end +} + +// CHECK:STDOUT: --- use_struct_fields.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Struct: type = class_type @Struct [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete] +// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %Struct.elem.86b: type = unbound_element_type %Struct, %i32 [concrete] +// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete] +// CHECK:STDOUT: %Struct.elem.765: type = unbound_element_type %Struct, %ptr.235 [concrete] +// CHECK:STDOUT: %.550: type = custom_layout_type {size=16, align=8, .a@0: %i32, .b@4: %i32, .p@8: %ptr.235} [concrete] +// CHECK:STDOUT: %complete_type.8cf: = complete_type_witness %.550 [concrete] +// CHECK:STDOUT: %pattern_type.60c: type = pattern_type %Struct [concrete] +// CHECK:STDOUT: %tuple.type.ff9: type = tuple_type (type, type, type) [concrete] +// CHECK:STDOUT: %tuple.type.189: type = tuple_type (%i32, %i32, %i32) [concrete] +// CHECK:STDOUT: %pattern_type.b5a: type = pattern_type %tuple.type.189 [concrete] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Int = %Core.Int +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .Struct = %Struct.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Struct.decl: type = class_decl @Struct [concrete = constants.%Struct] {} {} +// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "struct.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { +// CHECK:STDOUT: %s.patt: %pattern_type.60c = binding_pattern s [concrete] +// CHECK:STDOUT: %s.param_patt: %pattern_type.60c = value_param_pattern %s.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.b5a = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.b5a = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32.loc6_25: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc6_25: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %int_32.loc6_30: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc6_30: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %int_32.loc6_35: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.loc6_35: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.loc6_38.1: %tuple.type.ff9 = tuple_literal (%i32.loc6_25, %i32.loc6_30, %i32.loc6_35) +// CHECK:STDOUT: %.loc6_38.2: type = converted %.loc6_38.1, constants.%tuple.type.189 [concrete = constants.%tuple.type.189] +// CHECK:STDOUT: %s.param: %Struct = value_param call_param0 +// CHECK:STDOUT: %.loc6_12: type = splice_block %Struct.ref [concrete = constants.%Struct] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Struct.ref: type = name_ref Struct, imports.%Struct.decl [concrete = constants.%Struct] +// CHECK:STDOUT: } +// CHECK:STDOUT: %s: %Struct = bind_name s, %s.param +// CHECK:STDOUT: %return.param: ref %tuple.type.189 = out_param call_param1 +// CHECK:STDOUT: %return: ref %tuple.type.189 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Struct { +// CHECK:STDOUT: %int_32.1: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.1: %Struct.elem.86b = field_decl a, element0 [concrete] +// CHECK:STDOUT: %int_32.2: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.2: %Struct.elem.86b = field_decl b, element1 [concrete] +// CHECK:STDOUT: %int_32.3: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.3: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.3: %Struct.elem.765 = field_decl p, element2 [concrete] +// CHECK:STDOUT: %.4: type = custom_layout_type {size=16, align=8, .a@0: %i32, .b@4: %i32, .p@8: %ptr.235} [concrete = constants.%.550] +// CHECK:STDOUT: %complete_type: = complete_type_witness %.4 [concrete = constants.%complete_type.8cf] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Struct +// CHECK:STDOUT: .a = %.1 +// CHECK:STDOUT: .b = %.2 +// CHECK:STDOUT: .p = %.3 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%s.param: %Struct) -> %return.param: %tuple.type.189 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %s.ref.loc8_11: %Struct = name_ref s, %s +// CHECK:STDOUT: %a.ref: %Struct.elem.86b = name_ref a, @Struct.%.1 [concrete = @Struct.%.1] +// CHECK:STDOUT: %.loc8_12.1: ref %i32 = class_element_access %s.ref.loc8_11, element0 +// CHECK:STDOUT: %.loc8_12.2: %i32 = bind_value %.loc8_12.1 +// CHECK:STDOUT: %s.ref.loc8_16: %Struct = name_ref s, %s +// CHECK:STDOUT: %b.ref: %Struct.elem.86b = name_ref b, @Struct.%.2 [concrete = @Struct.%.2] +// CHECK:STDOUT: %.loc8_17.1: ref %i32 = class_element_access %s.ref.loc8_16, element1 +// CHECK:STDOUT: %.loc8_17.2: %i32 = bind_value %.loc8_17.1 +// CHECK:STDOUT: %s.ref.loc8_22: %Struct = name_ref s, %s +// CHECK:STDOUT: %p.ref: %Struct.elem.765 = name_ref p, @Struct.%.3 [concrete = @Struct.%.3] +// CHECK:STDOUT: %.loc8_23.1: ref %ptr.235 = class_element_access %s.ref.loc8_22, element2 +// CHECK:STDOUT: %.loc8_23.2: %ptr.235 = bind_value %.loc8_23.1 +// CHECK:STDOUT: %.loc8_21.1: ref %i32 = deref %.loc8_23.2 +// CHECK:STDOUT: %.loc8_25.1: %tuple.type.189 = tuple_literal (%.loc8_12.2, %.loc8_17.2, %.loc8_21.1) +// CHECK:STDOUT: %tuple.elem0: ref %i32 = tuple_access %return, element0 +// CHECK:STDOUT: %.loc8_25.2: init %i32 = initialize_from %.loc8_12.2 to %tuple.elem0 +// CHECK:STDOUT: %tuple.elem1: ref %i32 = tuple_access %return, element1 +// CHECK:STDOUT: %.loc8_25.3: init %i32 = initialize_from %.loc8_17.2 to %tuple.elem1 +// CHECK:STDOUT: %.loc8_21.2: %i32 = bind_value %.loc8_21.1 +// CHECK:STDOUT: %tuple.elem2: ref %i32 = tuple_access %return, element2 +// CHECK:STDOUT: %.loc8_25.4: init %i32 = initialize_from %.loc8_21.2 to %tuple.elem2 +// CHECK:STDOUT: %.loc8_25.5: init %tuple.type.189 = tuple_init (%.loc8_25.2, %.loc8_25.3, %.loc8_25.4) to %return +// CHECK:STDOUT: %.loc8_26: init %tuple.type.189 = converted %.loc8_25.1, %.loc8_25.5 +// CHECK:STDOUT: return %.loc8_26 to %return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- use_union_fields.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Union: type = class_type @Union [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete] +// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %Union.elem.041: type = unbound_element_type %Union, %i32 [concrete] +// CHECK:STDOUT: %ptr.235: type = ptr_type %i32 [concrete] +// CHECK:STDOUT: %Union.elem.92a: type = unbound_element_type %Union, %ptr.235 [concrete] +// CHECK:STDOUT: %.c84: type = custom_layout_type {size=8, align=8, .a@0: %i32, .b@0: %i32, .p@0: %ptr.235} [concrete] +// CHECK:STDOUT: %complete_type.1b0: = complete_type_witness %.c84 [concrete] +// CHECK:STDOUT: %pattern_type.a90: type = pattern_type %Union [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %G.type: type = fn_type @G [concrete] +// CHECK:STDOUT: %G: %G.type = struct_value () [concrete] +// CHECK:STDOUT: %H.type: type = fn_type @H [concrete] +// CHECK:STDOUT: %H: %H.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Int = %Core.Int +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .Union = %Union.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Union.decl: type = class_decl @Union [concrete = constants.%Union] {} {} +// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .G = %G.decl +// CHECK:STDOUT: .H = %H.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "union.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { +// CHECK:STDOUT: %u.patt: %pattern_type.a90 = binding_pattern u [concrete] +// CHECK:STDOUT: %u.param_patt: %pattern_type.a90 = value_param_pattern %u.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %u.param: %Union = value_param call_param0 +// CHECK:STDOUT: %.loc6: type = splice_block %Union.ref [concrete = constants.%Union] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Union.ref: type = name_ref Union, imports.%Union.decl [concrete = constants.%Union] +// CHECK:STDOUT: } +// CHECK:STDOUT: %u: %Union = bind_name u, %u.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] { +// CHECK:STDOUT: %u.patt: %pattern_type.a90 = binding_pattern u [concrete] +// CHECK:STDOUT: %u.param_patt: %pattern_type.a90 = value_param_pattern %u.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %u.param: %Union = value_param call_param0 +// CHECK:STDOUT: %.loc12: type = splice_block %Union.ref [concrete = constants.%Union] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Union.ref: type = name_ref Union, imports.%Union.decl [concrete = constants.%Union] +// CHECK:STDOUT: } +// CHECK:STDOUT: %u: %Union = bind_name u, %u.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %H.decl: %H.type = fn_decl @H [concrete = constants.%H] { +// CHECK:STDOUT: %u.patt: %pattern_type.a90 = binding_pattern u [concrete] +// CHECK:STDOUT: %u.param_patt: %pattern_type.a90 = value_param_pattern %u.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %u.param: %Union = value_param call_param0 +// CHECK:STDOUT: %.loc18: type = splice_block %Union.ref [concrete = constants.%Union] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Union.ref: type = name_ref Union, imports.%Union.decl [concrete = constants.%Union] +// CHECK:STDOUT: } +// CHECK:STDOUT: %u: %Union = bind_name u, %u.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Union { +// CHECK:STDOUT: %int_32.1: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.1: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.1: %Union.elem.041 = field_decl a, element0 [concrete] +// CHECK:STDOUT: %int_32.2: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.2: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.2: %Union.elem.041 = field_decl b, element1 [concrete] +// CHECK:STDOUT: %int_32.3: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32.3: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.3: %Union.elem.92a = field_decl p, element2 [concrete] +// CHECK:STDOUT: %.4: type = custom_layout_type {size=8, align=8, .a@0: %i32, .b@0: %i32, .p@0: %ptr.235} [concrete = constants.%.c84] +// CHECK:STDOUT: %complete_type: = complete_type_witness %.4 [concrete = constants.%complete_type.1b0] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Union +// CHECK:STDOUT: .a = %.1 +// CHECK:STDOUT: .b = %.2 +// CHECK:STDOUT: .p = %.3 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%u.param: %Union) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %u.ref: %Union = name_ref u, %u +// CHECK:STDOUT: %a.ref: %Union.elem.041 = name_ref a, @Union.%.1 [concrete = @Union.%.1] +// CHECK:STDOUT: %.loc8_11.1: ref %i32 = class_element_access %u.ref, element0 +// CHECK:STDOUT: %.loc8_11.2: %i32 = bind_value %.loc8_11.1 +// CHECK:STDOUT: return %.loc8_11.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G(%u.param: %Union) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %u.ref: %Union = name_ref u, %u +// CHECK:STDOUT: %b.ref: %Union.elem.041 = name_ref b, @Union.%.2 [concrete = @Union.%.2] +// CHECK:STDOUT: %.loc14_11.1: ref %i32 = class_element_access %u.ref, element1 +// CHECK:STDOUT: %.loc14_11.2: %i32 = bind_value %.loc14_11.1 +// CHECK:STDOUT: return %.loc14_11.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @H(%u.param: %Union) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %u.ref: %Union = name_ref u, %u +// CHECK:STDOUT: %p.ref: %Union.elem.92a = name_ref p, @Union.%.3 [concrete = @Union.%.3] +// CHECK:STDOUT: %.loc20_12.1: ref %ptr.235 = class_element_access %u.ref, element2 +// CHECK:STDOUT: %.loc20_12.2: %ptr.235 = bind_value %.loc20_12.1 +// CHECK:STDOUT: %.loc20_10.1: ref %i32 = deref %.loc20_12.2 +// CHECK:STDOUT: %.loc20_10.2: %i32 = bind_value %.loc20_10.1 +// CHECK:STDOUT: return %.loc20_10.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- use_non_bitfields_in_type_with_bitfields.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Struct: type = class_type @Struct [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete] +// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %Struct.elem: type = unbound_element_type %Struct, %i32 [concrete] +// CHECK:STDOUT: %.f9e: type = custom_layout_type {size=8, align=4, .a@0: %i32} [concrete] +// CHECK:STDOUT: %complete_type.d3c: = complete_type_witness %.f9e [concrete] +// CHECK:STDOUT: %pattern_type.60c: type = pattern_type %Struct [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %Union: type = class_type @Union [concrete] +// CHECK:STDOUT: %Union.elem: type = unbound_element_type %Union, %i32 [concrete] +// CHECK:STDOUT: %.891: type = custom_layout_type {size=4, align=4, .c@0: %i32} [concrete] +// CHECK:STDOUT: %complete_type.591: = complete_type_witness %.891 [concrete] +// CHECK:STDOUT: %pattern_type.a90: type = pattern_type %Union [concrete] +// CHECK:STDOUT: %G.type: type = fn_type @G [concrete] +// CHECK:STDOUT: %G: %G.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Int = %Core.Int +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .Struct = %Struct.decl +// CHECK:STDOUT: .Union = %Union.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Struct.decl: type = class_decl @Struct [concrete = constants.%Struct] {} {} +// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic] +// CHECK:STDOUT: %Union.decl: type = class_decl @Union [concrete = constants.%Union] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .G = %G.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "with_bitfields.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { +// CHECK:STDOUT: %s.patt: %pattern_type.60c = binding_pattern s [concrete] +// CHECK:STDOUT: %s.param_patt: %pattern_type.60c = value_param_pattern %s.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %s.param: %Struct = value_param call_param0 +// CHECK:STDOUT: %.loc6: type = splice_block %Struct.ref [concrete = constants.%Struct] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Struct.ref: type = name_ref Struct, imports.%Struct.decl [concrete = constants.%Struct] +// CHECK:STDOUT: } +// CHECK:STDOUT: %s: %Struct = bind_name s, %s.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] { +// CHECK:STDOUT: %s.patt: %pattern_type.a90 = binding_pattern s [concrete] +// CHECK:STDOUT: %s.param_patt: %pattern_type.a90 = value_param_pattern %s.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %s.param: %Union = value_param call_param0 +// CHECK:STDOUT: %.loc12: type = splice_block %Union.ref [concrete = constants.%Union] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Union.ref: type = name_ref Union, imports.%Union.decl [concrete = constants.%Union] +// CHECK:STDOUT: } +// CHECK:STDOUT: %s: %Union = bind_name s, %s.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Struct { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.1: %Struct.elem = field_decl a, element0 [concrete] +// CHECK:STDOUT: %.2: type = custom_layout_type {size=8, align=4, .a@0: %i32} [concrete = constants.%.f9e] +// CHECK:STDOUT: %complete_type: = complete_type_witness %.2 [concrete = constants.%complete_type.d3c] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Struct +// CHECK:STDOUT: .a = %.1 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Union { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.1: %Union.elem = field_decl c, element0 [concrete] +// CHECK:STDOUT: %.2: type = custom_layout_type {size=4, align=4, .c@0: %i32} [concrete = constants.%.891] +// CHECK:STDOUT: %complete_type: = complete_type_witness %.2 [concrete = constants.%complete_type.591] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Union +// CHECK:STDOUT: .c = %.1 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%s.param: %Struct) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %s.ref: %Struct = name_ref s, %s +// CHECK:STDOUT: %a.ref: %Struct.elem = name_ref a, @Struct.%.1 [concrete = @Struct.%.1] +// CHECK:STDOUT: %.loc8_11.1: ref %i32 = class_element_access %s.ref, element0 +// CHECK:STDOUT: %.loc8_11.2: %i32 = bind_value %.loc8_11.1 +// CHECK:STDOUT: return %.loc8_11.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G(%s.param: %Union) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %s.ref: %Union = name_ref s, %s +// CHECK:STDOUT: %c.ref: %Union.elem = name_ref c, @Union.%.1 [concrete = @Union.%.1] +// CHECK:STDOUT: %.loc14_11.1: ref %i32 = class_element_access %s.ref, element0 +// CHECK:STDOUT: %.loc14_11.2: %i32 = bind_value %.loc14_11.1 +// CHECK:STDOUT: return %.loc14_11.2 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_use_bitfields.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Struct: type = class_type @Struct [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %Int.type: type = generic_class_type @Int [concrete] +// CHECK:STDOUT: %Int.generic: %Int.type = struct_value () [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %Struct.elem: type = unbound_element_type %Struct, %i32 [concrete] +// CHECK:STDOUT: %.f9e: type = custom_layout_type {size=8, align=4, .a@0: %i32} [concrete] +// CHECK:STDOUT: %complete_type.d3c: = complete_type_witness %.f9e [concrete] +// CHECK:STDOUT: %pattern_type.60c: type = pattern_type %Struct [concrete] +// CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %Union: type = class_type @Union [concrete] +// CHECK:STDOUT: %Union.elem: type = unbound_element_type %Union, %i32 [concrete] +// CHECK:STDOUT: %.891: type = custom_layout_type {size=4, align=4, .c@0: %i32} [concrete] +// CHECK:STDOUT: %complete_type.591: = complete_type_witness %.891 [concrete] +// CHECK:STDOUT: %pattern_type.a90: type = pattern_type %Union [concrete] +// CHECK:STDOUT: %G.type: type = fn_type @G [concrete] +// CHECK:STDOUT: %G: %G.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { +// CHECK:STDOUT: .Int = %Core.Int +// CHECK:STDOUT: import Core//prelude +// CHECK:STDOUT: import Core//prelude/... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .Struct = %Struct.decl +// CHECK:STDOUT: .Union = %Union.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Struct.decl: type = class_decl @Struct [concrete = constants.%Struct] {} {} +// CHECK:STDOUT: %Core.Int: %Int.type = import_ref Core//prelude/parts/int, Int, loaded [concrete = constants.%Int.generic] +// CHECK:STDOUT: %Union.decl: type = class_decl @Union [concrete = constants.%Union] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: package: = namespace [concrete] { +// CHECK:STDOUT: .Core = imports.%Core +// CHECK:STDOUT: .Cpp = imports.%Cpp +// CHECK:STDOUT: .F = %F.decl +// CHECK:STDOUT: .G = %G.decl +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import = import Core +// CHECK:STDOUT: %Cpp.import_cpp = import_cpp { +// CHECK:STDOUT: import Cpp "with_bitfields.h" +// CHECK:STDOUT: } +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { +// CHECK:STDOUT: %s.patt: %pattern_type.60c = binding_pattern s [concrete] +// CHECK:STDOUT: %s.param_patt: %pattern_type.60c = value_param_pattern %s.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %s.param: %Struct = value_param call_param0 +// CHECK:STDOUT: %.loc6: type = splice_block %Struct.ref [concrete = constants.%Struct] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Struct.ref: type = name_ref Struct, imports.%Struct.decl [concrete = constants.%Struct] +// CHECK:STDOUT: } +// CHECK:STDOUT: %s: %Struct = bind_name s, %s.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %G.decl: %G.type = fn_decl @G [concrete = constants.%G] { +// CHECK:STDOUT: %s.patt: %pattern_type.a90 = binding_pattern s [concrete] +// CHECK:STDOUT: %s.param_patt: %pattern_type.a90 = value_param_pattern %s.patt, call_param0 [concrete] +// CHECK:STDOUT: %return.patt: %pattern_type.7ce = return_slot_pattern [concrete] +// CHECK:STDOUT: %return.param_patt: %pattern_type.7ce = out_param_pattern %return.patt, call_param1 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %s.param: %Union = value_param call_param0 +// CHECK:STDOUT: %.loc23: type = splice_block %Union.ref [concrete = constants.%Union] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Union.ref: type = name_ref Union, imports.%Union.decl [concrete = constants.%Union] +// CHECK:STDOUT: } +// CHECK:STDOUT: %s: %Union = bind_name s, %s.param +// CHECK:STDOUT: %return.param: ref %i32 = out_param call_param1 +// CHECK:STDOUT: %return: ref %i32 = return_slot %return.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Struct { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.1: %Struct.elem = field_decl a, element0 [concrete] +// CHECK:STDOUT: %.2: type = custom_layout_type {size=8, align=4, .a@0: %i32} [concrete = constants.%.f9e] +// CHECK:STDOUT: %complete_type: = complete_type_witness %.2 [concrete = constants.%complete_type.d3c] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Struct +// CHECK:STDOUT: .b = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @Union { +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(constants.%int_32) [concrete = constants.%i32] +// CHECK:STDOUT: %.1: %Union.elem = field_decl c, element0 [concrete] +// CHECK:STDOUT: %.2: type = custom_layout_type {size=4, align=4, .c@0: %i32} [concrete = constants.%.891] +// CHECK:STDOUT: %complete_type: = complete_type_witness %.2 [concrete = constants.%complete_type.591] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%Union +// CHECK:STDOUT: .d = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F(%s.param: %Struct) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %s.ref: %Struct = name_ref s, %s +// CHECK:STDOUT: %b.ref: = name_ref b, [concrete = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G(%s.param: %Union) -> %i32 { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %s.ref: %Union = name_ref s, %s +// CHECK:STDOUT: %d.ref: = name_ref d, [concrete = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/class/method.carbon b/toolchain/check/testdata/interop/cpp/class/method.carbon index 2a4e3ed63dbd..baa47b65879a 100644 --- a/toolchain/check/testdata/interop/cpp/class/method.carbon +++ b/toolchain/check/testdata/interop/cpp/class/method.carbon @@ -226,8 +226,6 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: %v.param: %HasQualifiers = value_param call_param0 // CHECK:STDOUT: %.loc6_12: type = splice_block %HasQualifiers.ref.loc6_12 [concrete = constants.%HasQualifiers] { // CHECK:STDOUT: %Cpp.ref.loc6_9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] -// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] // CHECK:STDOUT: %HasQualifiers.ref.loc6_12: type = name_ref HasQualifiers, imports.%HasQualifiers.decl [concrete = constants.%HasQualifiers] // CHECK:STDOUT: } // CHECK:STDOUT: %v: %HasQualifiers = bind_name v, %v.param @@ -242,7 +240,9 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @HasQualifiers { -// CHECK:STDOUT: complete_type_witness = @F.%complete_type +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%HasQualifiers @@ -378,8 +378,6 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: %v.param: %HasQualifiers = value_param call_param0 // CHECK:STDOUT: %.loc6: type = splice_block %HasQualifiers.ref [concrete = constants.%HasQualifiers] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] -// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type.357] // CHECK:STDOUT: %HasQualifiers.ref: type = name_ref HasQualifiers, imports.%HasQualifiers.decl [concrete = constants.%HasQualifiers] // CHECK:STDOUT: } // CHECK:STDOUT: %v: %HasQualifiers = bind_name v, %v.param @@ -387,7 +385,9 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @HasQualifiers { -// CHECK:STDOUT: complete_type_witness = @Value.%complete_type +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type.357] +// CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%HasQualifiers @@ -500,8 +500,6 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: %p.param: %ptr.ec3 = value_param call_param0 // CHECK:STDOUT: %.loc6: type = splice_block %ptr [concrete = constants.%ptr.ec3] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] -// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] // CHECK:STDOUT: %HasQualifiers.ref: type = name_ref HasQualifiers, imports.%HasQualifiers.decl [concrete = constants.%HasQualifiers] // CHECK:STDOUT: %ptr: type = ptr_type %HasQualifiers.ref [concrete = constants.%ptr.ec3] // CHECK:STDOUT: } @@ -510,7 +508,9 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @HasQualifiers { -// CHECK:STDOUT: complete_type_witness = @Ref.%complete_type +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%HasQualifiers @@ -572,8 +572,6 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: %p.param: %ptr.ec3 = value_param call_param0 // CHECK:STDOUT: %.loc6: type = splice_block %ptr [concrete = constants.%ptr.ec3] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] -// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] // CHECK:STDOUT: %HasQualifiers.ref: type = name_ref HasQualifiers, imports.%HasQualifiers.decl [concrete = constants.%HasQualifiers] // CHECK:STDOUT: %ptr: type = ptr_type %HasQualifiers.ref [concrete = constants.%ptr.ec3] // CHECK:STDOUT: } @@ -582,7 +580,9 @@ fn Ref(p: Cpp.HasQualifiers*) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: class @HasQualifiers { -// CHECK:STDOUT: complete_type_witness = @Ref.%complete_type +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete = constants.%empty_struct_type] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%HasQualifiers diff --git a/toolchain/check/testdata/interop/cpp/class/struct.carbon b/toolchain/check/testdata/interop/cpp/class/struct.carbon index 8143dc245e12..bf8053c5a343 100644 --- a/toolchain/check/testdata/interop/cpp/class/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/class/struct.carbon @@ -18,23 +18,32 @@ struct Bar; -// --- fail_todo_import_declaration.carbon +// --- import_declaration.carbon library "[[@TEST_NAME]]"; import Cpp library "declaration.h"; //@dump-sem-ir-begin -// CHECK:STDERR: fail_todo_import_declaration.carbon:[[@LINE+7]]:13: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fail_todo_import_declaration.carbon:[[@LINE+4]]:13: note: in `Cpp` name lookup for `Bar` [InCppNameLookup] -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); //@dump-sem-ir-end +// --- fail_use_declaration_as_definition.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "declaration.h"; + +fn MyF() { + // CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+6]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl] + // CHECK:STDERR: var bar: Cpp.Bar; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./declaration.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: + var bar: Cpp.Bar; +} + // ============================================================================ // Definition // ============================================================================ @@ -112,6 +121,7 @@ library "[[@TEST_NAME]]"; import Cpp library "private_static_member_function.h"; fn MyF() { + // TODO: Should fail because `foo` is inaccessible. Cpp.Bar.foo(); } @@ -122,7 +132,7 @@ fn MyF() { // --- public_static_data_member.h struct Bar { - static Bar* foo; + static Bar* _Nonnull foo; }; // --- fail_todo_import_public_static_data_member.carbon @@ -155,10 +165,10 @@ fn MyF() { // --- public_data_member.h struct Bar { - Bar* foo; + Bar* _Nonnull foo; }; -// --- fail_todo_import_public_data_member.carbon +// --- import_public_data_member.carbon library "[[@TEST_NAME]]"; @@ -166,17 +176,6 @@ import Cpp library "public_data_member.h"; //@dump-sem-ir-begin fn MyF(bar : Cpp.Bar*) { - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+11]]:27: error: semantics TODO: `Unsupported: Declaration type Field` [SemanticsTodo] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+8]]:27: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+4]]:27: error: member name `foo` not found in `Cpp.Bar` [MemberNameNotFoundInInstScope] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; } //@dump-sem-ir-end @@ -225,7 +224,7 @@ library "[[@TEST_NAME]]"; import Cpp library "inheritance_pointers.h"; //@dump-sem-ir-begin -fn MyF1(bar : Cpp.Bar1*); +fn MyF1(bar: Cpp.Bar1*); // TODO: Support C++ inheritance. // CHECK:STDERR: fail_todo_import_inheritance_pointers.carbon:[[@LINE+10]]:33: error: cannot implicitly convert expression of type `Cpp.Bar2*` to `Cpp.Bar1*` [ConversionFailure] // CHECK:STDERR: fn MyF2(bar : Cpp.Bar2*) { MyF1(bar); } @@ -234,8 +233,8 @@ fn MyF1(bar : Cpp.Bar1*); // CHECK:STDERR: fn MyF2(bar : Cpp.Bar2*) { MyF1(bar); } // CHECK:STDERR: ^~~ // CHECK:STDERR: fail_todo_import_inheritance_pointers.carbon:[[@LINE-8]]:9: note: initializing function parameter [InCallToFunctionParam] -// CHECK:STDERR: fn MyF1(bar : Cpp.Bar1*); -// CHECK:STDERR: ^~~~~~~~~~~~~~~ +// CHECK:STDERR: fn MyF1(bar: Cpp.Bar1*); +// CHECK:STDERR: ^~~~~~~~~~~~~~ // CHECK:STDERR: fn MyF2(bar : Cpp.Bar2*) { MyF1(bar); } //@dump-sem-ir-end @@ -247,24 +246,36 @@ fn MyF2(bar : Cpp.Bar2*) { MyF1(bar); } // --- dynamic.h struct Bar { - virtual ~Bar(); + virtual void f(); }; -// --- fail_todo_import_dynamic.carbon +// --- import_dynamic.carbon library "[[@TEST_NAME]]"; import Cpp library "dynamic.h"; //@dump-sem-ir-begin -// CHECK:STDERR: fail_todo_import_dynamic.carbon:[[@LINE+7]]:14: error: semantics TODO: `Unsupported: Dynamic Class` [SemanticsTodo] -// CHECK:STDERR: fn MyF(bar : Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fail_todo_import_dynamic.carbon:[[@LINE+4]]:14: note: in `Cpp` name lookup for `Bar` [InCppNameLookup] -// CHECK:STDERR: fn MyF(bar : Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: -fn MyF(bar : Cpp.Bar*); +fn MyF(bar: Cpp.Bar*); +//@dump-sem-ir-end + +// --- fail_todo_call_dynamic.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "dynamic.h"; + +//@dump-sem-ir-begin +fn MyF(bar: Cpp.Bar*) { + // CHECK:STDERR: fail_todo_call_dynamic.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Virtual function` [SemanticsTodo] + // CHECK:STDERR: bar->f(); + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: fail_todo_call_dynamic.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `f` [InCppNameLookup] + // CHECK:STDERR: bar->f(); + // CHECK:STDERR: ^~~~~~ + // CHECK:STDERR: + bar->f(); +} //@dump-sem-ir-end // ============================================================================ @@ -313,6 +324,7 @@ class Derived { } fn MyF() { + // TODO: Should fail because `foo` is inaccessible. Derived.foo(); } @@ -346,36 +358,40 @@ import Cpp library "template.h"; fn MyF(bar: Cpp.Bar*); //@dump-sem-ir-end -// CHECK:STDOUT: --- fail_todo_import_declaration.carbon +// CHECK:STDOUT: --- import_declaration.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %pattern_type: type = pattern_type %ptr [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .Bar = +// CHECK:STDOUT: .Bar = %Bar.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %Bar.decl: type = class_decl @Bar [concrete = constants.%Bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] { -// CHECK:STDOUT: %bar.patt: = binding_pattern bar [concrete] -// CHECK:STDOUT: %bar.param_patt: = value_param_pattern %bar.patt, call_param0 [concrete] +// CHECK:STDOUT: %bar.patt: %pattern_type = binding_pattern bar [concrete] +// CHECK:STDOUT: %bar.param_patt: %pattern_type = value_param_pattern %bar.patt, call_param0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %bar.param: = value_param call_param0 -// CHECK:STDOUT: %.loc14: type = splice_block %ptr [concrete = ] { +// CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 +// CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref: = name_ref Bar, [concrete = ] -// CHECK:STDOUT: %ptr: type = ptr_type [concrete = ] +// CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } -// CHECK:STDOUT: %bar: = bind_name bar, %bar.param +// CHECK:STDOUT: %bar: %ptr = bind_name bar, %bar.param // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @MyF(%bar.param: ); +// CHECK:STDOUT: fn @MyF(%bar.param: %ptr); // CHECK:STDOUT: // CHECK:STDOUT: --- import_definition.carbon // CHECK:STDOUT: @@ -403,7 +419,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } @@ -439,7 +454,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } @@ -470,7 +484,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: fn @MyF() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %foo.ref: %Bar.foo.type = name_ref foo, imports.%Bar.foo.decl [concrete = constants.%Bar.foo] // CHECK:STDOUT: %Bar.foo.call: init %empty_tuple.type = call %foo.ref() @@ -503,7 +516,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] // CHECK:STDOUT: %.loc19: type = splice_block %ptr [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref.loc19_12: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref.loc19_15: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref.loc19_15 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -511,11 +523,12 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_public_data_member.carbon +// CHECK:STDOUT: --- import_public_data_member.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] // CHECK:STDOUT: %ptr.f68: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %Bar.elem: type = unbound_element_type %Bar, %ptr.f68 [concrete] // CHECK:STDOUT: %pattern_type: type = pattern_type %ptr.f68 [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] @@ -537,7 +550,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr.f68 = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr.loc7 [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref.loc7: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref.loc7: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr.loc7: type = ptr_type %Bar.ref.loc7 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -551,14 +563,16 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %foo_bar.patt: %pattern_type = binding_pattern foo_bar [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: %bar.ref: %ptr.f68 = name_ref bar, %bar -// CHECK:STDOUT: %.loc19_30: ref %Bar = deref %bar.ref -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %.loc19_23: type = splice_block %ptr.loc19 [concrete = constants.%ptr.f68] { -// CHECK:STDOUT: %Cpp.ref.loc19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref.loc19: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] -// CHECK:STDOUT: %ptr.loc19: type = ptr_type %Bar.ref.loc19 [concrete = constants.%ptr.f68] +// CHECK:STDOUT: %.loc8_30.1: ref %Bar = deref %bar.ref +// CHECK:STDOUT: %foo.ref: %Bar.elem = name_ref foo, @Bar.%.1 [concrete = @Bar.%.1] +// CHECK:STDOUT: %.loc8_30.2: ref %ptr.f68 = class_element_access %.loc8_30.1, element0 +// CHECK:STDOUT: %.loc8_23: type = splice_block %ptr.loc8 [concrete = constants.%ptr.f68] { +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Bar.ref.loc8: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr.loc8: type = ptr_type %Bar.ref.loc8 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } -// CHECK:STDOUT: %foo_bar: %ptr.f68 = bind_name foo_bar, [concrete = ] +// CHECK:STDOUT: %.loc8_30.3: %ptr.f68 = bind_value %.loc8_30.2 +// CHECK:STDOUT: %foo_bar: %ptr.f68 = bind_name foo_bar, %.loc8_30.3 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: @@ -589,12 +603,10 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: fn @MyF() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar1.ref: type = name_ref Bar1, imports.%Bar1.decl [concrete = constants.%Bar1] // CHECK:STDOUT: %foo1.ref.loc8: %Bar1.foo1.type = name_ref foo1, imports.%Bar1.foo1.decl [concrete = constants.%Bar1.foo1] // CHECK:STDOUT: %Bar1.foo1.call.loc8: init %empty_tuple.type = call %foo1.ref.loc8() // CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar2.ref.loc9: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] // CHECK:STDOUT: %foo1.ref.loc9: %Bar1.foo1.type = name_ref foo1, imports.%Bar1.foo1.decl [concrete = constants.%Bar1.foo1] // CHECK:STDOUT: %Bar1.foo1.call.loc9: init %empty_tuple.type = call %foo1.ref.loc9() @@ -639,7 +651,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr.f68 = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar1.ref: type = name_ref Bar1, imports.%Bar1.decl [concrete = constants.%Bar1] // CHECK:STDOUT: %ptr: type = ptr_type %Bar1.ref [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -652,7 +663,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr.eca = value_param call_param0 // CHECK:STDOUT: %.loc19_23: type = splice_block %ptr [concrete = constants.%ptr.eca] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar2.ref: type = name_ref Bar2, imports.%Bar2.decl [concrete = constants.%Bar2] // CHECK:STDOUT: %ptr: type = ptr_type %Bar2.ref [concrete = constants.%ptr.eca] // CHECK:STDOUT: } @@ -671,36 +681,81 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_dynamic.carbon +// CHECK:STDOUT: --- import_dynamic.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %pattern_type: type = pattern_type %ptr [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .Bar = +// CHECK:STDOUT: .Bar = %Bar.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %Bar.decl: type = class_decl @Bar [concrete = constants.%Bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] { -// CHECK:STDOUT: %bar.patt: = binding_pattern bar [concrete] -// CHECK:STDOUT: %bar.param_patt: = value_param_pattern %bar.patt, call_param0 [concrete] +// CHECK:STDOUT: %bar.patt: %pattern_type = binding_pattern bar [concrete] +// CHECK:STDOUT: %bar.param_patt: %pattern_type = value_param_pattern %bar.patt, call_param0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %bar.param: = value_param call_param0 -// CHECK:STDOUT: %.loc14: type = splice_block %ptr [concrete = ] { +// CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 +// CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref: = name_ref Bar, [concrete = ] -// CHECK:STDOUT: %ptr: type = ptr_type [concrete = ] +// CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } -// CHECK:STDOUT: %bar: = bind_name bar, %bar.param +// CHECK:STDOUT: %bar: %ptr = bind_name bar, %bar.param // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @MyF(%bar.param: ); +// CHECK:STDOUT: fn @MyF(%bar.param: %ptr); +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_call_dynamic.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] +// CHECK:STDOUT: %ptr.f68: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %pattern_type: type = pattern_type %ptr.f68 [concrete] +// CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] +// CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .Bar = %Bar.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %Bar.decl: type = class_decl @Bar [concrete = constants.%Bar] {} {} +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] { +// CHECK:STDOUT: %bar.patt: %pattern_type = binding_pattern bar [concrete] +// CHECK:STDOUT: %bar.param_patt: %pattern_type = value_param_pattern %bar.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %bar.param: %ptr.f68 = value_param call_param0 +// CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr.f68] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr.f68] +// CHECK:STDOUT: } +// CHECK:STDOUT: %bar: %ptr.f68 = bind_name bar, %bar.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @MyF(%bar.param: %ptr.f68) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %bar.ref: %ptr.f68 = name_ref bar, %bar +// CHECK:STDOUT: %.loc15: ref %Bar = deref %bar.ref +// CHECK:STDOUT: %f.ref: = name_ref f, [concrete = ] +// CHECK:STDOUT: return +// CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: --- import_to_inherit_public.carbon // CHECK:STDOUT: @@ -733,12 +788,11 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: // CHECK:STDOUT: class @Derived { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %.loc8: %Derived.elem = base_decl %Bar.ref, element0 [concrete] // CHECK:STDOUT: %struct_type.base: type = struct_type {.base: %Bar} [concrete = constants.%struct_type.base.36d] -// CHECK:STDOUT: %complete_type.loc9: = complete_type_witness %struct_type.base [concrete = constants.%complete_type.fff] -// CHECK:STDOUT: complete_type_witness = %complete_type.loc9 +// CHECK:STDOUT: %complete_type: = complete_type_witness %struct_type.base [concrete = constants.%complete_type.fff] +// CHECK:STDOUT: complete_type_witness = %complete_type // CHECK:STDOUT: // CHECK:STDOUT: !members: // CHECK:STDOUT: .Self = constants.%Derived diff --git a/toolchain/check/testdata/interop/cpp/class/union.carbon b/toolchain/check/testdata/interop/cpp/class/union.carbon index a61a269fd2d9..b71b3850be0e 100644 --- a/toolchain/check/testdata/interop/cpp/class/union.carbon +++ b/toolchain/check/testdata/interop/cpp/class/union.carbon @@ -2,7 +2,7 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/none.carbon +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon // // AUTOUPDATE // TIP: To test this file alone, run: @@ -18,23 +18,32 @@ union Bar; -// --- fail_todo_import_declaration.carbon +// --- import_declaration.carbon library "[[@TEST_NAME]]"; import Cpp library "declaration.h"; //@dump-sem-ir-begin -// CHECK:STDERR: fail_todo_import_declaration.carbon:[[@LINE+7]]:13: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fail_todo_import_declaration.carbon:[[@LINE+4]]:13: note: in `Cpp` name lookup for `Bar` [InCppNameLookup] -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); -// CHECK:STDERR: ^~~~~~~ -// CHECK:STDERR: fn MyF(bar: Cpp.Bar*); //@dump-sem-ir-end +// --- fail_use_declaration_as_definition.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "declaration.h"; + +fn MyF() { + // CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE+6]]:12: error: binding pattern has incomplete type `Bar` in name binding declaration [IncompleteTypeInBindingDecl] + // CHECK:STDERR: var bar: Cpp.Bar; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_use_declaration_as_definition.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./declaration.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: + var bar: Cpp.Bar; +} + // ============================================================================ // Definition // ============================================================================ @@ -113,6 +122,7 @@ library "[[@TEST_NAME]]"; import Cpp library "private_static_member_function.h"; fn MyF() { + // TODO: Should fail because `foo` is inaccessible. Cpp.Bar.foo(); } @@ -124,7 +134,7 @@ fn MyF() { union Bar { public: - static Bar* foo; + static Bar* _Nonnull foo; }; // --- fail_todo_import_public_static_data_member.carbon @@ -158,28 +168,17 @@ fn MyF() { union Bar { public: - Bar* foo; + Bar* _Nonnull foo; }; -// --- fail_todo_import_public_data_member.carbon +// --- import_public_data_member.carbon library "[[@TEST_NAME]]"; -import Cpp library "public_static_data_member.h"; +import Cpp library "public_data_member.h"; //@dump-sem-ir-begin fn MyF(bar : Cpp.Bar*) { - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+11]]:27: error: semantics TODO: `Unsupported: Declaration type Var` [SemanticsTodo] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+8]]:27: note: in `Cpp` name lookup for `foo` [InCppNameLookup] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_public_data_member.carbon:[[@LINE+4]]:27: error: member name `foo` not found in `Cpp.Bar` [MemberNameNotFoundInInstScope] - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: let foo_bar: Cpp.Bar* = bar->foo; } //@dump-sem-ir-end @@ -202,6 +201,7 @@ library "[[@TEST_NAME]]"; import Cpp library "to_inherit_public.h"; class Derived { + // TODO: Presumably we should disallow deriving from a union. extend base: Cpp.Bar; } @@ -239,36 +239,40 @@ import Cpp library "template.h"; fn MyF(bar: Cpp.Bar*); //@dump-sem-ir-end -// CHECK:STDOUT: --- fail_todo_import_declaration.carbon +// CHECK:STDOUT: --- import_declaration.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %pattern_type: type = pattern_type %ptr [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .Bar = +// CHECK:STDOUT: .Bar = %Bar.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %Bar.decl: type = class_decl @Bar [concrete = constants.%Bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { // CHECK:STDOUT: %MyF.decl: %MyF.type = fn_decl @MyF [concrete = constants.%MyF] { -// CHECK:STDOUT: %bar.patt: = binding_pattern bar [concrete] -// CHECK:STDOUT: %bar.param_patt: = value_param_pattern %bar.patt, call_param0 [concrete] +// CHECK:STDOUT: %bar.patt: %pattern_type = binding_pattern bar [concrete] +// CHECK:STDOUT: %bar.param_patt: %pattern_type = value_param_pattern %bar.patt, call_param0 [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %bar.param: = value_param call_param0 -// CHECK:STDOUT: %.loc14: type = splice_block %ptr [concrete = ] { +// CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 +// CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref: = name_ref Bar, [concrete = ] -// CHECK:STDOUT: %ptr: type = ptr_type [concrete = ] +// CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } -// CHECK:STDOUT: %bar: = bind_name bar, %bar.param +// CHECK:STDOUT: %bar: %ptr = bind_name bar, %bar.param // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @MyF(%bar.param: ); +// CHECK:STDOUT: fn @MyF(%bar.param: %ptr); // CHECK:STDOUT: // CHECK:STDOUT: --- import_definition.carbon // CHECK:STDOUT: @@ -296,7 +300,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } @@ -332,7 +335,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr [concrete = constants.%ptr] { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref [concrete = constants.%ptr] // CHECK:STDOUT: } @@ -363,7 +365,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: fn @MyF() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %foo.ref: %Bar.foo.type = name_ref foo, imports.%Bar.foo.decl [concrete = constants.%Bar.foo] // CHECK:STDOUT: %Bar.foo.call: init %empty_tuple.type = call %foo.ref() @@ -396,7 +397,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] // CHECK:STDOUT: %.loc19: type = splice_block %ptr [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref.loc19_12: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref.loc19_15: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr: type = ptr_type %Bar.ref.loc19_15 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -404,11 +404,12 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_public_data_member.carbon +// CHECK:STDOUT: --- import_public_data_member.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %Bar: type = class_type @Bar [concrete] // CHECK:STDOUT: %ptr.f68: type = ptr_type %Bar [concrete] +// CHECK:STDOUT: %Bar.elem: type = unbound_element_type %Bar, %ptr.f68 [concrete] // CHECK:STDOUT: %pattern_type: type = pattern_type %ptr.f68 [concrete] // CHECK:STDOUT: %MyF.type: type = fn_type @MyF [concrete] // CHECK:STDOUT: %MyF: %MyF.type = struct_value () [concrete] @@ -430,7 +431,6 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %bar.param: %ptr.f68 = value_param call_param0 // CHECK:STDOUT: %.loc7: type = splice_block %ptr.loc7 [concrete = constants.%ptr.f68] { // CHECK:STDOUT: %Cpp.ref.loc7: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Bar.ref.loc7: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] // CHECK:STDOUT: %ptr.loc7: type = ptr_type %Bar.ref.loc7 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } @@ -444,14 +444,16 @@ fn MyF(bar: Cpp.Bar*); // CHECK:STDOUT: %foo_bar.patt: %pattern_type = binding_pattern foo_bar [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: %bar.ref: %ptr.f68 = name_ref bar, %bar -// CHECK:STDOUT: %.loc19_30: ref %Bar = deref %bar.ref -// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] -// CHECK:STDOUT: %.loc19_23: type = splice_block %ptr.loc19 [concrete = constants.%ptr.f68] { -// CHECK:STDOUT: %Cpp.ref.loc19: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %Bar.ref.loc19: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] -// CHECK:STDOUT: %ptr.loc19: type = ptr_type %Bar.ref.loc19 [concrete = constants.%ptr.f68] +// CHECK:STDOUT: %.loc8_30.1: ref %Bar = deref %bar.ref +// CHECK:STDOUT: %foo.ref: %Bar.elem = name_ref foo, @Bar.%.1 [concrete = @Bar.%.1] +// CHECK:STDOUT: %.loc8_30.2: ref %ptr.f68 = class_element_access %.loc8_30.1, element0 +// CHECK:STDOUT: %.loc8_23: type = splice_block %ptr.loc8 [concrete = constants.%ptr.f68] { +// CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Bar.ref.loc8: type = name_ref Bar, imports.%Bar.decl [concrete = constants.%Bar] +// CHECK:STDOUT: %ptr.loc8: type = ptr_type %Bar.ref.loc8 [concrete = constants.%ptr.f68] // CHECK:STDOUT: } -// CHECK:STDOUT: %foo_bar: %ptr.f68 = bind_name foo_bar, [concrete = ] +// CHECK:STDOUT: %.loc8_30.3: %ptr.f68 = bind_value %.loc8_30.2 +// CHECK:STDOUT: %foo_bar: %ptr.f68 = bind_name foo_bar, %.loc8_30.3 // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/class.carbon b/toolchain/check/testdata/interop/cpp/function/class.carbon index bb4302e017d4..5fb9e7b76e0c 100644 --- a/toolchain/check/testdata/interop/cpp/function/class.carbon +++ b/toolchain/check/testdata/interop/cpp/function/class.carbon @@ -2,7 +2,7 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon // // AUTOUPDATE // TIP: To test this file alone, run: @@ -27,12 +27,12 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:11: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] // 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: ^~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); } @@ -44,12 +44,11 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+11]]:10: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] - // CHECK:STDERR: let c: Cpp.C; - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+8]]:10: note: in `Cpp` name lookup for `C` [InCppNameLookup] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+10]]:10: error: binding pattern has incomplete type `C` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let c: Cpp.C; // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let c: Cpp.C; @@ -77,14 +76,21 @@ library "[[@TEST_NAME]]"; import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo1` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo1({}); + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.C` [IncompleteTypeInValueConversion] + // CHECK:STDERR: Cpp.foo2({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-14]]:1: in import [InImport] + // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: Cpp.foo2({}); } @@ -124,7 +130,7 @@ class C { auto foo(C) -> void; -// --- import_definition_single_data_member_value_param_type.carbon +// --- fail_todo_import_definition_single_data_member_value_param_type.carbon library "[[@TEST_NAME]]"; @@ -132,6 +138,14 @@ 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+8]]:11: error: cannot implicitly convert expression of type `{}` to `Cpp.C` [ConversionFailure] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+5]]:11: note: type `{}` does not implement interface `Core.ImplicitAs(Cpp.C)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end } @@ -152,7 +166,7 @@ class C { auto foo(C) -> void; -// --- import_definition_multiple_data_members_value_param_type.carbon +// --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon library "[[@TEST_NAME]]"; @@ -160,6 +174,14 @@ 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+8]]:11: error: cannot implicitly convert expression of type `{}` to `Cpp.C` [ConversionFailure] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+5]]:11: note: type `{}` does not implement interface `Core.ImplicitAs(Cpp.C)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end } @@ -285,19 +307,12 @@ class C; auto foo(C* _Nonnull) -> void; -// --- fail_todo_import_decl_pointer_param_type.carbon +// --- 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(c: 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(c: Cpp.C*) { -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: fn F(c: Cpp.C*) { //@dump-sem-ir-begin Cpp.foo(c); @@ -343,12 +358,12 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: function returns incomplete type `Cpp.C` [IncompleteTypeInFunctionReturnType] // 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: ^~~~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_return_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); } @@ -385,7 +400,7 @@ class C; auto foo() -> C* _Nonnull; -// --- fail_todo_import_decl_pointer_return_type.carbon +// --- import_decl_pointer_return_type.carbon library "[[@TEST_NAME]]"; @@ -393,13 +408,6 @@ 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: Record declarations without a definition` [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 } @@ -455,7 +463,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %C = temporary_storage @@ -472,7 +479,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- import_definition_single_data_member_value_param_type.carbon +// CHECK:STDOUT: --- fail_todo_import_definition_single_data_member_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] @@ -480,10 +487,6 @@ fn F() { // 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: %C.val: %C = struct_value () [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -501,24 +504,14 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %C = temporary_storage -// CHECK:STDOUT: %.loc8_12.3: init %C = class_init (), %.loc8_12.2 [concrete = constants.%C.val] -// CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 -// CHECK:STDOUT: %.loc8_12.5: ref %C = converted %.loc8_12.1, %.loc8_12.4 -// CHECK:STDOUT: %.loc8_12.6: %C = bind_value %.loc8_12.5 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.21b -// CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %.loc16_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc16_12.2: %C = converted %.loc16_12.1, [concrete = ] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- import_definition_multiple_data_members_value_param_type.carbon +// CHECK:STDOUT: --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] @@ -526,10 +519,6 @@ fn F() { // 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: %C.val: %C = struct_value () [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -547,20 +536,10 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %C = temporary_storage -// CHECK:STDOUT: %.loc8_12.3: init %C = class_init (), %.loc8_12.2 [concrete = constants.%C.val] -// CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 -// CHECK:STDOUT: %.loc8_12.5: ref %C = converted %.loc8_12.1, %.loc8_12.4 -// CHECK:STDOUT: %.loc8_12.6: %C = bind_value %.loc8_12.5 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_12.6) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.21b -// CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %.loc16_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc16_12.2: %C = converted %.loc16_12.1, [concrete = ] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -600,7 +579,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %C = temporary_storage @@ -667,7 +645,6 @@ 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: // 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 %C = temporary_storage @@ -720,7 +697,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %C = temporary_storage @@ -786,7 +762,6 @@ fn F() { // 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: %C.bar.type = name_ref bar, imports.%C.bar.decl [concrete = constants.%C.bar] // CHECK:STDOUT: %C.bar.call: init %empty_tuple.type = call %bar.ref() @@ -841,7 +816,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %C = temporary_storage @@ -862,9 +836,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_decl_pointer_param_type.carbon +// CHECK:STDOUT: --- import_decl_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: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] @@ -872,10 +848,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .C = +// CHECK:STDOUT: .C = %C.decl // CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -883,12 +860,12 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%c.param: ) { +// CHECK:STDOUT: fn @F(%c.param: %ptr) { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref.loc15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// 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: %c.ref: = name_ref c, %c -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %c.ref: %ptr = name_ref c, %c +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%c.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -952,7 +929,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_11.1: ref %C = temporary_storage // CHECK:STDOUT: %foo.call: init %C = call %foo.ref() to %.loc8_11.1 @@ -965,9 +941,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_decl_pointer_return_type.carbon +// CHECK:STDOUT: --- import_decl_pointer_return_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: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: } @@ -988,7 +966,7 @@ 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: %foo.call: init = call %foo.ref() +// CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1016,7 +994,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/in_template.carbon b/toolchain/check/testdata/interop/cpp/function/in_template.carbon index 85888911a251..01eeef3497e5 100644 --- a/toolchain/check/testdata/interop/cpp/function/in_template.carbon +++ b/toolchain/check/testdata/interop/cpp/function/in_template.carbon @@ -77,7 +77,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %Y.ref: type = name_ref Y, imports.%X.decl [concrete = constants.%X] // CHECK:STDOUT: %f.ref: %X.f.type = name_ref f, imports.%X.f.decl [concrete = constants.%X.f] // CHECK:STDOUT: %int_42: Core.IntLiteral = int_value 42 [concrete = constants.%int_42.20e] diff --git a/toolchain/check/testdata/interop/cpp/function/pointer.carbon b/toolchain/check/testdata/interop/cpp/function/pointer.carbon index f15699282d39..8a74192194b2 100644 --- a/toolchain/check/testdata/interop/cpp/function/pointer.carbon +++ b/toolchain/check/testdata/interop/cpp/function/pointer.carbon @@ -229,7 +229,6 @@ fn F() { // CHECK:STDOUT: assign %s.var, %.loc8_3 // CHECK:STDOUT: %.loc8_13: type = splice_block %S.ref [concrete = constants.%S] { // 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: } // CHECK:STDOUT: %s: ref %S = bind_name s, %s.var @@ -292,7 +291,6 @@ fn F() { // CHECK:STDOUT: assign %s.var, %.loc8_3 // CHECK:STDOUT: %.loc8_13: type = splice_block %S.ref.loc8 [concrete = constants.%S] { // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %S.ref.loc8: type = name_ref S, imports.%S.decl [concrete = constants.%S] // CHECK:STDOUT: } // CHECK:STDOUT: %s: ref %S = bind_name s, %s.var @@ -560,7 +558,6 @@ fn F() { // CHECK:STDOUT: assign %s.var, %.loc8_3 // CHECK:STDOUT: %.loc8_13: type = splice_block %S.ref [concrete = constants.%S] { // 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: } // CHECK:STDOUT: %s: ref %S = bind_name s, %s.var diff --git a/toolchain/check/testdata/interop/cpp/function/struct.carbon b/toolchain/check/testdata/interop/cpp/function/struct.carbon index 037c5ce29b3e..5f69fbac7b83 100644 --- a/toolchain/check/testdata/interop/cpp/function/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/struct.carbon @@ -27,12 +27,12 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:11: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] // 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: ^~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); } @@ -44,12 +44,11 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+11]]:10: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] - // CHECK:STDERR: let s: Cpp.S; - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+8]]:10: note: in `Cpp` name lookup for `S` [InCppNameLookup] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+10]]:10: error: binding pattern has incomplete type `S` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let s: Cpp.S; // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let s: Cpp.S; @@ -77,14 +76,21 @@ library "[[@TEST_NAME]]"; import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo1` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo1({}); + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.S` [IncompleteTypeInValueConversion] + // CHECK:STDERR: Cpp.foo2({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-14]]:1: in import [InImport] + // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: Cpp.foo2({}); } @@ -124,7 +130,7 @@ struct S { auto foo(S) -> void; -// --- import_definition_single_data_member_value_param_type.carbon +// --- fail_todo_import_definition_single_data_member_value_param_type.carbon library "[[@TEST_NAME]]"; @@ -132,6 +138,11 @@ 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+5]]:11: error: name `Core.ImplicitAs` implicitly referenced here, but not found [CoreNameNotFound] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end } @@ -152,7 +163,7 @@ struct S { auto foo(S) -> void; -// --- import_definition_multiple_data_members_value_param_type.carbon +// --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon library "[[@TEST_NAME]]"; @@ -160,6 +171,11 @@ 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+5]]:11: error: name `Core.ImplicitAs` implicitly referenced here, but not found [CoreNameNotFound] + // CHECK:STDERR: Cpp.foo({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end } @@ -284,19 +300,12 @@ struct S; auto foo(S* _Nonnull) -> void; -// --- fail_todo_import_decl_pointer_param_type.carbon +// --- 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.S*) { -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+4]]:9: note: in `Cpp` name lookup for `S` [InCppNameLookup] -// CHECK:STDERR: fn F(s: Cpp.S*) { -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: fn F(s: Cpp.S*) { //@dump-sem-ir-begin Cpp.foo(s); @@ -342,12 +351,12 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: function returns incomplete type `Cpp.S` [IncompleteTypeInFunctionReturnType] // 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: ^~~~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_return_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); } @@ -384,7 +393,7 @@ struct S; auto foo() -> S* _Nonnull; -// --- fail_todo_import_decl_pointer_return_type.carbon +// --- import_decl_pointer_return_type.carbon library "[[@TEST_NAME]]"; @@ -392,13 +401,6 @@ 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: Record declarations without a definition` [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 } @@ -454,7 +456,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 @@ -471,7 +472,7 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- import_definition_single_data_member_value_param_type.carbon +// CHECK:STDOUT: --- fail_todo_import_definition_single_data_member_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] @@ -479,10 +480,6 @@ fn F() { // 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: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -500,24 +497,14 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5 -// CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %.loc13_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc13_12.2: %S = converted %.loc13_12.1, [concrete = ] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- import_definition_multiple_data_members_value_param_type.carbon +// CHECK:STDOUT: --- fail_todo_import_definition_multiple_data_members_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] @@ -525,10 +512,6 @@ fn F() { // 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: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -546,20 +529,10 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5 -// CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %.loc13_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc13_12.2: %S = converted %.loc13_12.1, [concrete = ] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -599,7 +572,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 @@ -666,7 +638,6 @@ 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: // 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 @@ -719,7 +690,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 @@ -785,7 +755,6 @@ fn F() { // 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: %S.bar.type = name_ref bar, imports.%S.bar.decl [concrete = constants.%S.bar] // CHECK:STDOUT: %S.bar.call: init %empty_tuple.type = call %bar.ref() @@ -840,7 +809,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 @@ -861,9 +829,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_decl_pointer_param_type.carbon +// CHECK:STDOUT: --- import_decl_pointer_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %S [concrete] // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] @@ -871,10 +841,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .S = +// 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: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -882,12 +853,12 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%s.param: ) { +// 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: %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: %s.ref: = name_ref s, %s -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %s.ref: %ptr = name_ref s, %s +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%s.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -951,7 +922,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 @@ -964,9 +934,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_decl_pointer_return_type.carbon +// CHECK:STDOUT: --- import_decl_pointer_return_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: } @@ -987,7 +959,7 @@ 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: %foo.call: init = call %foo.ref() +// CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1015,7 +987,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/union.carbon b/toolchain/check/testdata/interop/cpp/function/union.carbon index a66ba9c7fb09..80371f9763e1 100644 --- a/toolchain/check/testdata/interop/cpp/function/union.carbon +++ b/toolchain/check/testdata/interop/cpp/function/union.carbon @@ -28,12 +28,12 @@ import Cpp library "decl_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+7]]:11: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] // 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: ^~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-7]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end @@ -46,12 +46,11 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+11]]:10: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] - // CHECK:STDERR: let u: Cpp.U; - // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+8]]:10: note: in `Cpp` name lookup for `U` [InCppNameLookup] + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+10]]:10: error: binding pattern has incomplete type `U` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let u: Cpp.U; // CHECK:STDERR: ^~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let u: Cpp.U; @@ -79,14 +78,21 @@ library "[[@TEST_NAME]]"; import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: ^~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo1` [InCppNameLookup] - // CHECK:STDERR: Cpp.foo1({}); - // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo1({}); + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+7]]:12: error: forming value of incomplete type `Cpp.U` [IncompleteTypeInValueConversion] + // CHECK:STDERR: Cpp.foo2({}); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-14]]:1: in import [InImport] + // CHECK:STDERR: ./double_decl_value_param_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: Cpp.foo2({}); } @@ -134,12 +140,10 @@ import Cpp library "definition_single_data_member_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Non-empty union` [SemanticsTodo] + // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon:[[@LINE+5]]:11: error: name `Core.ImplicitAs` implicitly referenced here, but not found [CoreNameNotFound] // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_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: ^~ + // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end @@ -169,12 +173,10 @@ import Cpp library "definition_multiple_data_members_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Non-empty union` [SemanticsTodo] + // CHECK:STDERR: fail_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+5]]:11: error: name `Core.ImplicitAs` implicitly referenced here, but not found [CoreNameNotFound] // CHECK:STDERR: Cpp.foo({}); - // CHECK:STDERR: ^~~~~~~ - // CHECK:STDERR: fail_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: ^~ + // CHECK:STDERR: fail_import_definition_multiple_data_members_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] // CHECK:STDERR: Cpp.foo({}); //@dump-sem-ir-end @@ -301,19 +303,12 @@ union U; auto foo(U* _Nonnull) -> void; -// --- fail_todo_import_decl_pointer_param_type.carbon +// --- 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(u: Cpp.U*) { -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: fail_todo_import_decl_pointer_param_type.carbon:[[@LINE+4]]:9: note: in `Cpp` name lookup for `U` [InCppNameLookup] -// CHECK:STDERR: fn F(u: Cpp.U*) { -// CHECK:STDERR: ^~~~~ -// CHECK:STDERR: fn F(u: Cpp.U*) { //@dump-sem-ir-begin Cpp.foo(u); @@ -359,12 +354,12 @@ library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+7]]:3: error: function returns incomplete type `Cpp.U` [IncompleteTypeInFunctionReturnType] // 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: ^~~~~~~~~ + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:1: in import [InImport] + // CHECK:STDERR: ./decl_value_return_type.h:2: note: class was forward declared here [ClassForwardDeclaredHere] + // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); } @@ -409,7 +404,7 @@ 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: Record declarations without a definition` [SemanticsTodo] + // CHECK:STDERR: fail_todo_import_decl_pointer_return_type.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: nullable pointer: U *` [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] @@ -501,7 +496,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %U = temporary_storage @@ -522,9 +516,10 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %U: type = class_type @U [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -543,7 +538,8 @@ 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: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc13_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc13_12.2: %U = converted %.loc13_12.1, [concrete = ] // CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } @@ -552,9 +548,10 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %U: type = class_type @U [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -573,7 +570,8 @@ 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: %.loc15: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc13_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %.loc13_12.2: %U = converted %.loc13_12.1, [concrete = ] // CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: // CHECK:STDOUT: } @@ -614,7 +612,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %U = temporary_storage @@ -681,7 +678,6 @@ 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: // 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 %U = temporary_storage @@ -734,7 +730,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %U = temporary_storage @@ -800,7 +795,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %U.ref: type = name_ref U, imports.%U.decl [concrete = constants.%U] // CHECK:STDOUT: %bar.ref: %U.bar.type = name_ref bar, imports.%U.bar.decl [concrete = constants.%U.bar] // CHECK:STDOUT: %U.bar.call: init %empty_tuple.type = call %bar.ref() @@ -855,7 +849,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref.loc8: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // 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 %U = temporary_storage @@ -876,9 +869,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- fail_todo_import_decl_pointer_param_type.carbon +// CHECK:STDOUT: --- import_decl_pointer_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { +// CHECK:STDOUT: %U: type = class_type @U [concrete] +// CHECK:STDOUT: %ptr: type = ptr_type %U [concrete] // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] @@ -886,10 +881,11 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .U = +// CHECK:STDOUT: .U = %U.decl // CHECK:STDOUT: .foo = %foo.decl // CHECK:STDOUT: import Cpp//... // CHECK:STDOUT: } +// CHECK:STDOUT: %U.decl: type = class_decl @U [concrete = constants.%U] {} {} // CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { // CHECK:STDOUT: // CHECK:STDOUT: } { @@ -897,12 +893,12 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @F(%u.param: ) { +// CHECK:STDOUT: fn @F(%u.param: %ptr) { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref.loc15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// 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: %u.ref: = name_ref u, %u -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %u.ref: %ptr = name_ref u, %u +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%u.ref) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -966,7 +962,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_11.1: ref %U = temporary_storage // CHECK:STDOUT: %foo.call: init %U = call %foo.ref() to %.loc8_11.1 @@ -1030,7 +1025,6 @@ fn F() { // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %foo.call: init %ptr = call %foo.ref() // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/namespace.carbon b/toolchain/check/testdata/interop/cpp/namespace.carbon index e328c6979f82..987079bda678 100644 --- a/toolchain/check/testdata/interop/cpp/namespace.carbon +++ b/toolchain/check/testdata/interop/cpp/namespace.carbon @@ -331,7 +331,6 @@ fn MyF() { // CHECK:STDOUT: fn @MyF() { // CHECK:STDOUT: !entry: // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %.loc8_11.1: ref %X = temporary_storage // CHECK:STDOUT: %foo.call: init %X = call %foo.ref() to %.loc8_11.1 diff --git a/toolchain/check/type_completion.cpp b/toolchain/check/type_completion.cpp index 95631e508942..4aaceae25149 100644 --- a/toolchain/check/type_completion.cpp +++ b/toolchain/check/type_completion.cpp @@ -140,6 +140,10 @@ class TypeCompleter { auto BuildInfoForInst(SemIR::TypeId /*type_id*/, SemIR::ConstType inst) const -> SemIR::CompleteTypeInfo; + auto BuildInfoForInst(SemIR::TypeId type_id, + SemIR::CustomLayoutType inst) const + -> SemIR::CompleteTypeInfo; + auto BuildInfoForInst(SemIR::TypeId /*type_id*/, SemIR::PartialType inst) const -> SemIR::CompleteTypeInfo; @@ -294,6 +298,12 @@ auto TypeCompleter::AddNestedIncompleteTypes(SemIR::Inst type_inst) -> bool { Push(context_->types().GetTypeIdForTypeInstId(inst.inner_id)); break; } + case CARBON_KIND(SemIR::CustomLayoutType inst): { + for (auto field : context_->struct_type_fields().Get(inst.fields_id)) { + Push(context_->types().GetTypeIdForTypeInstId(field.type_inst_id)); + } + break; + } case CARBON_KIND(SemIR::PartialType inst): { Push(context_->types().GetTypeIdForTypeInstId(inst.inner_id)); break; @@ -520,6 +530,14 @@ auto TypeCompleter::BuildInfoForInst(SemIR::TypeId /*type_id*/, return GetNestedInfo(context_->types().GetTypeIdForTypeInstId(inst.inner_id)); } +auto TypeCompleter::BuildInfoForInst(SemIR::TypeId type_id, + SemIR::CustomLayoutType /*inst*/) const + -> SemIR::CompleteTypeInfo { + // TODO: Should we support other value representations for custom layout + // types? + return {.value_repr = MakePointerValueRepr(type_id)}; +} + auto TypeCompleter::BuildInfoForInst(SemIR::TypeId /*type_id*/, SemIR::PartialType inst) const -> SemIR::CompleteTypeInfo { diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index 34b7f5af1c49..89854c9721da 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -768,6 +768,13 @@ static auto BuildTypeForInst(FileContext& context, SemIR::ConstType inst) context.sem_ir().types().GetTypeIdForTypeInstId(inst.inner_id)); } +static auto BuildTypeForInst(FileContext& context, SemIR::CustomLayoutType inst) + -> llvm::Type* { + auto layout = context.sem_ir().custom_layouts().Get(inst.layout_id); + return llvm::ArrayType::get(llvm::Type::getInt8Ty(context.llvm_context()), + layout[SemIR::CustomLayoutId::SizeIndex]); +} + static auto BuildTypeForInst(FileContext& context, SemIR::PartialType inst) -> llvm::Type* { return context.GetType( diff --git a/toolchain/lower/function_context.cpp b/toolchain/lower/function_context.cpp index 6df0e4ff4853..d1cf5825dffd 100644 --- a/toolchain/lower/function_context.cpp +++ b/toolchain/lower/function_context.cpp @@ -218,6 +218,8 @@ auto FunctionContext::CreateAlloca(llvm::Type* type, const llvm::Twine& name) builder().SetCurrentDebugLocation(debug_loc); // Create an alloca for this variable in the entry block. + // TODO: Compute alignment of the type, which may be greater than the + // alignment computed by LLVM. alloca = builder().CreateAlloca(type, /*ArraySize=*/nullptr, name); } diff --git a/toolchain/lower/handle_aggregates.cpp b/toolchain/lower/handle_aggregates.cpp index 0793ab422064..e36b933c45cb 100644 --- a/toolchain/lower/handle_aggregates.cpp +++ b/toolchain/lower/handle_aggregates.cpp @@ -10,6 +10,7 @@ #include "toolchain/lower/function_context.h" #include "toolchain/sem_ir/expr_info.h" #include "toolchain/sem_ir/file.h" +#include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/typed_insts.h" @@ -26,6 +27,30 @@ static auto GetPointeeType(FunctionContext::TypeInFile type) .type_id = type.file->GetPointeeType(type.type_id)}; } +// Given an index within a SemIR aggregate type, returns the corresponding index +// of the element within the LLVM type suitable for use with the getelementptr +// instruction. +static auto GetElementIndex(FunctionContext::TypeInFile type, + SemIR::ElementIndex idx) -> unsigned int { + auto type_inst = type.file->types().GetAsInst(type.type_id); + + if (auto custom_layout_type = type_inst.TryAs()) { + // For custom layout types, we form an array of i8 as the LLVM type, so the + // offset in the type is the getelementptr index. + // TODO: This offset might not fit into an `unsigned int`. + return type.file->custom_layouts().Get( + custom_layout_type + ->layout_id)[SemIR::CustomLayoutId::FirstFieldIndex + idx.index]; + } + + // For now, struct and tuple types map directly into LLVM struct types with + // identical field numbering. + CARBON_CHECK( + type_inst.Is() || type_inst.Is(), + "Indexing unexpected aggregate type {0}", type_inst); + return idx.index; +} + // Extracts an element of an aggregate, such as a struct, tuple, or class, by // index. Depending on the expression category and value representation of the // aggregate input, this will either produce a value or a reference. @@ -58,14 +83,16 @@ static auto GetAggregateElement(FunctionContext& context, return aggr_value; case SemIR::ValueRepr::Copy: // We are holding the values of the aggregate directly, elementwise. - return context.builder().CreateExtractValue(aggr_value, idx.index, - name); + return context.builder().CreateExtractValue( + aggr_value, GetElementIndex(value_repr.type(), idx), name); case SemIR::ValueRepr::Pointer: { // The value representation is a pointer to an aggregate that we want // to index into. - auto* value_type = context.GetType(GetPointeeType(value_repr.type())); + auto value_rep_type = GetPointeeType(value_repr.type()); + auto* value_type = context.GetType(value_rep_type); auto* elem_ptr = context.builder().CreateStructGEP( - value_type, aggr_value, idx.index, name); + value_type, aggr_value, GetElementIndex(value_rep_type, idx), + name); if (!value_repr.repr.elements_are_values()) { // `elem_ptr` points to an object representation, which is our @@ -88,17 +115,21 @@ static auto GetAggregateElement(FunctionContext& context, case SemIR::ExprCategory::DurableRef: case SemIR::ExprCategory::EphemeralRef: { // Just locate the aggregate element. - auto* aggr_type = context.GetTypeOfInst(aggr_inst_id); - return context.builder().CreateStructGEP(aggr_type, aggr_value, idx.index, - name); + auto aggr_type = context.GetTypeIdOfInst(aggr_inst_id); + auto object_repr = FunctionContext::TypeInFile{ + .file = aggr_type.file, + .type_id = aggr_type.file->types().GetObjectRepr(aggr_type.type_id)}; + return context.builder().CreateStructGEP( + context.GetType(object_repr), aggr_value, + GetElementIndex(object_repr, idx), name); } } } static auto GetStructFieldName(FunctionContext::TypeInFile struct_type, SemIR::ElementIndex index) -> llvm::StringRef { - auto struct_type_inst = - struct_type.file->types().GetAs(struct_type.type_id); + auto struct_type_inst = struct_type.file->types().GetAs( + struct_type.type_id); auto fields = struct_type.file->struct_type_fields().Get(struct_type_inst.fields_id); // We intentionally don't add this to the fingerprint because it's only used diff --git a/toolchain/lower/testdata/interop/cpp/field.carbon b/toolchain/lower/testdata/interop/cpp/field.carbon new file mode 100644 index 000000000000..401c3baceb1b --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/field.carbon @@ -0,0 +1,234 @@ +// 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-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/field.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/field.carbon + +// --- struct.h + +struct A { + int n; + alignas(16) int m; +}; + +// --- access_struct.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "struct.h"; + +// TODO: We generate 4-byte-aligned loads here, and should generate +// 16-byte-aligned loads as Clang does. +fn AccessN(a: Cpp.A) -> i32 { + return a.n; +} + +fn AccessM(a: Cpp.A) -> i32 { + return a.m; +} + +// --- assign_struct.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "struct.h"; + +// TODO: We generate 4-byte-aligned stores here, and should generate +// 16-byte-aligned stores as Clang does. +fn AssignN(p: Cpp.A*) { + p->n = 1; +} + +fn AssignM(p: Cpp.A*) { + p->m = 1; +} + +// --- union.h + +union A { + int n; + int m; +}; + +// --- access_union.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "union.h"; + +fn AccessN(a: Cpp.A) -> i32 { + return a.n; +} + +fn AccessM(a: Cpp.A) -> i32 { + return a.m; +} + +// --- assign_union.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "union.h"; + +fn AssignN(p: Cpp.A*) { + p->n = 1; +} + +fn AssignM(p: Cpp.A*) { + p->m = 1; +} + +// CHECK:STDOUT: ; ModuleID = 'access_struct.carbon' +// CHECK:STDOUT: source_filename = "access_struct.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @_CAccessN.Main(ptr %a) !dbg !7 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc9_11.1.n = getelementptr inbounds nuw [32 x i8], ptr %a, i32 0, i32 0, !dbg !10 +// CHECK:STDOUT: %.loc9_11.2 = load i32, ptr %.loc9_11.1.n, align 4, !dbg !10 +// CHECK:STDOUT: ret i32 %.loc9_11.2, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @_CAccessM.Main(ptr %a) !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc13_11.1.m = getelementptr inbounds nuw [32 x i8], ptr %a, i32 0, i32 16, !dbg !13 +// CHECK:STDOUT: %.loc13_11.2 = load i32, ptr %.loc13_11.1.m, align 4, !dbg !13 +// CHECK:STDOUT: ret i32 %.loc13_11.2, !dbg !14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "access_struct.carbon", directory: "") +// CHECK:STDOUT: !7 = distinct !DISubprogram(name: "AccessN", linkageName: "_CAccessN.Main", scope: null, file: !6, line: 8, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !8 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !9 = !{} +// CHECK:STDOUT: !10 = !DILocation(line: 9, column: 10, scope: !7) +// CHECK:STDOUT: !11 = !DILocation(line: 9, column: 3, scope: !7) +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "AccessM", linkageName: "_CAccessM.Main", scope: null, file: !6, line: 12, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !13 = !DILocation(line: 13, column: 10, scope: !12) +// CHECK:STDOUT: !14 = !DILocation(line: 13, column: 3, scope: !12) +// CHECK:STDOUT: ; ModuleID = 'assign_struct.carbon' +// CHECK:STDOUT: source_filename = "assign_struct.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CAssignN.Main(ptr %p) !dbg !7 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc9_4.2.n = getelementptr inbounds nuw [32 x i8], ptr %p, i32 0, i32 0, !dbg !10 +// CHECK:STDOUT: store i32 1, ptr %.loc9_4.2.n, align 4, !dbg !10 +// CHECK:STDOUT: ret void, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CAssignM.Main(ptr %p) !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc13_4.2.m = getelementptr inbounds nuw [32 x i8], ptr %p, i32 0, i32 16, !dbg !13 +// CHECK:STDOUT: store i32 1, ptr %.loc13_4.2.m, align 4, !dbg !13 +// CHECK:STDOUT: ret void, !dbg !14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "assign_struct.carbon", directory: "") +// CHECK:STDOUT: !7 = distinct !DISubprogram(name: "AssignN", linkageName: "_CAssignN.Main", scope: null, file: !6, line: 8, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !8 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !9 = !{} +// CHECK:STDOUT: !10 = !DILocation(line: 9, column: 3, scope: !7) +// CHECK:STDOUT: !11 = !DILocation(line: 8, column: 1, scope: !7) +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "AssignM", linkageName: "_CAssignM.Main", scope: null, file: !6, line: 12, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !13 = !DILocation(line: 13, column: 3, scope: !12) +// CHECK:STDOUT: !14 = !DILocation(line: 12, column: 1, scope: !12) +// CHECK:STDOUT: ; ModuleID = 'access_union.carbon' +// CHECK:STDOUT: source_filename = "access_union.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @_CAccessN.Main(ptr %a) !dbg !7 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc7_11.1.n = getelementptr inbounds nuw [4 x i8], ptr %a, i32 0, i32 0, !dbg !10 +// CHECK:STDOUT: %.loc7_11.2 = load i32, ptr %.loc7_11.1.n, align 4, !dbg !10 +// CHECK:STDOUT: ret i32 %.loc7_11.2, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define i32 @_CAccessM.Main(ptr %a) !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc11_11.1.m = getelementptr inbounds nuw [4 x i8], ptr %a, i32 0, i32 0, !dbg !13 +// CHECK:STDOUT: %.loc11_11.2 = load i32, ptr %.loc11_11.1.m, align 4, !dbg !13 +// CHECK:STDOUT: ret i32 %.loc11_11.2, !dbg !14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "access_union.carbon", directory: "") +// CHECK:STDOUT: !7 = distinct !DISubprogram(name: "AccessN", linkageName: "_CAccessN.Main", scope: null, file: !6, line: 6, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !8 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !9 = !{} +// CHECK:STDOUT: !10 = !DILocation(line: 7, column: 10, scope: !7) +// CHECK:STDOUT: !11 = !DILocation(line: 7, column: 3, scope: !7) +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "AccessM", linkageName: "_CAccessM.Main", scope: null, file: !6, line: 10, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !13 = !DILocation(line: 11, column: 10, scope: !12) +// CHECK:STDOUT: !14 = !DILocation(line: 11, column: 3, scope: !12) +// CHECK:STDOUT: ; ModuleID = 'assign_union.carbon' +// CHECK:STDOUT: source_filename = "assign_union.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CAssignN.Main(ptr %p) !dbg !7 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc7_4.2.n = getelementptr inbounds nuw [4 x i8], ptr %p, i32 0, i32 0, !dbg !10 +// CHECK:STDOUT: store i32 1, ptr %.loc7_4.2.n, align 4, !dbg !10 +// CHECK:STDOUT: ret void, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CAssignM.Main(ptr %p) !dbg !12 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc11_4.2.m = getelementptr inbounds nuw [4 x i8], ptr %p, i32 0, i32 0, !dbg !13 +// CHECK:STDOUT: store i32 1, ptr %.loc11_4.2.m, align 4, !dbg !13 +// CHECK:STDOUT: ret void, !dbg !14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "assign_union.carbon", directory: "") +// CHECK:STDOUT: !7 = distinct !DISubprogram(name: "AssignN", linkageName: "_CAssignN.Main", scope: null, file: !6, line: 6, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !8 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !9 = !{} +// CHECK:STDOUT: !10 = !DILocation(line: 7, column: 3, scope: !7) +// CHECK:STDOUT: !11 = !DILocation(line: 6, column: 1, scope: !7) +// CHECK:STDOUT: !12 = distinct !DISubprogram(name: "AssignM", linkageName: "_CAssignM.Main", scope: null, file: !6, line: 10, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !13 = !DILocation(line: 11, column: 3, scope: !12) +// CHECK:STDOUT: !14 = !DILocation(line: 10, column: 1, scope: !12) diff --git a/toolchain/sem_ir/expr_info.cpp b/toolchain/sem_ir/expr_info.cpp index 7874c81e40c3..1cb4fe91bb18 100644 --- a/toolchain/sem_ir/expr_info.cpp +++ b/toolchain/sem_ir/expr_info.cpp @@ -109,6 +109,7 @@ auto GetExprCategory(const File& file, InstId inst_id) -> ExprCategory { case CompleteTypeWitness::Kind: case ConstType::Kind: case ConvertToValueAction::Kind: + case CustomLayoutType::Kind: case FacetAccessType::Kind: case FacetType::Kind: case FacetValue::Kind: diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index dcc52df76275..10d6bc343026 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -61,6 +61,8 @@ struct ExprRegion { using ExprRegionStore = ValueStore; +using CustomLayoutStore = BlockValueStore; + // Provides semantic analysis on a Parse::Tree. class File : public Printable { public: @@ -210,6 +212,10 @@ class File : public Printable { auto struct_type_fields() const -> const StructTypeFieldsStore& { return struct_type_fields_; } + auto custom_layouts() -> CustomLayoutStore& { return custom_layouts_; } + auto custom_layouts() const -> const CustomLayoutStore& { + return custom_layouts_; + } auto types() -> TypeStore& { return types_; } auto types() const -> const TypeStore& { return types_; } auto insts() -> InstStore& { return insts_; } @@ -361,6 +367,9 @@ class File : public Printable { // Storage for StructTypeField lists. StructTypeFieldsStore struct_type_fields_ = StructTypeFieldsStore(allocator_); + // Storage for custom layouts. + CustomLayoutStore custom_layouts_ = CustomLayoutStore(allocator_); + // Descriptions of types used in this file. TypeStore types_ = TypeStore(this); diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index b225e8bcf45f..ad164d7f07f4 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -1006,6 +1006,23 @@ auto Formatter::FormatInstRhs(Inst inst) -> void { return; } + case CARBON_KIND(CustomLayoutType type): { + out_ << " {"; + auto layout = sem_ir_->custom_layouts().Get(type.layout_id); + out_ << "size=" << layout[CustomLayoutId::SizeIndex] + << ", align=" << layout[CustomLayoutId::AlignIndex]; + for (auto [field, offset] : + llvm::zip(sem_ir_->struct_type_fields().Get(type.fields_id), + layout.drop_front(CustomLayoutId::FirstFieldIndex))) { + out_ << ", ."; + FormatName(field.name_id); + out_ << "@" << offset << ": "; + FormatInstAsType(field.type_inst_id); + } + out_ << "}"; + return; + } + case CARBON_KIND(FloatLiteral value): { llvm::SmallVector buffer; sem_ir_->floats().Get(value.float_id).toString(buffer); diff --git a/toolchain/sem_ir/formatter.h b/toolchain/sem_ir/formatter.h index ac9de2284edc..9ec746f5d77e 100644 --- a/toolchain/sem_ir/formatter.h +++ b/toolchain/sem_ir/formatter.h @@ -401,8 +401,10 @@ auto Formatter::FormatEntityStart(llvm::StringRef entity_kind, if (import_ir_inst_id.has_value()) { auto import_ir_id = sem_ir_->import_ir_insts().Get(import_ir_inst_id).ir_id(); - const auto* import_file = sem_ir_->import_irs().Get(import_ir_id).sem_ir; - pending_imported_from_ = import_file->filename(); + if (const auto* import_file = + sem_ir_->import_irs().Get(import_ir_id).sem_ir) { + pending_imported_from_ = import_file->filename(); + } } } diff --git a/toolchain/sem_ir/id_kind.h b/toolchain/sem_ir/id_kind.h index 6e943fdca2bf..f914d387839d 100644 --- a/toolchain/sem_ir/id_kind.h +++ b/toolchain/sem_ir/id_kind.h @@ -35,6 +35,7 @@ using IdKind = TypeEnum< ClassId, CompileTimeBindIndex, ConstantId, + CustomLayoutId, DeclInstBlockId, DestInstId, ElementIndex, diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 87823c4faefa..a360489d03e6 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -728,6 +728,26 @@ struct StructTypeFieldsId : public IdBase { constexpr StructTypeFieldsId StructTypeFieldsId::Empty = StructTypeFieldsId(0); +// The ID of a `CustomLayout` block. +struct CustomLayoutId : public IdBase { + static constexpr llvm::StringLiteral Label = "custom_layout"; + + // The canonical empty block. This is never used, but needed by + // BlockValueStore. + static const CustomLayoutId Empty; + + // The index in a custom layout of the overall size field. + static constexpr int SizeIndex = 0; + // The index in a custom layout of the overall alignment field. + static constexpr int AlignIndex = 1; + // The index in a custom layout of the offset of the first struct field. + static constexpr int FirstFieldIndex = 2; + + using IdBase::IdBase; +}; + +constexpr CustomLayoutId CustomLayoutId::Empty = CustomLayoutId(0); + // The ID of a type. struct TypeId : public IdBase { static constexpr llvm::StringLiteral Label = "type"; diff --git a/toolchain/sem_ir/import_ir.cpp b/toolchain/sem_ir/import_ir.cpp index 5289bea51180..03413738395a 100644 --- a/toolchain/sem_ir/import_ir.cpp +++ b/toolchain/sem_ir/import_ir.cpp @@ -33,9 +33,13 @@ auto GetCanonicalFileAndInstId(const File* sem_ir, SemIR::InstId inst_id) if (auto import_ir_inst_id = sem_ir->insts().GetImportSource(inst_id); import_ir_inst_id.has_value()) { auto import_ir_inst = sem_ir->import_ir_insts().Get(import_ir_inst_id); - sem_ir = sem_ir->import_irs().Get(import_ir_inst.ir_id()).sem_ir; - inst_id = import_ir_inst.inst_id(); - continue; + // TODO: For imports from C++, we return the importing instruction, which + // isn't necessarily canonical. + if (import_ir_inst.ir_id() != ImportIRId::Cpp) { + sem_ir = sem_ir->import_irs().Get(import_ir_inst.ir_id()).sem_ir; + inst_id = import_ir_inst.inst_id(); + continue; + } } // Step through export declarations to their exported value. diff --git a/toolchain/sem_ir/inst_categories.h b/toolchain/sem_ir/inst_categories.h index f64b701b1e23..a3454258d29f 100644 --- a/toolchain/sem_ir/inst_categories.h +++ b/toolchain/sem_ir/inst_categories.h @@ -167,6 +167,17 @@ struct AnyParamPattern { CallParamIndex index; }; +// A struct-like type with a list of named fields. +struct AnyStructType { + using CategoryInfo = CategoryOf; + + InstKind kind; + + TypeId type_id; + StructTypeFieldsId fields_id; + AnyRawId arg1; +}; + } // namespace Carbon::SemIR #endif // CARBON_TOOLCHAIN_SEM_IR_INST_CATEGORIES_H_ diff --git a/toolchain/sem_ir/inst_fingerprinter.cpp b/toolchain/sem_ir/inst_fingerprinter.cpp index a927698e496e..9b2c76dca678 100644 --- a/toolchain/sem_ir/inst_fingerprinter.cpp +++ b/toolchain/sem_ir/inst_fingerprinter.cpp @@ -150,6 +150,16 @@ struct Worklist { AddBlock(sem_ir->struct_type_fields().Get(struct_type_fields_id)); } + auto Add(CustomLayoutId custom_layout_id) -> void { + if (!custom_layout_id.has_value()) { + AddInvalid(); + return; + } + auto block = sem_ir->custom_layouts().Get(custom_layout_id); + contents.push_back(block.size()); + contents.insert(contents.end(), block.begin(), block.end()); + } + auto Add(NameScopeId name_scope_id) -> void { if (!name_scope_id.has_value()) { AddInvalid(); diff --git a/toolchain/sem_ir/inst_kind.def b/toolchain/sem_ir/inst_kind.def index ae2d64352aad..7bb97a0f5f70 100644 --- a/toolchain/sem_ir/inst_kind.def +++ b/toolchain/sem_ir/inst_kind.def @@ -55,6 +55,7 @@ CARBON_SEM_IR_INST_KIND(CompleteTypeWitness) CARBON_SEM_IR_INST_KIND(ConstType) CARBON_SEM_IR_INST_KIND(ConvertToValueAction) CARBON_SEM_IR_INST_KIND(Converted) +CARBON_SEM_IR_INST_KIND(CustomLayoutType) CARBON_SEM_IR_INST_KIND(Deref) CARBON_SEM_IR_INST_KIND(ErrorInst) CARBON_SEM_IR_INST_KIND(ExportDecl) diff --git a/toolchain/sem_ir/stringify.cpp b/toolchain/sem_ir/stringify.cpp index 22f17356ac13..5b918fc56683 100644 --- a/toolchain/sem_ir/stringify.cpp +++ b/toolchain/sem_ir/stringify.cpp @@ -299,6 +299,12 @@ class Stringifier { step_stack_->PushInstId(inst.inner_id); } + auto StringifyInst(InstId /*inst_id*/, CustomLayoutType inst) -> void { + auto layout = sem_ir_->custom_layouts().Get(inst.layout_id); + *out_ << ""; + } + auto StringifyInst(InstId /*inst_id*/, FacetAccessType inst) -> void { // Given `T:! I`, print `T as type` as simply `T`. step_stack_->PushInstId(inst.facet_value_inst_id); diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index f43b18c4dfdf..b051b9094024 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -552,6 +552,20 @@ struct ConvertToValueAction { TypeInstId target_type_inst_id; }; +// A type whose layout is determined externally. This is used as the object +// representation of class types imported from C++. +struct CustomLayoutType { + static constexpr auto Kind = InstKind::CustomLayoutType.Define( + {.ir_name = "custom_layout_type", + .is_type = InstIsType::Always, + .constant_kind = InstConstantKind::WheneverPossible, + .deduce_through = true}); + + TypeId type_id; + StructTypeFieldsId fields_id; + CustomLayoutId layout_id; +}; + // The `*` dereference operator, as in `*pointer`. struct Deref { static constexpr auto Kind =