From 71ba07239f65b1089ff28fb671a8f6ccacc23ed5 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 12 May 2026 18:44:07 -0700 Subject: [PATCH] Support pass-by-move when calling a C++ function taking by value. (#7135) Previously, we picked a single Carbon parameter pattern for each C++ parameter pattern. This doesn't work well in cases where the Carbon semantics and the C++ semantics are not perfectly aligned. In particular, when a parameter is passed by value in C++, that might mean either pass-by-move (which in Carbon would best be modeled by a `var` pattern, as no other form of parameter would perform a move) or pass-by-copy (which in Carbon would best be modeled by a value parameter, as a `var` parameter would force an extra copy). After this change, we compute a passing mode for each parameter based on the implicit conversion sequence from the argument to the parameter as determined by C++ overload resolution, and use that to determine the Carbon pattern corresponding to each C++ parameter. This results in potentially generating multiple different thunks for the same C++ function if it's called in different ways, but we already did that to handle default arguments and list-initialization. The passing modes are included in the thunk mangling. Add a new value store for clang decl signatures, which capture the information about parameter passing mode as well as the other existing information about different ways that a C++ function might be imported to Carbon. Most of the rules for computing passing modes are the same as before: const references use pass by value, non-const lvalue references use pass-by-ref, non-const rvalue references use pass-by-var. But for C++ non-reference parameters, pick between pass-by-value and pass-by-var based on whether the implicit conversion sequence was effectively performing a copy. Prefer pass-by-value if either would work and they'd do the same thing. We still use pass-by-value for const references, even when the argument is an lvalue and we could pass a reference; we may want to change this in future. For virtual functions, we try to pick a worst-case passing mode, as we can only pick a single signature for what goes in the vtable. Calls to virtual functions will still use a thunk to C++, allowing variance in the calling convention at call sites. We don't allow variance in the overriders as we don't implement support for thunks for virtual functions yet. We currently use pass-by-value for const reference parameters here, but that should probably change at some point. Assisted-by: Gemini via Antigravity --- toolchain/check/context.h | 3 + toolchain/check/cpp/impl_lookup.cpp | 41 +- toolchain/check/cpp/import.cpp | 208 +++++--- toolchain/check/cpp/import.h | 10 +- toolchain/check/cpp/operators.cpp | 94 ++-- toolchain/check/cpp/overload_resolution.cpp | 146 ++++- toolchain/check/cpp/overload_resolution.h | 12 + toolchain/check/cpp/thunk.cpp | 109 ++-- toolchain/check/cpp/type_mapping.cpp | 5 +- toolchain/check/import_ref.cpp | 6 +- .../basics/raw_sem_ir/builtins.carbon | 1 + .../testdata/basics/raw_sem_ir/bundle.carbon | 1 + .../basics/raw_sem_ir/cpp_interop.carbon | 21 +- .../basics/raw_sem_ir/multifile.carbon | 2 + .../multifile_with_textual_ir.carbon | 2 + .../raw_sem_ir/non_core_interfaces.carbon | 2 + .../basics/raw_sem_ir/one_file.carbon | 1 + .../one_file_with_textual_ir.carbon | 1 + .../interop/cpp/basics/import/indirect.carbon | 3 +- .../interop/cpp/class/import/method.carbon | 40 +- .../interop/cpp/enum/anonymous.carbon | 3 +- .../interop/cpp/function/import/class.carbon | 156 ++++++ .../cpp/function/import/default_arg.carbon | 16 +- .../cpp/function/import/thunk_ast.carbon | 4 +- .../cpp/operators/arithmetic_operators.carbon | 62 +-- .../interop/cpp/operators/deref.carbon | 3 +- .../interop/cpp/operators/operators.carbon | 42 +- .../interop/cpp/operators/ordered_with.carbon | 15 +- toolchain/driver/testdata/stdin.carbon | 1 + .../testdata/interop/cpp/constructor.carbon | 78 +-- .../testdata/interop/cpp/copy_vs_move.carbon | 504 ++++++++++++++++++ .../testdata/interop/cpp/extern_c.carbon | 4 +- .../testdata/interop/cpp/function_decl.carbon | 16 +- .../lower/testdata/interop/cpp/method.carbon | 12 +- .../lower/testdata/interop/cpp/nullptr.carbon | 10 +- .../testdata/interop/cpp/operators.carbon | 24 +- .../testdata/interop/cpp/parameters.carbon | 36 +- .../lower/testdata/interop/cpp/pointer.carbon | 16 +- .../testdata/interop/cpp/reference.carbon | 72 +-- .../lower/testdata/interop/cpp/return.carbon | 44 +- .../interop/cpp/std_initializer_list.carbon | 28 +- .../testdata/interop/cpp/template.carbon | 16 +- .../lower/testdata/interop/cpp/thunks.carbon | 6 +- .../testdata/interop/cpp/virtual_base.carbon | 4 +- toolchain/sem_ir/clang_decl.cpp | 61 ++- toolchain/sem_ir/clang_decl.h | 144 +++-- toolchain/sem_ir/file.cpp | 76 +-- toolchain/sem_ir/file.h | 9 + toolchain/sem_ir/ids.h | 7 + toolchain/sem_ir/yaml_test.cpp | 1 + 50 files changed, 1654 insertions(+), 524 deletions(-) create mode 100644 toolchain/lower/testdata/interop/cpp/copy_vs_move.carbon diff --git a/toolchain/check/context.h b/toolchain/check/context.h index 190388ad4f7e..6e8775d2309a 100644 --- a/toolchain/check/context.h +++ b/toolchain/check/context.h @@ -357,6 +357,9 @@ class Context { auto clang_decls() -> SemIR::ClangDeclStore& { return sem_ir().clang_decls(); } + auto clang_decl_signatures() -> SemIR::ClangDeclSignatureStore& { + return sem_ir().clang_decl_signatures(); + } auto names() -> SemIR::NameStoreWrapper { return sem_ir().names(); } auto name_scopes() -> SemIR::NameScopeStore& { return sem_ir().name_scopes(); diff --git a/toolchain/check/cpp/impl_lookup.cpp b/toolchain/check/cpp/impl_lookup.cpp index 1bf521c20182..c345f15d5891 100644 --- a/toolchain/check/cpp/impl_lookup.cpp +++ b/toolchain/check/cpp/impl_lookup.cpp @@ -76,7 +76,7 @@ namespace { struct DeclInfo { // If null, no C++ decl was found and no witness can be created. clang::NamedDecl* decl = nullptr; - SemIR::ClangDeclKey::Signature signature; + SemIR::ClangDeclSignatureId signature_id; }; } // namespace @@ -98,7 +98,7 @@ static auto GetFunctionId(Context& context, SemIR::LocId loc_id, } auto fn_id = - ImportCppFunctionDecl(context, loc_id, cpp_fn, decl_info.signature); + ImportCppFunctionDecl(context, loc_id, cpp_fn, decl_info.signature_id); if (fn_id == SemIR::ErrorInst::InstId) { return SemIR::ErrorInst::InstId; } @@ -109,6 +109,18 @@ static auto GetFunctionId(Context& context, SemIR::LocId loc_id, return fn_id; } +// Creates a signature with `Normal` kind and the given parameter passing +// modes, and adds it to the value store. +static auto MakeSignature( + Context& context, + std::initializer_list modes, + SemIR::ClangDeclSignature::PassingMode self_passing_mode = + SemIR::ClangDeclSignature::PassingMode::ByRef) + -> SemIR::ClangDeclSignatureId { + return context.clang_decl_signatures().Add(SemIR::ClangDeclSignature::Make( + modes, SemIR::ClangDeclSignature::Normal, self_passing_mode)); +} + static auto BuildCopyWitness( Context& context, SemIR::LocId loc_id, SemIR::ConstantId query_self_const_id, @@ -131,9 +143,12 @@ static auto BuildCopyWitness( })) { return SemIR::ErrorInst::InstId; } + + SemIR::ClangDeclSignatureId signature_id = MakeSignature( + context, {SemIR::ClangDeclSignature::PassingMode::ByValue}); auto decl_info = DeclInfo{.decl = clang_sema.LookupCopyingConstructor( class_decl, clang::Qualifiers::Const), - .signature = {.num_params = 1}}; + .signature_id = signature_id}; auto fn_id = GetFunctionId(context, loc_id, decl_info); if (fn_id == SemIR::ErrorInst::InstId || fn_id == SemIR::InstId::None) { return fn_id; @@ -168,8 +183,14 @@ static auto BuildCppUnsafeDerefWitness( context.TODO(loc_id, "operator* overload sets not implemented yet"); return SemIR::ErrorInst::InstId; } + + // TODO: Parameterize the interface by the form of the operand and compute the + // appropriate passing mode here. + SemIR::ClangDeclSignatureId signature_id = + MakeSignature(context, {}, SemIR::ClangDeclSignature::PassingMode::ByRef); + auto decl_info = - DeclInfo{.decl = *candidates.begin(), .signature = {.num_params = 0}}; + DeclInfo{.decl = *candidates.begin(), .signature_id = signature_id}; auto fn_id = GetFunctionId(context, loc_id, decl_info); if (fn_id == SemIR::ErrorInst::InstId || fn_id == SemIR::InstId::None) { return fn_id; @@ -204,9 +225,11 @@ static auto BuildDefaultWitness( // That happens if class_decl->hasUninitializedExplicitInitFields() is true. // // TODO: Consider treating such types as not implementing `Default`. + SemIR::ClangDeclSignatureId signature_id = MakeSignature(context, {}); + auto decl_info = DeclInfo{.decl = clang_sema.LookupDefaultConstructor(class_decl), - .signature = {.num_params = 0}}; + .signature_id = signature_id}; auto fn_id = GetFunctionId(context, loc_id, decl_info); if (fn_id == SemIR::ErrorInst::InstId || fn_id == SemIR::InstId::None) { return fn_id; @@ -227,8 +250,10 @@ static auto BuildDestroyWitness( if (!class_decl) { return SemIR::InstId::None; } + SemIR::ClangDeclSignatureId signature_id = MakeSignature(context, {}); + auto decl_info = DeclInfo{.decl = clang_sema.LookupDestructor(class_decl), - .signature = {.num_params = 0}}; + .signature_id = signature_id}; auto fn_id = GetFunctionId(context, loc_id, decl_info); if (fn_id == SemIR::ErrorInst::InstId || fn_id == SemIR::InstId::None) { return fn_id; @@ -375,8 +400,8 @@ static auto LookupCppMethod( auto decl_info = DeclInfo{ .decl = *lookup_info.begin(), - .signature = {.num_params = 0}, - }; + .signature_id = MakeSignature( + context, {}, SemIR::ClangDeclSignature::PassingMode::ByValue)}; return GetFunctionId(context, loc_id, decl_info); } diff --git a/toolchain/check/cpp/import.cpp b/toolchain/check/cpp/import.cpp index 73221e581c65..856b41e72f5a 100644 --- a/toolchain/check/cpp/import.cpp +++ b/toolchain/check/cpp/import.cpp @@ -70,6 +70,12 @@ namespace Carbon::Check { +auto IsObjectMemberFunction(const clang::FunctionDecl& decl) -> bool { + const auto* method = dyn_cast(&decl); + return method && !method->isStatic() && + !isa(&decl); +} + // Adds the name to the scope with the given `access_kind` and `inst_id`. // `inst_id` must have a value. static auto AddNameToScope(Context& context, SemIR::NameScopeId scope_id, @@ -504,6 +510,7 @@ static auto ImportNamespaceDecl(Context& context, clang::NamespaceDecl* clang_decl) -> SemIR::InstId { auto key = SemIR::ClangDeclKey(clang_decl); + // Check if the declaration is already mapped. if (SemIR::InstId existing_inst_id = LookupClangDeclInstId(context, key); existing_inst_id.has_value()) { @@ -833,6 +840,75 @@ static auto ImportClassObjectRepr(Context& context, SemIR::ClassId class_id, .layout_id = context.custom_layouts().Add(layout)})); } +// Returns the passing mode to use for a given virtual function's object +// parameter. +static auto GetVirtualFunctionSelfPassingMode( + const clang::CXXMethodDecl* method_decl) + -> SemIR::ClangDeclSignature::PassingMode { + if (method_decl->getMethodQualifiers().hasConst()) { + // Map these signatures to pass-by-value: + // + // virtual void f() const; + // virtual void f() const&; + // virtual void f() const&&; + // + // In each case, we expect `self` to not be modified. + return SemIR::ClangDeclSignature::PassingMode::ByValue; + } + + // Map anything else to pass-by-reference. This includes `&&`-qualified + // functions, which we can't map to pass-by-var since that would perform a + // slicing copy at the call site, which would be disastrous for a virtual + // function call. + // TODO: Find a better way to handle such cases, perhaps with a library type + // representing a `&&` parameter. + return SemIR::ClangDeclSignature::PassingMode::ByRef; +} + +// Returns the passing mode to use for a virtual function parameter of the given +// type. +static auto GetVirtualFunctionParamPassingMode(clang::QualType type) + -> SemIR::ClangDeclSignature::PassingMode { + if (type->isReferenceType() && + type.getNonReferenceType().isConstQualified()) { + // For `const &`, `const &&`, use pass by value. + return SemIR::ClangDeclSignature::PassingMode::ByValue; + } + + if (type->isLValueReferenceType()) { + // For non-const `&`, use pass by reference. + return SemIR::ClangDeclSignature::PassingMode::ByRef; + } + + // Map everything else to pass by var. That's the closest match we have to C++ + // parameter semantics, and is necessary to support parameters that are passed + // by move. + return SemIR::ClangDeclSignature::PassingMode::ByVar; +} + +// Computes the signature to use for the given imported virtual function. Unlike +// with regular imported functions, we can only use a single signature here, so +// we pick one conservatively. +static auto MakeVirtualFunctionSignature( + Context& context, const clang::CXXMethodDecl* method_decl) + -> SemIR::ClangDeclSignatureId { + SemIR::ClangDeclSignature signature = { + .kind = SemIR::ClangDeclSignature::Normal, + // Include all parameters. Virtual calls do not support using default + // arguments. + .num_params = static_cast(method_decl->getNumNonObjectParams()), + .self_passing_mode = GetVirtualFunctionSelfPassingMode(method_decl), + }; + signature.passing_modes.reserve(signature.num_params); + for (auto i : llvm::seq(signature.num_params)) { + const auto* param = method_decl->getNonObjectParameter(i); + signature.passing_modes.push_back( + GetVirtualFunctionParamPassingMode(param->getType())); + } + + return context.clang_decl_signatures().Add(signature); +} + // Creates a Carbon class definition based on the information in the given Clang // class declaration, which is assumed to be for a class definition. static auto BuildClassDefinition(Context& context, @@ -879,7 +955,7 @@ static auto BuildClassDefinition(Context& context, vtable.push_back(ImportCppFunctionDecl( context, SemIR::LocId(import_ir_inst_id), const_cast(method_decl), - {.num_params = static_cast(method_decl->getNumParams())})); + MakeVirtualFunctionSignature(context, method_decl))); } vtable.truncate(num_components); auto vtable_id = context.vtables().Add( @@ -1304,47 +1380,38 @@ struct ParameterTypeInfo { }; } // namespace +// Maps a C++ parameter passing mode to a Carbon pattern kind. +static auto GetParamPatternKindForPassingMode( + SemIR::ClangDeclSignature::PassingMode mode) -> ParamPatternKind { + switch (mode) { + case SemIR::ClangDeclSignature::PassingMode::ByValue: + return ParamPatternKind::Value; + case SemIR::ClangDeclSignature::PassingMode::ByVar: + return ParamPatternKind::Var; + case SemIR::ClangDeclSignature::PassingMode::ByRef: + return ParamPatternKind::Ref; + } +} + // Given the type of a C++ function parameter, returns information about the // type to use for the corresponding Carbon parameter. // // Note that if the parameter has a type for which `IsSimpleAbiType` returns // true, we must produce a parameter type that has the same calling convention // as the C++ type. -static auto MapParameterType(Context& context, SemIR::LocId loc_id, - clang::QualType param_type) -> ParameterTypeInfo { - ParameterTypeInfo info = {.type = TypeExpr::None, - .kind = ParamPatternKind::Value}; - - // Perform some custom mapping for parameters of reference type: - // - // * `T& x` -> `ref x: T`. - // * `T&& x` -> `var x: T`. - // * `const T& x` -> `x: T`. - // * `const T&& x` -> `x: T`. +static auto MapParameterType( + Context& context, SemIR::LocId loc_id, clang::QualType param_type, + SemIR::ClangDeclSignature::PassingMode passing_mode) -> ParameterTypeInfo { if (param_type->isReferenceType()) { - clang::QualType pointee_type = param_type->getPointeeType(); - if (pointee_type.isConstQualified()) { - // TODO: Consider only doing this if `const` is the only qualifier. For - // now, any other qualifier will fail when mapping the type. - auto split_type = pointee_type.getSplitUnqualifiedType(); - split_type.Quals.removeConst(); - pointee_type = context.ast_context().getQualifiedType(split_type); - } else if (param_type->isLValueReferenceType()) { - // Lvalue references map to a `ref` pattern. - info.kind = ParamPatternKind::Ref; - } else { - // Rvalue references map to a `var` pattern. When given a value expression - // as an argument, this will result in a copy. However, if the argument is - // of class type, we will map its type to `const T`, which means overload - // resolution won't allow the call anyway, so this only permits passing - // value expressions of non-class type to a `T&&` parameter. - info.kind = ParamPatternKind::Var; - } - param_type = pointee_type; + // TODO: For now, we only remove `const`; any other qualifier will fail when + // mapping the type. + auto split_type = + param_type.getNonReferenceType().getSplitUnqualifiedType(); + split_type.Quals.removeConst(); + param_type = context.ast_context().getQualifiedType(split_type); } - - info.type = MapType(context, loc_id, param_type); - return info; + return {.type = MapType(context, loc_id, param_type), + .kind = GetParamPatternKindForPassingMode(passing_mode)}; } // Returns a block for the implicit parameters of the given function @@ -1354,19 +1421,22 @@ static auto MapParameterType(Context& context, SemIR::LocId loc_id, static auto MakeImplicitParamPatternsBlockId( Context& context, SemIR::LocId loc_id, SemIR::ImportIRInstId import_ir_inst_id, - const clang::FunctionDecl& clang_decl) -> SemIR::InstBlockId { - const auto* method_decl = dyn_cast(&clang_decl); - if (!method_decl || method_decl->isStatic() || - isa(clang_decl)) { + const clang::FunctionDecl& clang_decl, + SemIR::ClangDeclSignatureId signature_id) -> SemIR::InstBlockId { + if (!IsObjectMemberFunction(clang_decl)) { return SemIR::InstBlockId::Empty; } + const auto* method_decl = cast(&clang_decl); // Build a `self` parameter from the object parameter. BeginSubpattern(context); clang::QualType param_type = method_decl->getFunctionObjectParameterReferenceType(); - auto param_info = MapParameterType(context, loc_id, param_type); + const auto& signature = context.clang_decl_signatures().Get(signature_id); + SemIR::ClangDeclSignature::PassingMode passing_mode = + signature.self_passing_mode; + auto param_info = MapParameterType(context, loc_id, param_type, passing_mode); auto [type_inst_id, type_id] = param_info.type; SemIR::ExprRegionId type_expr_region_id = ConsumeSubpatternExpr(context, type_inst_id); @@ -1399,8 +1469,9 @@ static auto MakeImplicitParamPatternsBlockId( static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, SemIR::ImportIRInstId import_ir_inst_id, const clang::FunctionDecl& clang_decl, - SemIR::ClangDeclKey::Signature signature) + SemIR::ClangDeclSignatureId signature_id) -> SemIR::InstBlockId { + const auto& signature = context.clang_decl_signatures().Get(signature_id); llvm::SmallVector param_ids; llvm::SmallVector param_type_ids; param_ids.reserve(signature.num_params); @@ -1411,7 +1482,7 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, clang_decl.getNumNonObjectParams(), signature.num_params); const auto* function_type = clang_decl.getType()->castAs(); - for (int i : llvm::seq(signature.num_params)) { + for (auto i : llvm::seq(signature.num_params)) { const auto* param = clang_decl.getNonObjectParameter(i); clang::QualType orig_param_type = function_type->getParamType( clang_decl.hasCXXExplicitFunctionObjectParameter() + i); @@ -1425,7 +1496,8 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, // Mark the start of a region of insts, needed for the type expression // created later with the call of `ConsumeSubpatternExpr()`. BeginSubpattern(context); - auto param_info = MapParameterType(context, loc_id, param_type); + auto param_info = MapParameterType(context, loc_id, param_type, + signature.GetPassingMode(i)); auto [type_inst_id, type_id] = param_info.type; // Type expression of the binding pattern - a single-entry/single-exit // region that allows control flow in the type expression e.g. fn F(x: if C @@ -1460,12 +1532,12 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id, } switch (signature.kind) { - case SemIR::ClangDeclKey::Signature::Normal: { + case SemIR::ClangDeclSignature::Normal: { // Use the converted parameter list as-is. break; } - case SemIR::ClangDeclKey::Signature::TuplePattern: { + case SemIR::ClangDeclSignature::TuplePattern: { // Replace the parameters with a single tuple pattern containing the // converted parameter list. auto param_block_id = context.inst_blocks().Add(param_ids); @@ -1629,18 +1701,18 @@ struct FunctionSignatureInsts { static auto CreateFunctionSignatureInsts( Context& context, SemIR::LocId loc_id, SemIR::ImportIRInstId import_ir_inst_id, clang::FunctionDecl* clang_decl, - SemIR::ClangDeclKey::Signature signature) + SemIR::ClangDeclSignatureId signature_id) -> std::optional { context.full_pattern_stack().StartImplicitParamList(); auto implicit_param_patterns_id = MakeImplicitParamPatternsBlockId( - context, loc_id, import_ir_inst_id, *clang_decl); + context, loc_id, import_ir_inst_id, *clang_decl, signature_id); if (!implicit_param_patterns_id.has_value()) { return std::nullopt; } context.full_pattern_stack().EndImplicitParamList(); context.full_pattern_stack().StartExplicitParamList(); auto param_patterns_id = MakeParamPatternsBlockId( - context, loc_id, import_ir_inst_id, *clang_decl, signature); + context, loc_id, import_ir_inst_id, *clang_decl, signature_id); if (!param_patterns_id.has_value()) { return std::nullopt; } @@ -1705,12 +1777,12 @@ static auto GetFunctionName(Context& context, clang::FunctionDecl* clang_decl) static auto ImportFunction(Context& context, SemIR::LocId loc_id, SemIR::ImportIRInstId import_ir_inst_id, clang::FunctionDecl* clang_decl, - SemIR::ClangDeclKey::Signature signature) + SemIR::ClangDeclSignatureId signature_id) -> std::optional { StartFunctionSignature(context); auto function_params_insts = CreateFunctionSignatureInsts( - context, loc_id, import_ir_inst_id, clang_decl, signature); + context, loc_id, import_ir_inst_id, clang_decl, signature_id); auto [pattern_block_id, decl_block_id] = FinishFunctionSignature(context, /*check_unused=*/false); @@ -1780,9 +1852,9 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id, context.imports().push_back(decl_id); context.functions().Get(function_id).clang_decl_id = - context.clang_decls().Add( - {.key = SemIR::ClangDeclKey::ForFunctionDecl(clang_decl, signature), - .inst_id = decl_id}); + context.clang_decls().Add({.key = SemIR::ClangDeclKey::ForFunctionDecl( + clang_decl, signature_id), + .inst_id = decl_id}); return function_id; } @@ -1794,9 +1866,9 @@ static auto ImportFunction(Context& context, SemIR::LocId loc_id, // the trailing parameters. static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, clang::FunctionDecl* clang_decl, - SemIR::ClangDeclKey::Signature signature) + SemIR::ClangDeclSignatureId signature_id) -> SemIR::InstId { - auto key = SemIR::ClangDeclKey::ForFunctionDecl(clang_decl, signature); + auto key = SemIR::ClangDeclKey::ForFunctionDecl(clang_decl, signature_id); // Check if the declaration is already mapped. if (SemIR::InstId existing_inst_id = LookupClangDeclInstId(context, key); @@ -1822,8 +1894,8 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, CARBON_CHECK(clang_decl->getFunctionType()->isFunctionProtoType(), "Not Prototype function (non-C++ code)"); - auto function_id = - ImportFunction(context, loc_id, import_ir_inst_id, clang_decl, signature); + auto function_id = ImportFunction(context, loc_id, import_ir_inst_id, + clang_decl, signature_id); if (!function_id) { MarkFailedDecl(context, key); return SemIR::ErrorInst::InstId; @@ -1840,10 +1912,19 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, if (clang::FunctionDecl* thunk_clang_decl = BuildCppThunk(context, function_info)) { - if (auto thunk_function_id = ImportFunction( - context, loc_id, import_ir_inst_id, thunk_clang_decl, - {.num_params = - static_cast(thunk_clang_decl->getNumParams())})) { + SemIR::ClangDeclSignature thunk_signature; + thunk_signature.kind = SemIR::ClangDeclSignature::Normal; + thunk_signature.num_params = + static_cast(thunk_clang_decl->getNumParams()); + thunk_signature.passing_modes.assign( + thunk_signature.num_params, + SemIR::ClangDeclSignature::PassingMode::ByValue); + SemIR::ClangDeclSignatureId thunk_signature_id = + context.clang_decl_signatures().Add(std::move(thunk_signature)); + + if (auto thunk_function_id = + ImportFunction(context, loc_id, import_ir_inst_id, + thunk_clang_decl, thunk_signature_id)) { auto& thunk_function = context.functions().Get(*thunk_function_id); thunk_function.SetCppThunk(function_info.first_owning_decl_id); SemIR::InstId thunk_function_decl_id = @@ -1922,8 +2003,9 @@ static auto AddDependentUnimportedTypeDecls(Context& context, // and adds them to the given set. static auto AddDependentUnimportedFunctionDecls( Context& context, const clang::FunctionDecl& clang_decl, - SemIR::ClangDeclKey::Signature signature, ImportWorklist& worklist) + SemIR::ClangDeclSignatureId signature_id, ImportWorklist& worklist) -> void { + const auto& signature = context.clang_decl_signatures().Get(signature_id); const auto* function_type = clang_decl.getType()->castAs(); for (int i : llvm::seq(clang_decl.hasCXXExplicitFunctionObjectParameter() + @@ -1943,7 +2025,7 @@ static auto AddDependentUnimportedDecls(Context& context, clang::Decl* clang_decl = key.decl; if (auto* clang_function_decl = clang_decl->getAsFunction()) { AddDependentUnimportedFunctionDecls(context, *clang_function_decl, - key.signature, worklist); + key.signature_id, worklist); } else if (auto* type_decl = dyn_cast(clang_decl)) { if (!isa(clang_decl)) { AddDependentUnimportedTypeDecls( @@ -2063,7 +2145,7 @@ static auto ImportDeclAfterDependencies(Context& context, SemIR::LocId loc_id, clang::Decl* clang_decl = key.decl; if (auto* clang_function_decl = clang_decl->getAsFunction()) { return ImportFunctionDecl(context, loc_id, clang_function_decl, - key.signature); + key.signature_id); } if (auto* clang_namespace_decl = dyn_cast(clang_decl)) { return ImportNamespaceDecl(context, clang_namespace_decl); diff --git a/toolchain/check/cpp/import.h b/toolchain/check/cpp/import.h index 096f1fb19095..f94a04e0bffa 100644 --- a/toolchain/check/cpp/import.h +++ b/toolchain/check/cpp/import.h @@ -18,6 +18,12 @@ namespace Carbon::Check { +// Returns whether the given function is an object member function. This is true +// if it's a non-static member function and not a constructor. Object member +// functions correspond to Carbon functions with a `self` parameter. +// TODO: Find a better home for this function. +auto IsObjectMemberFunction(const clang::FunctionDecl& decl) -> bool; + // Generates a C++ header that includes the imported cpp files, parses it, // generates the AST from it and links `SemIR::File` to it. Reports C++ errors // and warnings. If successful, adds a `Cpp` namespace. @@ -59,11 +65,11 @@ auto ImportCppDecl(Context& context, SemIR::LocId loc_id, // imported, returns the mapped instruction. inline auto ImportCppFunctionDecl(Context& context, SemIR::LocId loc_id, clang::FunctionDecl* clang_decl, - SemIR::ClangDeclKey::Signature signature) + SemIR::ClangDeclSignatureId signature_id) -> SemIR::InstId { return ImportCppDecl( context, loc_id, - SemIR::ClangDeclKey::ForFunctionDecl(clang_decl, signature)); + SemIR::ClangDeclKey::ForFunctionDecl(clang_decl, signature_id)); } // Imports a function declaration from Clang to Carbon. If successful, returns diff --git a/toolchain/check/cpp/operators.cpp b/toolchain/check/cpp/operators.cpp index b3b87ba1ed37..17d497d6f857 100644 --- a/toolchain/check/cpp/operators.cpp +++ b/toolchain/check/cpp/operators.cpp @@ -19,6 +19,7 @@ #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" #include "toolchain/sem_ir/builtin_function_kind.h" +#include "toolchain/sem_ir/clang_decl.h" #include "toolchain/sem_ir/cpp_initializer_list.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" @@ -285,44 +286,67 @@ static auto MakeCppStdInitializerListMake(Context& context, SemIR::LocId loc_id, static auto GetConversionSignatureToImport( Context& context, SemIR::InstId source_id, clang::InitializationSequence::StepKind step_kind, - clang::FunctionDecl* function_decl) -> SemIR::ClangDeclKey::Signature { + clang::FunctionDecl* function_decl, clang::DeclAccessPair found_decl, + clang::Expr* arg_expr) -> SemIR::ClangDeclSignatureId { + auto signature_kind = SemIR::ClangDeclSignature::Normal; + clang::Expr* self_expr = nullptr; + llvm::ArrayRef arg_exprs(arg_expr); + // If we're performing a constructor initialization from a list, form a // function signature that takes a single tuple or struct pattern // instead of a function signature with one parameter per C++ parameter. if (step_kind == clang::InitializationSequence::SK_ConstructorInitializationFromList) { + // Initialization from a tuple `(a, b, c)` results in a constructor + // function that takes a tuple pattern: + // + // fn Class.Class((a: A, b: B, c: C)) -> Class; + // // The source type should always be a tuple type, because we don't support // C++ initialization from struct types. auto tuple_type = context.types().TryGetAs( context.insts().Get(source_id).type_id()); CARBON_CHECK(tuple_type, "List initialization from non-tuple type"); - - // Initialization from a tuple `(a, b, c)` results in a constructor - // function that takes a tuple pattern: - // - // fn Class.Class((a: A, b: B, c: C)) -> Class; - return { - .kind = SemIR::ClangDeclKey::Signature::Kind::TuplePattern, - .num_params = static_cast( - context.inst_blocks().Get(tuple_type->type_elements_id).size())}; + arg_exprs = cast(arg_expr)->inits(); + signature_kind = SemIR::ClangDeclSignature::TuplePattern; } - // Any other initialization using a constructor is calling a converting - // constructor: - // - // fn Class.Class(a: A) -> Class; + // In order to determine how to map the parameters, we need to build the + // conversion sequence(s) again. Clang already threw them away. The only way + // to do this is to "redo" overload resolution with our single candidate. + clang::OverloadCandidateSet candidates( + function_decl->getLocation(), + clang::OverloadCandidateSet::CSK_InitByUserDefinedConversion); + if (isa(function_decl)) { - return {.kind = SemIR::ClangDeclKey::Signature::Kind::Normal, - .num_params = 1}; + // This is either tuple list initialization as described above or a + // constructor call: + // + // fn Class.Class(a: A) -> Class; + context.clang_sema().AddOverloadCandidate(function_decl, found_decl, + arg_exprs, candidates); + } else { + // Otherwise, the initialization is calling a conversion function + // `Source::operator Dest`: + // + // fn Source.[self: Source]() -> Dest; + auto* conversion_decl = cast(function_decl); + self_expr = arg_expr; + arg_exprs = {}; + context.clang_sema().AddMethodCandidate( + conversion_decl, found_decl, conversion_decl->getParent(), + self_expr->getType(), self_expr->Classify(context.ast_context()), + arg_exprs, candidates); } - // Otherwise, the initialization is calling a conversion function - // `Source::operator Dest`: - // - // fn Source.[self: Source]() -> Dest; - CARBON_CHECK(isa(function_decl)); - return {.kind = SemIR::ClangDeclKey::Signature::Kind::Normal, - .num_params = 0}; + clang::OverloadCandidateSet::iterator best; + auto result = candidates.BestViableFunction( + context.clang_sema(), function_decl->getLocation(), best); + CARBON_CHECK(result == clang::OverloadingResult::OR_Success || + result == clang::OverloadingResult::OR_Deleted); + + return ComputeClangDeclSignatureFromBestViableFunction( + context, best, self_expr, arg_exprs, signature_kind); } static auto LookupCppConversion(Context& context, SemIR::LocId loc_id, @@ -402,10 +426,12 @@ static auto LookupCppConversion(Context& context, SemIR::LocId loc_id, sema.MarkFunctionReferenced(loc, step.Function.Function); - auto signature = GetConversionSignatureToImport( - context, source_id, step.Kind, step.Function.Function); + SemIR::ClangDeclSignatureId signature_id = + GetConversionSignatureToImport(context, source_id, step.Kind, + step.Function.Function, + step.Function.FoundDecl, arg_expr); auto result_id = ImportCppFunctionDecl( - context, loc_id, step.Function.Function, signature); + context, loc_id, step.Function.Function, signature_id); if (auto fn_decl = context.insts().TryGetAsWithId( result_id)) { CheckCppOverloadAccess(context, loc_id, step.Function.FoundDecl, @@ -637,14 +663,18 @@ static auto FindClangOperator(Context& context, SemIR::LocId loc_id, sema.MarkFunctionReferenced(loc, best_viable_fn->Function); // If this is an operator method, the first arg will be used as self. - int32_t num_params = arg_exprs.size(); - if (isa(best_viable_fn->Function)) { - --num_params; + clang::Expr* self_expr = nullptr; + auto arg_exprs_for_signature = arg_exprs; + if (IsObjectMemberFunction(*best_viable_fn->Function)) { + self_expr = arg_exprs_for_signature.consume_front(); } - auto result_id = - ImportCppFunctionDecl(context, loc_id, best_viable_fn->Function, - {.num_params = num_params}); + SemIR::ClangDeclSignatureId signature_id = + ComputeClangDeclSignatureFromBestViableFunction( + context, best_viable_fn, self_expr, arg_exprs_for_signature); + + auto result_id = ImportCppFunctionDecl( + context, loc_id, best_viable_fn->Function, signature_id); if (result_id != SemIR::ErrorInst::InstId) { CheckCppOverloadAccess( context, loc_id, best_viable_fn->FoundDecl, diff --git a/toolchain/check/cpp/overload_resolution.cpp b/toolchain/check/cpp/overload_resolution.cpp index e55c4cfe33a4..99419dfd8a33 100644 --- a/toolchain/check/cpp/overload_resolution.cpp +++ b/toolchain/check/cpp/overload_resolution.cpp @@ -4,6 +4,7 @@ #include "toolchain/check/cpp/overload_resolution.h" +#include "clang/AST/DeclCXX.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Sema.h" @@ -68,9 +69,8 @@ static auto AddOverloadCandidates( auto* fn_decl = template_decl ? template_decl->getTemplatedDecl() : cast(decl); - auto* method_decl = dyn_cast(fn_decl); - if (method_decl && !method_decl->isStatic() && - !isa(fn_decl)) { + if (IsObjectMemberFunction(*fn_decl)) { + auto* method_decl = cast(fn_decl); clang::QualType self_type; clang::Expr::Classification self_classification; if (self_arg) { @@ -130,6 +130,139 @@ auto CheckCppOverloadAccess( .highest_allowed_access = allowed_access_kind}); } +// Computes the passing mode for a C++ function parameter that is a reference. +static auto ComputePassingModeForReferenceBinding( + const clang::StandardConversionSequence& scs) + -> SemIR::ClangDeclSignature::PassingMode { + CARBON_CHECK(scs.ReferenceBinding); + auto pointee_type = scs.getToType(2); + if (pointee_type.isConstQualified() || + (scs.IsLvalueReference && scs.BindsToRvalue)) { + // Reference to const is always mapped to Carbon pass by value. A non-const + // lvalue reference bound to an rvalue only happens when initializing an + // object parameter with no ref-qualifier from an rvalue, which we also + // model as pass-by-value. + return SemIR::ClangDeclSignature::PassingMode::ByValue; + } + // Rvalue reference to non-const is passed as a `var` to force a copy or move + // in the caller. Lvalue reference to non-const is passed by reference. + return scs.IsLvalueReference ? SemIR::ClangDeclSignature::PassingMode::ByRef + : SemIR::ClangDeclSignature::PassingMode::ByVar; +} + +// Returns whether move-construction of type `type` is known to be equivalent to +// a copy. If so, it's safe to map C++ pass-by-value into Carbon pass-by-value +// instead of pass-by-var. +static auto IsMoveEquivalentToCopy(clang::QualType type) { + // We can pass by copy instead of by move if: + // - The type is not a class type. + auto* record_decl = type->getAsCXXRecordDecl(); + if (!record_decl) { + return true; + } + + // - The move constructor is defaulted and deleted or non-existent, in + // which case overload resolution for a move will call the copy + // constructor. + if (!record_decl->hasMoveConstructor() || + (!record_decl->hasUserDeclaredMoveConstructor() && + record_decl->defaultedMoveConstructorIsDeleted())) { + return true; + } + + // - Both move and copy are trivial and not deleted, in which case they + // are equivalent. + if (record_decl->hasTrivialMoveConstructor() && + !record_decl->defaultedMoveConstructorIsDeleted() && + record_decl->hasTrivialCopyConstructor() && + !record_decl->defaultedCopyConstructorIsDeleted()) { + return true; + } + + // Otherwise we need a move, so we pass by var. + return false; +} + +auto GetPassingModeForCppParameter(const clang::ImplicitConversionSequence& ics, + const clang::Expr* arg_expr) + -> SemIR::ClangDeclSignature::PassingMode { + if (ics.isStandard()) { + const auto& scs = ics.Standard; + if (scs.ReferenceBinding) { + return ComputePassingModeForReferenceBinding(scs); + } + + // Most standard conversions can be mapped to Carbon pass by value. The + // exception is where the source is an initializing expression of record + // type, which we map to pass by var, unless a copy would do the same thing. + if (arg_expr->isXValue() && !IsMoveEquivalentToCopy(arg_expr->getType())) { + return SemIR::ClangDeclSignature::PassingMode::ByVar; + } + + return SemIR::ClangDeclSignature::PassingMode::ByValue; + } + + if (ics.isUserDefined()) { + const auto& ucs = ics.UserDefined; + if (ucs.After.ReferenceBinding) { + return ComputePassingModeForReferenceBinding(ucs.After); + } + + const auto* ctor = + dyn_cast_or_null(ucs.ConversionFunction); + if (ctor && ctor->isCopyConstructor()) { + // Overload resolution wanted to call a copy constructor to initialize + // this parameter. Pass by value instead; we'll copy in the thunk. + return SemIR::ClangDeclSignature::PassingMode::ByValue; + } + + // We're calling a user-defined conversion, so we're performing + // initialization. Pass by move unless the type being initialized doesn't + // distinguish moves and copies. + return IsMoveEquivalentToCopy(ucs.After.getToType(2)) + ? SemIR::ClangDeclSignature::PassingMode::ByValue + : SemIR::ClangDeclSignature::PassingMode::ByVar; + } + + // TODO: Support ellipsis conversion sequences. + CARBON_FATAL("Unexpected kind of implicit conversion sequence"); +} + +// Computes the signature for a C++ function candidate based on the conversions +// performed on the arguments. +auto ComputeClangDeclSignatureFromBestViableFunction( + Context& context, clang::OverloadCandidateSet::iterator candidate, + clang::Expr* self_expr, llvm::ArrayRef arg_exprs, + SemIR::ClangDeclSignature::Kind kind) -> SemIR::ClangDeclSignatureId { + SemIR::ClangDeclSignature signature; + signature.kind = kind; + signature.num_params = static_cast(arg_exprs.size()); + signature.passing_modes.reserve(signature.num_params); + + for (auto [i, arg_expr] : llvm::enumerate(arg_exprs)) { + // Compute which conversion sequence corresponds to this argument. + // TODO: Clang should expose a way to compute this. + int conversion_index = i; + if (auto* method = dyn_cast(candidate->Function)) { + if (method->isStatic()) { + // Static methods get an object parameter conversion at index 0, even + // though there's no argument. + ++conversion_index; + } + } + + signature.passing_modes.push_back(GetPassingModeForCppParameter( + candidate->Conversions[conversion_index], arg_expr)); + } + + if (IsObjectMemberFunction(*candidate->Function)) { + signature.self_passing_mode = + GetPassingModeForCppParameter(candidate->Conversions[0], self_expr); + } + + return context.clang_decl_signatures().Add(std::move(signature)); +} + auto PerformCppOverloadResolution( Context& context, SemIR::LocId loc_id, const SemIR::CppOverloadSet& overload_set, @@ -179,9 +312,12 @@ auto PerformCppOverloadResolution( case clang::OverloadingResult::OR_Success: { CARBON_CHECK(best_viable_fn->Function); CARBON_CHECK(!best_viable_fn->RewriteKind); + SemIR::ClangDeclSignatureId signature_id = + ComputeClangDeclSignatureFromBestViableFunction( + context, best_viable_fn, self_expr, arg_exprs); + SemIR::InstId result_id = ImportCppFunctionDecl( - context, loc_id, best_viable_fn->Function, - {.num_params = static_cast(arg_exprs.size())}); + context, loc_id, best_viable_fn->Function, signature_id); if (result_id != SemIR::ErrorInst::InstId) { CheckCppOverloadAccess( context, loc_id, best_viable_fn->FoundDecl, diff --git a/toolchain/check/cpp/overload_resolution.h b/toolchain/check/cpp/overload_resolution.h index ca8f7bb4d53b..39453a780819 100644 --- a/toolchain/check/cpp/overload_resolution.h +++ b/toolchain/check/cpp/overload_resolution.h @@ -20,6 +20,18 @@ auto CheckCppOverloadAccess( SemIR::KnownInstId overload_inst_id, SemIR::NameScopeId parent_scope_id = SemIR::NameScopeId::None) -> void; +// Returns the passing mode to use for a parameter given the implicit +// conversion sequence and the argument expression. +auto GetPassingModeForCppParameter(const clang::ImplicitConversionSequence& ics, + const clang::Expr* arg_expr) + -> SemIR::ClangDeclSignature::PassingMode; + +auto ComputeClangDeclSignatureFromBestViableFunction( + Context& context, clang::OverloadCandidateSet::iterator candidate, + clang::Expr* self_expr, llvm::ArrayRef arg_exprs, + SemIR::ClangDeclSignature::Kind kind = SemIR::ClangDeclSignature::Normal) + -> SemIR::ClangDeclSignatureId; + // Resolves which function to call using Clang overload resolution. Returns an // instruction referring to that function, or an error instruction if overload // resolution failed. diff --git a/toolchain/check/cpp/thunk.cpp b/toolchain/check/cpp/thunk.cpp index aaf7c1b4bbff..5e24b1ba16c3 100644 --- a/toolchain/check/cpp/thunk.cpp +++ b/toolchain/check/cpp/thunk.cpp @@ -15,6 +15,7 @@ #include "toolchain/check/control_flow.h" #include "toolchain/check/convert.h" #include "toolchain/check/cpp/context.h" +#include "toolchain/check/cpp/import.h" #include "toolchain/check/literal.h" #include "toolchain/check/type.h" #include "toolchain/check/type_completion.h" @@ -74,23 +75,42 @@ static auto GetGlobalDecl(const clang::FunctionDecl* decl) static auto GenerateThunkMangledName( clang::MangleContext& mangle_context, const clang::FunctionDecl& callee_function_decl, - SemIR::ClangDeclKey::Signature::Kind signature_kind, int num_params) - -> std::string { + const SemIR::ClangDeclSignature& signature) -> std::string { RawStringOstream mangled_name_stream; mangle_context.mangleName(GetGlobalDecl(&callee_function_decl), mangled_name_stream); - switch (signature_kind) { - case SemIR::ClangDeclKey::Signature::Normal: + switch (signature.kind) { + case SemIR::ClangDeclSignature::Normal: mangled_name_stream << ".carbon_thunk"; break; - case SemIR::ClangDeclKey::Signature::TuplePattern: + case SemIR::ClangDeclSignature::TuplePattern: mangled_name_stream << ".carbon_thunk_tuple"; break; } - if (num_params != - static_cast(callee_function_decl.getNumNonObjectParams())) { - mangled_name_stream << num_params; + // Append passing modes. + // TODO: Pick one "likely" set of passing modes for the function and omit the + // suffix for that signature. + mangled_name_stream << "."; + auto append_mode = [&](SemIR::ClangDeclSignature::PassingMode mode) { + switch (mode) { + case SemIR::ClangDeclSignature::PassingMode::ByValue: + mangled_name_stream << "_"; + break; + case SemIR::ClangDeclSignature::PassingMode::ByVar: + mangled_name_stream << "v"; + break; + case SemIR::ClangDeclSignature::PassingMode::ByRef: + mangled_name_stream << "r"; + break; + } + }; + + if (IsObjectMemberFunction(callee_function_decl)) { + append_mode(signature.self_passing_mode); + } + for (auto mode : signature.passing_modes) { + append_mode(mode); } return mangled_name_stream.TakeStr(); @@ -143,15 +163,15 @@ namespace { // Information about the callee of a thunk. struct CalleeFunctionInfo { explicit CalleeFunctionInfo(clang::FunctionDecl* decl, - SemIR::ClangDeclKey::Signature signature) + const SemIR::ClangDeclSignature* signature) : decl(decl), - signature_kind(signature.kind), - num_params(signature.num_params + + signature(signature), + num_params(signature->num_params + decl->hasCXXExplicitFunctionObjectParameter()) { auto& ast_context = decl->getASTContext(); const auto* method_decl = dyn_cast(decl); bool is_ctor = isa(decl); - has_object_parameter = method_decl && !method_decl->isStatic() && !is_ctor; + has_object_parameter = IsObjectMemberFunction(*decl); if (has_object_parameter && method_decl->isImplicitObjectMemberFunction()) { implicit_object_parameter_type = method_decl->getFunctionObjectParameterReferenceType(); @@ -195,8 +215,8 @@ struct CalleeFunctionInfo { // The callee function. clang::FunctionDecl* decl; - // The kind of function signature being imported. - SemIR::ClangDeclKey::Signature::Kind signature_kind; + // The signature of the function being imported. + const SemIR::ClangDeclSignature* signature; // The number of explicit parameters to import. This may be less than the // number of parameters that the function has if default arguments are being @@ -229,25 +249,28 @@ auto IsCppThunkRequired(Context& context, const SemIR::Function& function) } const auto& decl_info = context.clang_decls().Get(function.clang_decl_id); + const auto& signature = + context.clang_decl_signatures().Get(decl_info.key.signature_id); auto* decl = cast(decl_info.key.decl); - if (decl_info.key.signature.kind != SemIR::ClangDeclKey::Signature::Normal || - decl_info.key.signature.num_params != - static_cast(decl->getNumNonObjectParams())) { + if (signature.kind != SemIR::ClangDeclSignature::Normal || + signature.num_params != static_cast(decl->getNumNonObjectParams())) { // We require a thunk if the number of parameters we want isn't all of them. // This happens if default arguments are in use, or (eventually) when // calling a varargs function. return true; } - CalleeFunctionInfo callee_info(decl, decl_info.key.signature); + CalleeFunctionInfo callee_info(decl, &signature); if (!callee_info.has_simple_return_type) { return true; } auto& ast_context = context.ast_context(); if (callee_info.has_implicit_object_parameter() && - !IsSimpleAbiType(ast_context, callee_info.implicit_object_parameter_type, - /*for_parameter=*/true)) { + (!IsSimpleAbiType(ast_context, callee_info.implicit_object_parameter_type, + /*for_parameter=*/true) || + signature.self_passing_mode == + SemIR::ClangDeclSignature::PassingMode::ByVar)) { return true; } @@ -255,7 +278,9 @@ auto IsCppThunkRequired(Context& context, const SemIR::Function& function) decl->getType()->castAs(); for (int i : llvm::seq(decl->getNumParams())) { if (!IsSimpleAbiType(ast_context, function_type->getParamType(i), - /*for_parameter=*/true)) { + /*for_parameter=*/true) || + signature.GetPassingMode(i) == + SemIR::ClangDeclSignature::PassingMode::ByVar) { return true; } } @@ -437,10 +462,8 @@ static auto CreateThunkFunctionDecl( // Set asm(".carbon_thunk"). thunk_function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( ast_context, - GenerateThunkMangledName( - context.cpp_context()->clang_mangle_context(), *callee_info.decl, - callee_info.signature_kind, - callee_info.num_params - callee_info.has_explicit_object_parameter()), + GenerateThunkMangledName(context.cpp_context()->clang_mangle_context(), + *callee_info.decl, *callee_info.signature), clang_loc)); // Set function declaration type source info. @@ -453,11 +476,10 @@ static auto CreateThunkFunctionDecl( // Builds a reference to the given parameter thunk. If `type` is specified, that // is the callee parameter type that's being held by the parameter, and // conversions will be performed as necessary to recover a value of that type. -static auto BuildThunkParamRef(clang::Sema& sema, - clang::FunctionDecl* thunk_function_decl, - unsigned thunk_index, - clang::QualType type = clang::QualType()) - -> clang::Expr* { +static auto BuildThunkParamRef( + clang::Sema& sema, clang::FunctionDecl* thunk_function_decl, + unsigned thunk_index, SemIR::ClangDeclSignature::PassingMode passing_mode, + clang::QualType type = clang::QualType()) -> clang::Expr* { clang::ParmVarDecl* thunk_param = thunk_function_decl->getParamDecl(thunk_index); clang::SourceLocation clang_loc = thunk_param->getLocation(); @@ -472,15 +494,10 @@ static auto BuildThunkParamRef(clang::Sema& sema, call_arg = deref_result.get(); } - // Cast to an rvalue when initializing an rvalue reference. The validity of - // the initialization of the reference should be validated by the caller of - // the thunk. - // - // TODO: Consider inserting a cast to an rvalue in more cases. Note that we - // currently pass pointers to non-temporary objects as the argument when - // calling a thunk, so we'll need to either change that or generate - // different thunks depending on whether we're moving from each parameter. - if (!type.isNull() && type->isRValueReferenceType()) { + // Cast to an xvalue when using pass-by-`var` or when initializing an rvalue + // reference (which might be passed by value if it's const-qualified). + if (passing_mode == SemIR::ClangDeclSignature::PassingMode::ByVar || + thunk_param->getType()->isRValueReferenceType()) { call_arg = clang::ImplicitCastExpr::Create( sema.getASTContext(), call_arg->getType(), clang::CK_NoOp, call_arg, nullptr, clang::ExprValueKind::VK_XValue, clang::FPOptionsOverride()); @@ -497,6 +514,7 @@ static auto BuildParamRefForCalleeArg(clang::Sema& sema, unsigned thunk_index = callee_info.GetThunkParamIndex(callee_index); return BuildThunkParamRef( sema, thunk_function_decl, thunk_index, + callee_info.signature->GetPassingMode(callee_index), callee_info.decl->getParamDecl(callee_index)->getType()); } @@ -538,8 +556,9 @@ static auto BuildThunkBody(CppContext& cpp_context, clang::Sema& sema, clang::QualType object_param_type = cast(callee_info.decl) ->getFunctionObjectParameterReferenceType(); - auto* object_param_ref = - BuildThunkParamRef(sema, thunk_function_decl, 0, object_param_type); + auto* object_param_ref = BuildThunkParamRef( + sema, thunk_function_decl, 0, callee_info.signature->self_passing_mode, + object_param_type); constexpr bool IsArrow = false; auto object = sema.PerformMemberExprBaseConversion(object_param_ref, IsArrow); @@ -597,7 +616,8 @@ static auto BuildThunkBody(CppContext& cpp_context, clang::Sema& sema, } auto* return_object_addr = BuildThunkParamRef( - sema, thunk_function_decl, callee_info.GetThunkReturnParamIndex()); + sema, thunk_function_decl, callee_info.GetThunkReturnParamIndex(), + SemIR::ClangDeclSignature::PassingMode::ByValue); auto return_type = callee_info.effective_return_type.getNonReferenceType(); auto* return_type_info = sema.Context.getTrivialTypeSourceInfo(return_type, clang_loc); @@ -635,8 +655,9 @@ auto BuildCppThunk(Context& context, const SemIR::Function& callee_function) // shouldn't consider it here. However, to do that, we would need to cache the // thunks we build so that we don't build the same thunk multiple times if // it's used with multiple different signature kinds. - CalleeFunctionInfo callee_info(callee_function_decl, - clang_decl_key.signature); + const auto& signature = + context.clang_decl_signatures().Get(clang_decl_key.signature_id); + CalleeFunctionInfo callee_info(callee_function_decl, &signature); // Build the thunk function declaration. auto thunk_param_types = diff --git a/toolchain/check/cpp/type_mapping.cpp b/toolchain/check/cpp/type_mapping.cpp index 0ddfd9c84ef7..9c2ed4a29603 100644 --- a/toolchain/check/cpp/type_mapping.cpp +++ b/toolchain/check/cpp/type_mapping.cpp @@ -518,7 +518,10 @@ static auto InventPrimitiveClangArg(Context& context, FormInfo form) case SemIR::ExprCategory::ReprInitializing: case SemIR::ExprCategory::InPlaceInitializing: - value_kind = clang::ExprValueKind::VK_PRValue; + // A Carbon initializing expression is much more similar to a C++ prvalue + // than a C++ xvalue, but we encode it as an xvalue expression to request + // that it be passed through the thunk by move rather than by copy. + value_kind = clang::ExprValueKind::VK_XValue; break; case SemIR::ExprCategory::Mixed: diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index c9d13dfaf4ab..d791ba879b5a 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -2521,7 +2521,7 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, resolver.import_functions().Get(inst.function_id).first_decl_id()); auto specific_data = GetLocalSpecificData(resolver, inst.specific_id); - if (resolver.HasNewWork() || !fn_val_id.has_value()) { + if (resolver.HasNewWork()) { return ResolveResult::Retry(); } auto fn_type_id = resolver.local_insts().Get(fn_val_id).type_id(); @@ -4150,9 +4150,11 @@ static auto TryResolveInstCanonical(ImportRefResolver& resolver, CARBON_CHECK(!const_id.has_value()); auto inst_constant_id = resolver.import_constant_values().Get(inst_id); - if (!inst_constant_id.has_value() || !inst_constant_id.is_constant()) { + if (!inst_constant_id.is_constant()) { // TODO: Import of non-constant BindNames happens when importing `let` // declarations. + CARBON_CHECK(resolver.import_insts().Is(inst_id), + "TryResolveInst on non-constant instruction {0}", inst_id); return ResolveResult::Done(SemIR::ConstantId::NotConstant); } diff --git a/toolchain/check/testdata/basics/raw_sem_ir/builtins.carbon b/toolchain/check/testdata/basics/raw_sem_ir/builtins.carbon index d2adf8f18a65..3dc77d6d450b 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/builtins.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/builtins.carbon @@ -20,6 +20,7 @@ // CHECK:STDOUT: 'import_ir(Cpp)': {decl_id: inst, is_export: false} // CHECK:STDOUT: import_ir_insts: {} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {}} // CHECK:STDOUT: entity_names: {} diff --git a/toolchain/check/testdata/basics/raw_sem_ir/bundle.carbon b/toolchain/check/testdata/basics/raw_sem_ir/bundle.carbon index 55d4564cbcd3..9bb798af94ad 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/bundle.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/bundle.carbon @@ -34,6 +34,7 @@ fn F(Form:! Core.Form()) ->? Form; // CHECK:STDOUT: import_ir_inst4: {ir_id: import_ir70000003, inst_id: inst50000010} // CHECK:STDOUT: import_ir_inst5: {ir_id: import_ir70000003, inst_id: inst50000011} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name(Core): inst70000011, name0: inst7000003B}} // CHECK:STDOUT: name_scope70000001: {inst: inst70000011, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name1: inst70000016}} diff --git a/toolchain/check/testdata/basics/raw_sem_ir/cpp_interop.carbon b/toolchain/check/testdata/basics/raw_sem_ir/cpp_interop.carbon index 73120bef862d..5bceae461246 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/cpp_interop.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/cpp_interop.carbon @@ -53,15 +53,18 @@ fn G(x: Cpp.X) { // CHECK:STDOUT: import_ir_inst3: {ir_id: import_ir(Cpp), clang_source_loc_id: clang_source_loc50000003} // CHECK:STDOUT: import_ir_inst4: {ir_id: import_ir(Cpp), clang_source_loc_id: clang_source_loc50000004} // CHECK:STDOUT: clang_decls: -// CHECK:STDOUT: clang_decl_id50000000: {key: "namespace Carbon {\n}", inst_id: instF} -// CHECK:STDOUT: clang_decl_id50000001: {key: "", inst_id: inst50000011} -// CHECK:STDOUT: clang_decl_id50000002: {key: "struct X {}", inst_id: inst50000013} -// CHECK:STDOUT: clang_decl_id50000003: {key: "X * _Nonnull p", inst_id: inst50000022} -// CHECK:STDOUT: clang_decl_id50000004: {key: {decl: "void f(X x = {})", kind: normal, num_params: 0}, inst_id: inst5000002D} -// CHECK:STDOUT: clang_decl_id50000005: {key: {decl: "inline void f__carbon_thunk()", kind: normal, num_params: 0}, inst_id: inst50000030} -// CHECK:STDOUT: clang_decl_id50000006: {key: {decl: "void f(X x = {})", kind: normal, num_params: 1}, inst_id: inst5000003B} -// CHECK:STDOUT: clang_decl_id50000007: {key: {decl: "inline void f__carbon_thunk(X * _Nonnull x)", kind: normal, num_params: 1}, inst_id: inst50000043} -// CHECK:STDOUT: clang_decl_id50000008: {key: "X * _Nonnull global", inst_id: inst5000004E} +// CHECK:STDOUT: clang_decl_id50000000: {key: {decl: "namespace Carbon {\n}"}, inst_id: instF} +// CHECK:STDOUT: clang_decl_id50000001: {key: {decl: ""}, inst_id: inst50000011} +// CHECK:STDOUT: clang_decl_id50000002: {key: {decl: "struct X {}"}, inst_id: inst50000013} +// CHECK:STDOUT: clang_decl_id50000003: {key: {decl: "X * _Nonnull p"}, inst_id: inst50000022} +// CHECK:STDOUT: clang_decl_id50000004: {key: {decl: "void f(X x = {})", clang_decl_signature_id: clang_decl_signature_id50000000}, inst_id: inst5000002D} +// CHECK:STDOUT: clang_decl_id50000005: {key: {decl: "inline void f__carbon_thunk()", clang_decl_signature_id: clang_decl_signature_id50000000}, inst_id: inst50000030} +// CHECK:STDOUT: clang_decl_id50000006: {key: {decl: "void f(X x = {})", clang_decl_signature_id: clang_decl_signature_id50000001}, inst_id: inst5000003B} +// CHECK:STDOUT: clang_decl_id50000007: {key: {decl: "inline void f__carbon_thunk(X * _Nonnull x)", clang_decl_signature_id: clang_decl_signature_id50000001}, inst_id: inst50000043} +// CHECK:STDOUT: clang_decl_id50000008: {key: {decl: "X * _Nonnull global"}, inst_id: inst5000004E} +// CHECK:STDOUT: clang_decl_signatures: +// CHECK:STDOUT: clang_decl_signature_id50000000: {kind: normal, num_params: 0} +// CHECK:STDOUT: clang_decl_signature_id50000001: {kind: normal, num_params: 1, modes: [value]} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name(Cpp): inst50000011, name0: inst5000001C}} // CHECK:STDOUT: name_scope50000001: {inst: inst50000011, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name2: inst50000013, name3: inst5000002A, name4: inst5000004E}} diff --git a/toolchain/check/testdata/basics/raw_sem_ir/multifile.carbon b/toolchain/check/testdata/basics/raw_sem_ir/multifile.carbon index 449f82b7ead4..e95d95fd521e 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/multifile.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/multifile.carbon @@ -37,6 +37,7 @@ fn B() { // CHECK:STDOUT: 'import_ir(Cpp)': {decl_id: inst, is_export: false} // CHECK:STDOUT: import_ir_insts: {} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name0: inst50000010}} // CHECK:STDOUT: entity_names: {} @@ -141,6 +142,7 @@ fn B() { // CHECK:STDOUT: import_ir_inst0: {ir_id: import_ir70000002, inst_id: inst50000010} // CHECK:STDOUT: import_ir_inst1: {ir_id: import_ir70000002, inst_id: inst50000010} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name1: inst70000011, name0: inst70000012}} // CHECK:STDOUT: name_scope70000001: {inst: inst70000011, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name1: inst70000017}} diff --git a/toolchain/check/testdata/basics/raw_sem_ir/multifile_with_textual_ir.carbon b/toolchain/check/testdata/basics/raw_sem_ir/multifile_with_textual_ir.carbon index a977a4cbe7d2..3fb18a8a4c81 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/multifile_with_textual_ir.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/multifile_with_textual_ir.carbon @@ -37,6 +37,7 @@ fn B() { // CHECK:STDOUT: 'import_ir(Cpp)': {decl_id: inst, is_export: false} // CHECK:STDOUT: import_ir_insts: {} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name0: inst50000010}} // CHECK:STDOUT: entity_names: {} @@ -160,6 +161,7 @@ fn B() { // CHECK:STDOUT: import_ir_inst0: {ir_id: import_ir70000002, inst_id: inst50000010} // CHECK:STDOUT: import_ir_inst1: {ir_id: import_ir70000002, inst_id: inst50000010} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name1: inst70000011, name0: inst70000012}} // CHECK:STDOUT: name_scope70000001: {inst: inst70000011, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name1: inst70000017}} diff --git a/toolchain/check/testdata/basics/raw_sem_ir/non_core_interfaces.carbon b/toolchain/check/testdata/basics/raw_sem_ir/non_core_interfaces.carbon index 860fa0336319..5289c6e6583d 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/non_core_interfaces.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/non_core_interfaces.carbon @@ -46,6 +46,7 @@ fn UseLocalCopy[T:! Copy](_: T.T1, _: T.T2) {} // CHECK:STDOUT: 'import_ir(Cpp)': {decl_id: inst, is_export: false} // CHECK:STDOUT: import_ir_insts: {} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name1: inst60000010}} // CHECK:STDOUT: name_scope60000001: {inst: inst60000010, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name(SelfType): inst60000012}} @@ -210,6 +211,7 @@ fn UseLocalCopy[T:! Copy](_: T.T1, _: T.T2) {} // CHECK:STDOUT: import_ir_instB: {ir_id: import_ir50000002, inst_id: inst6000001C} // CHECK:STDOUT: import_ir_instC: {ir_id: import_ir50000002, inst_id: inst6000001C} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name0: inst50000011, name1: inst50000012, name4: inst50000060, name7: inst50000095}} // CHECK:STDOUT: name_scope50000001: {inst: inst50000011, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name6: inst50000025}} diff --git a/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon b/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon index 4f41631e4231..eb6c9e5590b2 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/one_file.carbon @@ -255,6 +255,7 @@ fn Foo[T:! type](p: T*) -> (T*, ()) { // CHECK:STDOUT: import_ir_instD6: {ir_id: import_ir78000004, inst_id: inst70000259} // CHECK:STDOUT: import_ir_instD7: {ir_id: import_ir78000004, inst_id: inst7000025A} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name(Core): inst78000011, name0: inst7800003E}} // CHECK:STDOUT: name_scope78000001: {inst: inst78000011, parent_scope: name_scope0, has_error: false, extended_scopes: [], names: {name3: inst7800004E}} diff --git a/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon b/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon index 497de519c45e..9480eba1d7c8 100644 --- a/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon +++ b/toolchain/check/testdata/basics/raw_sem_ir/one_file_with_textual_ir.carbon @@ -28,6 +28,7 @@ fn Foo(n: ()) -> ((), ()) { // CHECK:STDOUT: 'import_ir(Cpp)': {decl_id: inst, is_export: false} // CHECK:STDOUT: import_ir_insts: {} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {name0: inst5000002A}} // CHECK:STDOUT: entity_names: diff --git a/toolchain/check/testdata/interop/cpp/basics/import/indirect.carbon b/toolchain/check/testdata/interop/cpp/basics/import/indirect.carbon index dd136dadf44f..acc3223d9219 100644 --- a/toolchain/check/testdata/interop/cpp/basics/import/indirect.carbon +++ b/toolchain/check/testdata/interop/cpp/basics/import/indirect.carbon @@ -201,7 +201,8 @@ fn UseZ() -> Cpp.A.Z { // CHECK:STDOUT: %.loc15_12.2: ref %X = temporary %.loc15_12.1, %F.call // CHECK:STDOUT: %g.ref: %X.g.cpp_overload_set.type = name_ref g, imports.%X.g.cpp_overload_set.value [concrete = constants.%X.g.cpp_overload_set.value] // CHECK:STDOUT: %bound_method: = bound_method %.loc15_12.2, %g.ref -// CHECK:STDOUT: %X.g.call: init %i32 = call imports.%X.g.decl(%.loc15_12.2) +// CHECK:STDOUT: %.loc15_12.3: %X = acquire_value %.loc15_12.2 +// CHECK:STDOUT: %X.g.call: init %i32 = call imports.%X.g.decl(%.loc15_12.3) // CHECK:STDOUT: %X.cpp_destructor.bound: = bound_method %.loc15_12.2, constants.%X.cpp_destructor // CHECK:STDOUT: %X.cpp_destructor.call: init %empty_tuple.type = call %X.cpp_destructor.bound(%.loc15_12.2) // CHECK:STDOUT: return %X.g.call diff --git a/toolchain/check/testdata/interop/cpp/class/import/method.carbon b/toolchain/check/testdata/interop/cpp/class/import/method.carbon index abdda8dd7843..2cf35c58add7 100644 --- a/toolchain/check/testdata/interop/cpp/class/import/method.carbon +++ b/toolchain/check/testdata/interop/cpp/class/import/method.carbon @@ -288,12 +288,14 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %const_ref_ref_this__carbon_thunk: %const_ref_ref_this__carbon_thunk.type = struct_value () [concrete] // CHECK:STDOUT: %HasQualifiers.plain.cpp_overload_set.type: type = cpp_overload_set_type @HasQualifiers.plain.cpp_overload_set [concrete] // CHECK:STDOUT: %HasQualifiers.plain.cpp_overload_set.value: %HasQualifiers.plain.cpp_overload_set.type = cpp_overload_set_value @HasQualifiers.plain.cpp_overload_set [concrete] -// CHECK:STDOUT: %HasQualifiers.plain.type: type = fn_type @HasQualifiers.plain [concrete] -// CHECK:STDOUT: %HasQualifiers.plain: %HasQualifiers.plain.type = struct_value () [concrete] +// CHECK:STDOUT: %HasQualifiers.plain.type.b9c87a.1: type = fn_type @HasQualifiers.plain.1 [concrete] +// CHECK:STDOUT: %HasQualifiers.plain.4829ab.1: %HasQualifiers.plain.type.b9c87a.1 = struct_value () [concrete] // CHECK:STDOUT: %HasQualifiers.ref_this.cpp_overload_set.type: type = cpp_overload_set_type @HasQualifiers.ref_this.cpp_overload_set [concrete] // CHECK:STDOUT: %HasQualifiers.ref_this.cpp_overload_set.value: %HasQualifiers.ref_this.cpp_overload_set.type = cpp_overload_set_value @HasQualifiers.ref_this.cpp_overload_set [concrete] // CHECK:STDOUT: %HasQualifiers.ref_this.type: type = fn_type @HasQualifiers.ref_this [concrete] // CHECK:STDOUT: %HasQualifiers.ref_this: %HasQualifiers.ref_this.type = struct_value () [concrete] +// CHECK:STDOUT: %HasQualifiers.plain.type.b9c87a.2: type = fn_type @HasQualifiers.plain.2 [concrete] +// CHECK:STDOUT: %HasQualifiers.plain.4829ab.2: %HasQualifiers.plain.type.b9c87a.2 = struct_value () [concrete] // CHECK:STDOUT: %HasQualifiers.ref_ref_this.cpp_overload_set.type: type = cpp_overload_set_type @HasQualifiers.ref_ref_this.cpp_overload_set [concrete] // CHECK:STDOUT: %HasQualifiers.ref_ref_this.cpp_overload_set.value: %HasQualifiers.ref_ref_this.cpp_overload_set.type = cpp_overload_set_value @HasQualifiers.ref_ref_this.cpp_overload_set [concrete] // CHECK:STDOUT: %ref_ref_this__carbon_thunk.type: type = fn_type @ref_ref_this__carbon_thunk [concrete] @@ -337,7 +339,7 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: %HasQualifiers.plain.cpp_overload_set.value: %HasQualifiers.plain.cpp_overload_set.type = cpp_overload_set_value @HasQualifiers.plain.cpp_overload_set [concrete = constants.%HasQualifiers.plain.cpp_overload_set.value] -// CHECK:STDOUT: %HasQualifiers.plain.decl: %HasQualifiers.plain.type = fn_decl @HasQualifiers.plain [concrete = constants.%HasQualifiers.plain] { +// CHECK:STDOUT: %HasQualifiers.plain.decl.020d0d.1: %HasQualifiers.plain.type.b9c87a.1 = fn_decl @HasQualifiers.plain.1 [concrete = constants.%HasQualifiers.plain.4829ab.1] { // CHECK:STDOUT: // CHECK:STDOUT: } { // CHECK:STDOUT: @@ -348,6 +350,11 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: } { // CHECK:STDOUT: // CHECK:STDOUT: } +// CHECK:STDOUT: %HasQualifiers.plain.decl.020d0d.2: %HasQualifiers.plain.type.b9c87a.2 = fn_decl @HasQualifiers.plain.2 [concrete = constants.%HasQualifiers.plain.4829ab.2] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } // CHECK:STDOUT: %HasQualifiers.ref_ref_this.cpp_overload_set.value: %HasQualifiers.ref_ref_this.cpp_overload_set.type = cpp_overload_set_value @HasQualifiers.ref_ref_this.cpp_overload_set [concrete = constants.%HasQualifiers.ref_ref_this.cpp_overload_set.value] // CHECK:STDOUT: %ref_ref_this__carbon_thunk.decl: %ref_ref_this__carbon_thunk.type = fn_decl @ref_ref_this__carbon_thunk [concrete = constants.%ref_ref_this__carbon_thunk] { // CHECK:STDOUT: @@ -389,7 +396,7 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %.loc14: ref %HasQualifiers = deref %p.ref.loc14 // CHECK:STDOUT: %plain.ref.loc14: %HasQualifiers.plain.cpp_overload_set.type = name_ref plain, imports.%HasQualifiers.plain.cpp_overload_set.value [concrete = constants.%HasQualifiers.plain.cpp_overload_set.value] // CHECK:STDOUT: %bound_method.loc14: = bound_method %.loc14, %plain.ref.loc14 -// CHECK:STDOUT: %HasQualifiers.plain.call.loc14: init %empty_tuple.type = call imports.%HasQualifiers.plain.decl(%.loc14) +// CHECK:STDOUT: %HasQualifiers.plain.call.loc14: init %empty_tuple.type = call imports.%HasQualifiers.plain.decl.020d0d.1(%.loc14) // CHECK:STDOUT: %p.ref.loc15: %ptr.ec3 = name_ref p, %p // CHECK:STDOUT: %.loc15: ref %HasQualifiers = deref %p.ref.loc15 // CHECK:STDOUT: %ref_this.ref: %HasQualifiers.ref_this.cpp_overload_set.type = name_ref ref_this, imports.%HasQualifiers.ref_this.cpp_overload_set.value [concrete = constants.%HasQualifiers.ref_this.cpp_overload_set.value] @@ -413,7 +420,8 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %.loc19_8.2: ref %HasQualifiers = temporary %.loc19_8.1, %Make.call.loc19 // CHECK:STDOUT: %plain.ref.loc19: %HasQualifiers.plain.cpp_overload_set.type = name_ref plain, imports.%HasQualifiers.plain.cpp_overload_set.value [concrete = constants.%HasQualifiers.plain.cpp_overload_set.value] // CHECK:STDOUT: %bound_method.loc19: = bound_method %.loc19_8.2, %plain.ref.loc19 -// CHECK:STDOUT: %HasQualifiers.plain.call.loc19: init %empty_tuple.type = call imports.%HasQualifiers.plain.decl(%.loc19_8.2) +// CHECK:STDOUT: %.loc19_8.3: %HasQualifiers = acquire_value %.loc19_8.2 +// CHECK:STDOUT: %HasQualifiers.plain.call.loc19: init %empty_tuple.type = call imports.%HasQualifiers.plain.decl.020d0d.2(%.loc19_8.3) // CHECK:STDOUT: %Make.ref.loc20: %Make.type = name_ref Make, file.%Make.decl [concrete = constants.%Make] // CHECK:STDOUT: %.loc20_8.1: ref %HasQualifiers = temporary_storage // CHECK:STDOUT: %Make.call.loc20: init %HasQualifiers to %.loc20_8.1 = call %Make.ref.loc20() @@ -640,8 +648,8 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %F__carbon_thunk: %F__carbon_thunk.type = struct_value () [concrete] // CHECK:STDOUT: %ExplicitObjectParam.G.cpp_overload_set.type: type = cpp_overload_set_type @ExplicitObjectParam.G.cpp_overload_set [concrete] // CHECK:STDOUT: %ExplicitObjectParam.G.cpp_overload_set.value: %ExplicitObjectParam.G.cpp_overload_set.type = cpp_overload_set_value @ExplicitObjectParam.G.cpp_overload_set [concrete] -// CHECK:STDOUT: %ExplicitObjectParam.G.type: type = fn_type @ExplicitObjectParam.G [concrete] -// CHECK:STDOUT: %ExplicitObjectParam.G: %ExplicitObjectParam.G.type = struct_value () [concrete] +// CHECK:STDOUT: %G__carbon_thunk.type: type = fn_type @G__carbon_thunk [concrete] +// CHECK:STDOUT: %G__carbon_thunk: %G__carbon_thunk.type = struct_value () [concrete] // CHECK:STDOUT: %ExplicitObjectParam.H.cpp_overload_set.type: type = cpp_overload_set_type @ExplicitObjectParam.H.cpp_overload_set [concrete] // CHECK:STDOUT: %ExplicitObjectParam.H.cpp_overload_set.value: %ExplicitObjectParam.H.cpp_overload_set.type = cpp_overload_set_value @ExplicitObjectParam.H.cpp_overload_set [concrete] // CHECK:STDOUT: %ptr.289: type = ptr_type %Another [concrete] @@ -664,7 +672,7 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: %ExplicitObjectParam.G.cpp_overload_set.value: %ExplicitObjectParam.G.cpp_overload_set.type = cpp_overload_set_value @ExplicitObjectParam.G.cpp_overload_set [concrete = constants.%ExplicitObjectParam.G.cpp_overload_set.value] -// CHECK:STDOUT: %ExplicitObjectParam.G.decl: %ExplicitObjectParam.G.type = fn_decl @ExplicitObjectParam.G [concrete = constants.%ExplicitObjectParam.G] { +// CHECK:STDOUT: %G__carbon_thunk.decl: %G__carbon_thunk.type = fn_decl @G__carbon_thunk [concrete = constants.%G__carbon_thunk] { // CHECK:STDOUT: // CHECK:STDOUT: } { // CHECK:STDOUT: @@ -690,7 +698,7 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %ExplicitObjectParam.ref.loc9: type = name_ref ExplicitObjectParam, imports.%ExplicitObjectParam.decl [concrete = constants.%ExplicitObjectParam] // CHECK:STDOUT: %G.ref: %ExplicitObjectParam.G.cpp_overload_set.type = name_ref G, imports.%ExplicitObjectParam.G.cpp_overload_set.value [concrete = constants.%ExplicitObjectParam.G.cpp_overload_set.value] // CHECK:STDOUT: %bound_method.loc9: = bound_method %n.ref, %G.ref -// CHECK:STDOUT: %ExplicitObjectParam.G.call: init %empty_tuple.type = call imports.%ExplicitObjectParam.G.decl(%n.ref) +// CHECK:STDOUT: %G__carbon_thunk.call: init %empty_tuple.type = call imports.%G__carbon_thunk.decl(%n.ref) // CHECK:STDOUT: %a.ref: %Another = name_ref a, %a // CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %ExplicitObjectParam.ref.loc10: type = name_ref ExplicitObjectParam, imports.%ExplicitObjectParam.decl [concrete = constants.%ExplicitObjectParam] @@ -715,11 +723,11 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %ptr.7f5: type = ptr_type %ExplicitObjectParam [concrete] // CHECK:STDOUT: %F__carbon_thunk.type.eda1ac.1: type = fn_type @F__carbon_thunk.1 [concrete] // CHECK:STDOUT: %F__carbon_thunk.0cd6a8.1: %F__carbon_thunk.type.eda1ac.1 = struct_value () [concrete] -// CHECK:STDOUT: %ExplicitObjectParam.F.type.5d25a8.2: type = fn_type @ExplicitObjectParam.F.2 [concrete] -// CHECK:STDOUT: %ExplicitObjectParam.F.28cf2e.2: %ExplicitObjectParam.F.type.5d25a8.2 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.289: type = ptr_type %Another [concrete] // CHECK:STDOUT: %F__carbon_thunk.type.eda1ac.2: type = fn_type @F__carbon_thunk.2 [concrete] // CHECK:STDOUT: %F__carbon_thunk.0cd6a8.2: %F__carbon_thunk.type.eda1ac.2 = struct_value () [concrete] +// CHECK:STDOUT: %ptr.289: type = ptr_type %Another [concrete] +// CHECK:STDOUT: %F__carbon_thunk.type.eda1ac.3: type = fn_type @F__carbon_thunk.3 [concrete] +// CHECK:STDOUT: %F__carbon_thunk.0cd6a8.3: %F__carbon_thunk.type.eda1ac.3 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -736,12 +744,12 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: } { // CHECK:STDOUT: // CHECK:STDOUT: } -// CHECK:STDOUT: %ExplicitObjectParam.F.decl.28f5af.2: %ExplicitObjectParam.F.type.5d25a8.2 = fn_decl @ExplicitObjectParam.F.2 [concrete = constants.%ExplicitObjectParam.F.28cf2e.2] { +// CHECK:STDOUT: %F__carbon_thunk.decl.e1b8ec.2: %F__carbon_thunk.type.eda1ac.2 = fn_decl @F__carbon_thunk.2 [concrete = constants.%F__carbon_thunk.0cd6a8.2] { // CHECK:STDOUT: // CHECK:STDOUT: } { // CHECK:STDOUT: // CHECK:STDOUT: } -// CHECK:STDOUT: %F__carbon_thunk.decl.e1b8ec.2: %F__carbon_thunk.type.eda1ac.2 = fn_decl @F__carbon_thunk.2 [concrete = constants.%F__carbon_thunk.0cd6a8.2] { +// CHECK:STDOUT: %F__carbon_thunk.decl.e1b8ec.3: %F__carbon_thunk.type.eda1ac.3 = fn_decl @F__carbon_thunk.3 [concrete = constants.%F__carbon_thunk.0cd6a8.3] { // CHECK:STDOUT: // CHECK:STDOUT: } { // CHECK:STDOUT: @@ -761,7 +769,7 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %ExplicitObjectParam.ref.loc9: type = name_ref ExplicitObjectParam, imports.%ExplicitObjectParam.decl [concrete = constants.%ExplicitObjectParam] // CHECK:STDOUT: %F.ref.loc9: %ExplicitObjectParam.F.cpp_overload_set.type = name_ref F, imports.%ExplicitObjectParam.F.cpp_overload_set.value [concrete = constants.%ExplicitObjectParam.F.cpp_overload_set.value] // CHECK:STDOUT: %bound_method.loc9: = bound_method %n.ref, %F.ref.loc9 -// CHECK:STDOUT: %ExplicitObjectParam.F.call: init %empty_tuple.type = call imports.%ExplicitObjectParam.F.decl.28f5af.2(%n.ref) +// CHECK:STDOUT: %F__carbon_thunk.call.loc9: init %empty_tuple.type = call imports.%F__carbon_thunk.decl.e1b8ec.2(%n.ref) // CHECK:STDOUT: %a.ref: %Another = name_ref a, %a // CHECK:STDOUT: %Cpp.ref.loc10: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %ExplicitObjectParam.ref.loc10: type = name_ref ExplicitObjectParam, imports.%ExplicitObjectParam.decl [concrete = constants.%ExplicitObjectParam] @@ -769,7 +777,7 @@ fn Call(e: Cpp.ExplicitObjectParam, n: i32, a: Cpp.Another) { // CHECK:STDOUT: %bound_method.loc10: = bound_method %a.ref, %F.ref.loc10 // CHECK:STDOUT: %.loc10: ref %Another = value_as_ref %a.ref // CHECK:STDOUT: %addr.loc10: %ptr.289 = addr_of %.loc10 -// CHECK:STDOUT: %F__carbon_thunk.call.loc10: init %empty_tuple.type = call imports.%F__carbon_thunk.decl.e1b8ec.2(%addr.loc10) +// CHECK:STDOUT: %F__carbon_thunk.call.loc10: init %empty_tuple.type = call imports.%F__carbon_thunk.decl.e1b8ec.3(%addr.loc10) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/enum/anonymous.carbon b/toolchain/check/testdata/interop/cpp/enum/anonymous.carbon index 7dd859fccf47..c7bb5153b039 100644 --- a/toolchain/check/testdata/interop/cpp/enum/anonymous.carbon +++ b/toolchain/check/testdata/interop/cpp/enum/anonymous.carbon @@ -119,7 +119,8 @@ fn G() { // CHECK:STDOUT: %Cpp.ref.loc10_15: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref.loc10_18: type = name_ref C, imports.%C.decl [concrete = constants.%C] // CHECK:STDOUT: %e.ref: %.bb7 = name_ref e, imports.%int_1.1d6 [concrete = constants.%int_1.1d6] -// CHECK:STDOUT: %C.F.call: init %empty_tuple.type = call imports.%C.F.decl(%.loc10_11.3, %e.ref) +// CHECK:STDOUT: %.loc10_11.4: %C = acquire_value %.loc10_11.3 +// CHECK:STDOUT: %C.F.call: init %empty_tuple.type = call imports.%C.F.decl(%.loc10_11.4, %e.ref) // CHECK:STDOUT: %C.cpp_destructor.bound: = bound_method %.loc10_11.3, constants.%C.cpp_destructor // CHECK:STDOUT: %C.cpp_destructor.call: init %empty_tuple.type = call %C.cpp_destructor.bound(%.loc10_11.3) // CHECK:STDOUT: return diff --git a/toolchain/check/testdata/interop/cpp/function/import/class.carbon b/toolchain/check/testdata/interop/cpp/function/import/class.carbon index 733761e6d3d6..fd70bc1585b3 100644 --- a/toolchain/check/testdata/interop/cpp/function/import/class.carbon +++ b/toolchain/check/testdata/interop/cpp/function/import/class.carbon @@ -142,6 +142,110 @@ fn F(c: Cpp.C) { //@dump-sem-ir-end } +// ============================================================================ +// Move-only class as parameter type +// ============================================================================ + +// --- move_only_param_type.h + +struct C { + C(C&&); +}; + +auto foo(C) -> void; +auto make() -> C; +auto move(C&) -> C&&; + +// --- pass_move_only_param_temporary.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "move_only_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.foo(Cpp.make()); + //@dump-sem-ir-end +} + +// --- fail_pass_move_only_param_value.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_pass_move_only_param_value.carbon:[[@LINE+12]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:6:6: error: call to implicitly-deleted copy constructor of 'C' [CppInteropParseError] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_pass_move_only_param_value.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:3:3: note: copy constructor is implicitly deleted because 'C' has a user-declared move constructor [CppInteropParseNote] +// CHECK:STDERR: 3 | C(C&&); +// CHECK:STDERR: | ^ +// CHECK:STDERR: fail_pass_move_only_param_value.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:6:11: note: passing argument to parameter here [CppInteropParseNote] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^ +import Cpp library "move_only_param_type.h"; + +fn F(c: Cpp.C) { + // CHECK:STDERR: fail_pass_move_only_param_value.carbon:[[@LINE+4]]:3: note: in thunk for C++ function used here [InCppThunk] + // CHECK:STDERR: Cpp.foo(c); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + Cpp.foo(c); +} + +// --- fail_pass_move_only_param_ref.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_pass_move_only_param_ref.carbon:[[@LINE+12]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:6:6: error: call to implicitly-deleted copy constructor of 'C' [CppInteropParseError] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_pass_move_only_param_ref.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:3:3: note: copy constructor is implicitly deleted because 'C' has a user-declared move constructor [CppInteropParseNote] +// CHECK:STDERR: 3 | C(C&&); +// CHECK:STDERR: | ^ +// CHECK:STDERR: fail_pass_move_only_param_ref.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:6:11: note: passing argument to parameter here [CppInteropParseNote] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^ +import Cpp library "move_only_param_type.h"; + +fn F(ref c: Cpp.C) { + // CHECK:STDERR: fail_pass_move_only_param_ref.carbon:[[@LINE+4]]:3: note: in thunk for C++ function used here [InCppThunk] + // CHECK:STDERR: Cpp.foo(c); + // CHECK:STDERR: ^~~~~~~~~~ + // CHECK:STDERR: + Cpp.foo(c); +} + +// --- fail_todo_pass_move_only_param_ref_by_move.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_todo_pass_move_only_param_ref_by_move.carbon:[[@LINE+12]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:6:6: error: call to implicitly-deleted copy constructor of 'C' [CppInteropParseError] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_todo_pass_move_only_param_ref_by_move.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:3:3: note: copy constructor is implicitly deleted because 'C' has a user-declared move constructor [CppInteropParseNote] +// CHECK:STDERR: 3 | C(C&&); +// CHECK:STDERR: | ^ +// CHECK:STDERR: fail_todo_pass_move_only_param_ref_by_move.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./move_only_param_type.h:6:11: note: passing argument to parameter here [CppInteropParseNote] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^ +import Cpp library "move_only_param_type.h"; + +fn F(ref c: Cpp.C) { + // CHECK:STDERR: fail_todo_pass_move_only_param_ref_by_move.carbon:[[@LINE+4]]:3: note: in thunk for C++ function used here [InCppThunk] + // CHECK:STDERR: Cpp.foo(Cpp.move(ref c)); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Cpp.foo(Cpp.move(ref c)); +} + // ============================================================================ // Defined class with a single data member as parameter type // ============================================================================ @@ -565,6 +669,58 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- pass_move_only_param_temporary.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %foo.cpp_overload_set.type: type = cpp_overload_set_type @foo.cpp_overload_set [concrete] +// CHECK:STDOUT: %foo.cpp_overload_set.value: %foo.cpp_overload_set.type = cpp_overload_set_value @foo.cpp_overload_set [concrete] +// CHECK:STDOUT: %make.cpp_overload_set.type: type = cpp_overload_set_type @make.cpp_overload_set [concrete] +// CHECK:STDOUT: %make.cpp_overload_set.value: %make.cpp_overload_set.type = cpp_overload_set_value @make.cpp_overload_set [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] +// CHECK:STDOUT: %make__carbon_thunk.type: type = fn_type @make__carbon_thunk [concrete] +// CHECK:STDOUT: %make__carbon_thunk: %make__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: %foo__carbon_thunk.type: type = fn_type @foo__carbon_thunk [concrete] +// CHECK:STDOUT: %foo__carbon_thunk: %foo__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = %foo.cpp_overload_set.value +// CHECK:STDOUT: .make = %make.cpp_overload_set.value +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo.cpp_overload_set.value: %foo.cpp_overload_set.type = cpp_overload_set_value @foo.cpp_overload_set [concrete = constants.%foo.cpp_overload_set.value] +// CHECK:STDOUT: %make.cpp_overload_set.value: %make.cpp_overload_set.type = cpp_overload_set_value @make.cpp_overload_set [concrete = constants.%make.cpp_overload_set.value] +// CHECK:STDOUT: %make__carbon_thunk.decl: %make__carbon_thunk.type = fn_decl @make__carbon_thunk [concrete = constants.%make__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo__carbon_thunk.decl: %foo__carbon_thunk.type = fn_decl @foo__carbon_thunk [concrete = constants.%foo__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc8_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: %foo.cpp_overload_set.type = name_ref foo, imports.%foo.cpp_overload_set.value [concrete = constants.%foo.cpp_overload_set.value] +// CHECK:STDOUT: %Cpp.ref.loc8_11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %make.ref: %make.cpp_overload_set.type = name_ref make, imports.%make.cpp_overload_set.value [concrete = constants.%make.cpp_overload_set.value] +// CHECK:STDOUT: +// CHECK:STDOUT: %addr.loc8_20: %ptr.d9e = addr_of %_.var +// CHECK:STDOUT: %make__carbon_thunk.call: init %empty_tuple.type = call imports.%make__carbon_thunk.decl(%addr.loc8_20) +// CHECK:STDOUT: %.loc8: init %C to %_.var = mark_in_place_init %make__carbon_thunk.call +// CHECK:STDOUT: +// CHECK:STDOUT: %addr.loc8_21: %ptr.d9e = addr_of %_.var +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_21) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- import_definition_single_data_member_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/testdata/interop/cpp/function/import/default_arg.carbon b/toolchain/check/testdata/interop/cpp/function/import/default_arg.carbon index 426ec89d80c6..3fdb68ca5b8b 100644 --- a/toolchain/check/testdata/interop/cpp/function/import/default_arg.carbon +++ b/toolchain/check/testdata/interop/cpp/function/import/default_arg.carbon @@ -338,6 +338,7 @@ fn Call() { // CHECK:STDOUT: %bound_method.loc10_16: = bound_method %.loc10_7.2, %B.ref [concrete = constants.%bound_method.a5d] // CHECK:STDOUT: %int_1.loc10: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] // CHECK:STDOUT: %int_2.loc10: Core.IntLiteral = int_value 2 [concrete = constants.%int_2.ecc] +// CHECK:STDOUT: %.loc10_7.3: %X = acquire_value %.loc10_7.2 [concrete = constants.%X.val] // CHECK:STDOUT: %impl.elem0.loc10_19: %.9db = impl_witness_access constants.%ImplicitAs.impl_witness.ac5, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f1a] // CHECK:STDOUT: %bound_method.loc10_19.1: = bound_method %int_1.loc10, %impl.elem0.loc10_19 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.d43] // CHECK:STDOUT: %specific_fn.loc10_19: = specific_function %impl.elem0.loc10_19, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] @@ -352,7 +353,7 @@ fn Call() { // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc10_22: init %i32 = call %bound_method.loc10_22.2(%int_2.loc10) [concrete = constants.%int_2.ef8] // CHECK:STDOUT: %.loc10_22.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc10_22 [concrete = constants.%int_2.ef8] // CHECK:STDOUT: %.loc10_22.2: %i32 = converted %int_2.loc10, %.loc10_22.1 [concrete = constants.%int_2.ef8] -// CHECK:STDOUT: %X.B.call: init %empty_tuple.type = call imports.%X.B.decl(%.loc10_7.2, %.loc10_19.2, %.loc10_22.2) +// CHECK:STDOUT: %X.B.call: init %empty_tuple.type = call imports.%X.B.decl(%.loc10_7.3, %.loc10_19.2, %.loc10_22.2) // CHECK:STDOUT: %Cpp.ref.loc11: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %X.ref.loc11: type = name_ref X, imports.%X.decl [concrete = constants.%X] // CHECK:STDOUT: %C.ref: %X.C.cpp_overload_set.type = name_ref C, imports.%X.C.cpp_overload_set.value [concrete = constants.%X.C.cpp_overload_set.value] @@ -591,13 +592,13 @@ fn Call() { // CHECK:STDOUT: %X.decl: type = class_decl @X [concrete = constants.%X] {} {} // CHECK:STDOUT: %X.B.cpp_overload_set.value: %X.B.cpp_overload_set.type = cpp_overload_set_value @X.B.cpp_overload_set [concrete = constants.%X.B.cpp_overload_set.value] // CHECK:STDOUT: %B__carbon_thunk.decl: %B__carbon_thunk.type = fn_decl @B__carbon_thunk [concrete = constants.%B__carbon_thunk] { -// CHECK:STDOUT: %this.param_patt: %pattern_type.46b = ref_param_pattern [concrete] +// CHECK:STDOUT: %this.param_patt: %pattern_type.46b = value_param_pattern [concrete] // CHECK:STDOUT: %this.patt: %pattern_type.46b = at_binding_pattern this, %this.param_patt [concrete] // CHECK:STDOUT: %a.param_patt: %pattern_type.7ce = value_param_pattern [concrete] // CHECK:STDOUT: %a.patt: %pattern_type.7ce = at_binding_pattern a, %a.param_patt [concrete] // CHECK:STDOUT: } { -// CHECK:STDOUT: %this.param: ref %X = ref_param call_param0 -// CHECK:STDOUT: %this: ref %X = ref_binding this, %this.param +// CHECK:STDOUT: %this.param: %X = value_param call_param0 +// CHECK:STDOUT: %this: %X = value_binding this, %this.param // CHECK:STDOUT: %a.param: %i32 = value_param call_param1 // CHECK:STDOUT: %.1: type = splice_block %i32.2 [concrete = constants.%i32] { // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete = constants.%int_32] @@ -756,6 +757,7 @@ fn Call() { // CHECK:STDOUT: %B.ref: %X.B.cpp_overload_set.type = name_ref B, imports.%X.B.cpp_overload_set.value [concrete = constants.%X.B.cpp_overload_set.value] // CHECK:STDOUT: %bound_method.loc11_16: = bound_method %.loc11_7.2, %B.ref [concrete = constants.%bound_method.a5d] // CHECK:STDOUT: %int_1.loc11: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] +// CHECK:STDOUT: %.loc11_7.3: %X = acquire_value %.loc11_7.2 [concrete = constants.%X.val] // CHECK:STDOUT: %impl.elem0.loc11: %.9db = impl_witness_access constants.%ImplicitAs.impl_witness.ac5, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f1a] // CHECK:STDOUT: %bound_method.loc11_19.1: = bound_method %int_1.loc11, %impl.elem0.loc11 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.d43] // CHECK:STDOUT: %specific_fn.loc11: = specific_function %impl.elem0.loc11, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] @@ -763,7 +765,7 @@ fn Call() { // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc11: init %i32 = call %bound_method.loc11_19.2(%int_1.loc11) [concrete = constants.%int_1.5d2] // CHECK:STDOUT: %.loc11_19.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc11 [concrete = constants.%int_1.5d2] // CHECK:STDOUT: %.loc11_19.2: %i32 = converted %int_1.loc11, %.loc11_19.1 [concrete = constants.%int_1.5d2] -// CHECK:STDOUT: %B__carbon_thunk.call: init %empty_tuple.type = call imports.%B__carbon_thunk.decl(%.loc11_7.2, %.loc11_19.2) +// CHECK:STDOUT: %B__carbon_thunk.call: init %empty_tuple.type = call imports.%B__carbon_thunk.decl(%.loc11_7.3, %.loc11_19.2) // CHECK:STDOUT: %Cpp.ref.loc12: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %X.ref.loc12: type = name_ref X, imports.%X.decl [concrete = constants.%X] // CHECK:STDOUT: %C.ref: %X.C.cpp_overload_set.type = name_ref C, imports.%X.C.cpp_overload_set.value [concrete = constants.%X.C.cpp_overload_set.value] @@ -821,9 +823,9 @@ fn Call() { // CHECK:STDOUT: // CHECK:STDOUT: fn @GlobalNoReturn__carbon_thunk.2(%a.param: %i32, %b.param: %i32, %c.param: %i32); // CHECK:STDOUT: -// CHECK:STDOUT: fn @X.B(%self.param: ref %X, %a.param: %i32); +// CHECK:STDOUT: fn @X.B(%self.param: %X, %a.param: %i32); // CHECK:STDOUT: -// CHECK:STDOUT: fn @B__carbon_thunk(%this.param: ref %X, %a.param: %i32); +// CHECK:STDOUT: fn @B__carbon_thunk(%this.param: %X, %a.param: %i32); // CHECK:STDOUT: // CHECK:STDOUT: fn @X.C(%a.param: %i32); // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/import/thunk_ast.carbon b/toolchain/check/testdata/interop/cpp/function/import/thunk_ast.carbon index c7d7db7e452a..a706fd14102b 100644 --- a/toolchain/check/testdata/interop/cpp/function/import/thunk_ast.carbon +++ b/toolchain/check/testdata/interop/cpp/function/import/thunk_ast.carbon @@ -31,7 +31,7 @@ auto foo(short a) -> void; // CHECK:STDOUT: | `-DeclRefExpr {{0x[a-f0-9]+}} 'short * _Nonnull':'short *' lvalue ParmVar {{0x[a-f0-9]+}} 'a' 'short * _Nonnull':'short *' // CHECK:STDOUT: |-AlwaysInlineAttr {{0x[a-f0-9]+}} <> Implicit always_inline // CHECK:STDOUT: |-InternalLinkageAttr {{0x[a-f0-9]+}} <> Implicit -// CHECK:STDOUT: `-AsmLabelAttr {{0x[a-f0-9]+}} Implicit "_Z3foos.carbon_thunk" +// CHECK:STDOUT: `-AsmLabelAttr {{0x[a-f0-9]+}} Implicit "_Z3foos.carbon_thunk._" // CHECK:STDOUT: TranslationUnitDecl {{0x[a-f0-9]+}} <> // CHECK:STDOUT: |-NamespaceDecl {{0x[a-f0-9]+}} <> Carbon @@ -58,7 +58,7 @@ auto foo() -> short; // CHECK:STDOUT: | `-DeclRefExpr {{0x[a-f0-9]+}} 'short * _Nonnull':'short *' lvalue ParmVar {{0x[a-f0-9]+}} 'return' 'short * _Nonnull':'short *' // CHECK:STDOUT: |-AlwaysInlineAttr {{0x[a-f0-9]+}} <> Implicit always_inline // CHECK:STDOUT: |-InternalLinkageAttr {{0x[a-f0-9]+}} <> Implicit -// CHECK:STDOUT: `-AsmLabelAttr {{0x[a-f0-9]+}} Implicit "_Z3foov.carbon_thunk" +// CHECK:STDOUT: `-AsmLabelAttr {{0x[a-f0-9]+}} Implicit "_Z3foov.carbon_thunk." // --- import_return_thunk_required.carbon diff --git a/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon b/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon index 17ac6d648a68..1d6acb6a8069 100644 --- a/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon +++ b/toolchain/check/testdata/interop/cpp/operators/arithmetic_operators.carbon @@ -1128,14 +1128,14 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.0d7: type = fn_type_with_self_type %Negate.WithSelf.Op.type.899, %Negate.facet.758 [symbolic] // CHECK:STDOUT: %impl.elem1.ec8: %.0d7 = impl_witness_access %Negate.lookup_impl_witness.783, element1 [symbolic] // CHECK:STDOUT: %specific_impl_fn.f22: = specific_impl_function %impl.elem1.ec8, @Negate.WithSelf.Op(%Negate.facet.758) [symbolic] -// CHECK:STDOUT: %Int32.cpp_operator.type.49e401.16: type = fn_type @Int32.cpp_operator.16 [concrete] -// CHECK:STDOUT: %Int32.cpp_operator.0010d3.16: %Int32.cpp_operator.type.49e401.16 = struct_value () [concrete] -// CHECK:STDOUT: %custom_witness.934: = custom_witness (%Int32.cpp_operator.0010d3.16), @Inc [concrete] -// CHECK:STDOUT: %Inc.facet.390: %Inc.type = facet_value %Int32, (%custom_witness.934) [concrete] -// CHECK:STDOUT: %Int32.cpp_operator.type.49e401.17: type = fn_type @Int32.cpp_operator.17 [concrete] -// CHECK:STDOUT: %Int32.cpp_operator.0010d3.17: %Int32.cpp_operator.type.49e401.17 = struct_value () [concrete] -// CHECK:STDOUT: %custom_witness.99f: = custom_witness (%Int32.cpp_operator.0010d3.17), @Dec [concrete] -// CHECK:STDOUT: %Dec.facet.961: %Dec.type = facet_value %Int32, (%custom_witness.99f) [concrete] +// CHECK:STDOUT: %Int32.Op.type.68b858.18: type = fn_type @Int32.Op.18 [concrete] +// CHECK:STDOUT: %Int32.Op.6afff1.18: %Int32.Op.type.68b858.18 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.50d: = custom_witness (%Int32.Op.6afff1.18), @Inc [concrete] +// CHECK:STDOUT: %Inc.facet.9db: %Inc.type = facet_value %Int32, (%custom_witness.50d) [concrete] +// CHECK:STDOUT: %Int32.Op.type.68b858.19: type = fn_type @Int32.Op.19 [concrete] +// CHECK:STDOUT: %Int32.Op.6afff1.19: %Int32.Op.type.68b858.19 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.e76: = custom_witness (%Int32.Op.6afff1.19), @Dec [concrete] +// CHECK:STDOUT: %Dec.facet.bed: %Dec.type = facet_value %Int32, (%custom_witness.e76) [concrete] // CHECK:STDOUT: %facet_type.89a: type = facet_type <@Destroy & @Negate where %impl.elem0.f00 = %Int64> [concrete] // CHECK:STDOUT: %Int16.Op.type.180c8b.18: type = fn_type @Int16.Op.18 [concrete] // CHECK:STDOUT: %Int16.Op.c3e49c.18: %Int16.Op.type.180c8b.18 = struct_value () [concrete] @@ -1143,9 +1143,9 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %facet_value.70a: %facet_type.89a = facet_value %Int16, (%custom_witness.e5b, %custom_witness.e58) [concrete] // CHECK:STDOUT: %pattern_type.c49: type = pattern_type %facet_type.89a [concrete] // CHECK:STDOUT: %facet_type.d5d: type = facet_type <@Destroy & @Negate where %impl.elem0.f00 = %Int32> [concrete] -// CHECK:STDOUT: %Int32.Op.type.68b858.18: type = fn_type @Int32.Op.18 [concrete] -// CHECK:STDOUT: %Int32.Op.6afff1.18: %Int32.Op.type.68b858.18 = struct_value () [concrete] -// CHECK:STDOUT: %custom_witness.e8a: = custom_witness (%Int32, %Int32.Op.6afff1.18), @Negate [concrete] +// CHECK:STDOUT: %Int32.Op.type.68b858.20: type = fn_type @Int32.Op.20 [concrete] +// CHECK:STDOUT: %Int32.Op.6afff1.20: %Int32.Op.type.68b858.20 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.e8a: = custom_witness (%Int32, %Int32.Op.6afff1.20), @Negate [concrete] // CHECK:STDOUT: %facet_value.396: %facet_type.d5d = facet_value %Int32, (%custom_witness.ce1, %custom_witness.e8a) [concrete] // CHECK:STDOUT: %pattern_type.0ec: type = pattern_type %facet_type.d5d [concrete] // CHECK:STDOUT: %complete_type.f1c: = complete_type_witness %AddWith.type.344 [concrete] @@ -1313,10 +1313,10 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %.384: type = fn_type_with_self_type %DivAssignWith.WithSelf.Op.type.646, %DivAssignWith.facet.d3b [concrete] // CHECK:STDOUT: %ModAssignWith.WithSelf.Op.type.a34: type = fn_type @ModAssignWith.WithSelf.Op, @ModAssignWith.WithSelf(%Int32, %ModAssignWith.facet.1c6) [concrete] // CHECK:STDOUT: %.ee0: type = fn_type_with_self_type %ModAssignWith.WithSelf.Op.type.a34, %ModAssignWith.facet.1c6 [concrete] -// CHECK:STDOUT: %Inc.WithSelf.Op.type.eaa: type = fn_type @Inc.WithSelf.Op, @Inc.WithSelf(%Inc.facet.390) [concrete] -// CHECK:STDOUT: %.696: type = fn_type_with_self_type %Inc.WithSelf.Op.type.eaa, %Inc.facet.390 [concrete] -// CHECK:STDOUT: %Dec.WithSelf.Op.type.6fb: type = fn_type @Dec.WithSelf.Op, @Dec.WithSelf(%Dec.facet.961) [concrete] -// CHECK:STDOUT: %.cdd: type = fn_type_with_self_type %Dec.WithSelf.Op.type.6fb, %Dec.facet.961 [concrete] +// CHECK:STDOUT: %Inc.WithSelf.Op.type.755: type = fn_type @Inc.WithSelf.Op, @Inc.WithSelf(%Inc.facet.9db) [concrete] +// CHECK:STDOUT: %.cfd3: type = fn_type_with_self_type %Inc.WithSelf.Op.type.755, %Inc.facet.9db [concrete] +// CHECK:STDOUT: %Dec.WithSelf.Op.type.e71: type = fn_type @Dec.WithSelf.Op, @Dec.WithSelf(%Dec.facet.bed) [concrete] +// CHECK:STDOUT: %.b6e: type = fn_type_with_self_type %Dec.WithSelf.Op.type.e71, %Dec.facet.bed [concrete] // CHECK:STDOUT: %Negate.facet.0a5: %Negate.type = facet_value %Int16, (%custom_witness.e58) [concrete] // CHECK:STDOUT: %Negate.WithSelf.Op.type.d7d: type = fn_type @Negate.WithSelf.Op, @Negate.WithSelf(%Negate.facet.0a5) [concrete] // CHECK:STDOUT: %.3e7: type = fn_type_with_self_type %Negate.WithSelf.Op.type.d7d, %Negate.facet.0a5 [concrete] @@ -3763,32 +3763,32 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %pattern_type.loc294_22 => constants.%pattern_type.ece // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @TestInc(constants.%Inc.facet.390) { -// CHECK:STDOUT: %T.loc278_13.1 => constants.%Inc.facet.390 +// CHECK:STDOUT: specific @TestInc(constants.%Inc.facet.9db) { +// CHECK:STDOUT: %T.loc278_13.1 => constants.%Inc.facet.9db // CHECK:STDOUT: %T.as_type.loc278_33.1 => constants.%Int32 // CHECK:STDOUT: %pattern_type => constants.%pattern_type.9c9 // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete => constants.%complete_type.357 -// CHECK:STDOUT: %Inc.WithSelf.Op.type => constants.%Inc.WithSelf.Op.type.eaa -// CHECK:STDOUT: %.loc280 => constants.%.696 -// CHECK:STDOUT: %Inc.lookup_impl_witness => constants.%custom_witness.934 -// CHECK:STDOUT: %impl.elem0.loc280_3.2 => constants.%Int32.cpp_operator.0010d3.16 -// CHECK:STDOUT: %specific_impl_fn.loc280_3.2 => constants.%Int32.cpp_operator.0010d3.16 +// CHECK:STDOUT: %Inc.WithSelf.Op.type => constants.%Inc.WithSelf.Op.type.755 +// CHECK:STDOUT: %.loc280 => constants.%.cfd3 +// CHECK:STDOUT: %Inc.lookup_impl_witness => constants.%custom_witness.50d +// CHECK:STDOUT: %impl.elem0.loc280_3.2 => constants.%Int32.Op.6afff1.18 +// CHECK:STDOUT: %specific_impl_fn.loc280_3.2 => constants.%Int32.Op.6afff1.18 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: specific @TestDec(constants.%Dec.facet.961) { -// CHECK:STDOUT: %T.loc284_13.1 => constants.%Dec.facet.961 +// CHECK:STDOUT: specific @TestDec(constants.%Dec.facet.bed) { +// CHECK:STDOUT: %T.loc284_13.1 => constants.%Dec.facet.bed // CHECK:STDOUT: %T.as_type.loc284_33.1 => constants.%Int32 // CHECK:STDOUT: %pattern_type => constants.%pattern_type.9c9 // CHECK:STDOUT: // CHECK:STDOUT: !definition: // CHECK:STDOUT: %require_complete => constants.%complete_type.357 -// CHECK:STDOUT: %Dec.WithSelf.Op.type => constants.%Dec.WithSelf.Op.type.6fb -// CHECK:STDOUT: %.loc286 => constants.%.cdd -// CHECK:STDOUT: %Dec.lookup_impl_witness => constants.%custom_witness.99f -// CHECK:STDOUT: %impl.elem0.loc286_3.2 => constants.%Int32.cpp_operator.0010d3.17 -// CHECK:STDOUT: %specific_impl_fn.loc286_3.2 => constants.%Int32.cpp_operator.0010d3.17 +// CHECK:STDOUT: %Dec.WithSelf.Op.type => constants.%Dec.WithSelf.Op.type.e71 +// CHECK:STDOUT: %.loc286 => constants.%.b6e +// CHECK:STDOUT: %Dec.lookup_impl_witness => constants.%custom_witness.e76 +// CHECK:STDOUT: %impl.elem0.loc286_3.2 => constants.%Int32.Op.6afff1.19 +// CHECK:STDOUT: %specific_impl_fn.loc286_3.2 => constants.%Int32.Op.6afff1.19 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: specific @TestNegate(constants.%Destroy.facet.b0a, constants.%facet_value.70a) { @@ -3834,8 +3834,8 @@ fn TestUnaryOperators(a: Cpp.Int16, b: Cpp.Int32) { // CHECK:STDOUT: %Negate.facet => constants.%Negate.facet.3c9 // CHECK:STDOUT: %Negate.WithSelf.Op.type => constants.%Negate.WithSelf.Op.type.1bc // CHECK:STDOUT: %.loc296_3.3 => constants.%.19b -// CHECK:STDOUT: %impl.elem1.loc296_3.2 => constants.%Int32.Op.6afff1.18 -// CHECK:STDOUT: %specific_impl_fn.loc296_3.3 => constants.%Int32.Op.6afff1.18 +// CHECK:STDOUT: %impl.elem1.loc296_3.2 => constants.%Int32.Op.6afff1.20 +// CHECK:STDOUT: %specific_impl_fn.loc296_3.3 => constants.%Int32.Op.6afff1.20 // CHECK:STDOUT: %Destroy.WithSelf.Op.type => constants.%Destroy.WithSelf.Op.type.2e1 // CHECK:STDOUT: %.loc296_3.4 => constants.%.e6c // CHECK:STDOUT: %Destroy.lookup_impl_witness => constants.%custom_witness.ce1 diff --git a/toolchain/check/testdata/interop/cpp/operators/deref.carbon b/toolchain/check/testdata/interop/cpp/operators/deref.carbon index ee279a58e9da..5a374a1c42f3 100644 --- a/toolchain/check/testdata/interop/cpp/operators/deref.carbon +++ b/toolchain/check/testdata/interop/cpp/operators/deref.carbon @@ -175,8 +175,7 @@ fn TestDerefFail(not_ptr: Cpp.NotAPtr) { // CHECK:STDOUT: %bound_method: = bound_method %int_ptr.ref, %impl.elem1 // CHECK:STDOUT: %Op.ref.loc13_43: %ConstDeref.cpp_operator.type = name_ref Op, imports.%ConstDeref.cpp_operator.decl [concrete = constants.%ConstDeref.cpp_operator] // CHECK:STDOUT: %ConstDeref.cpp_operator.bound: = bound_method %int_ptr.ref, %Op.ref.loc13_43 -// CHECK:STDOUT: %.loc13: %ConstDeref = acquire_value %int_ptr.ref -// CHECK:STDOUT: %operator_Star__carbon_thunk.call: ref %i32 = call imports.%operator_Star__carbon_thunk.decl(%.loc13) +// CHECK:STDOUT: %operator_Star__carbon_thunk.call: ref %i32 = call imports.%operator_Star__carbon_thunk.decl(%int_ptr.ref) // CHECK:STDOUT: return %operator_Star__carbon_thunk.call // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/operators/operators.carbon b/toolchain/check/testdata/interop/cpp/operators/operators.carbon index 2479dc0b8d23..a658474419ca 100644 --- a/toolchain/check/testdata/interop/cpp/operators/operators.carbon +++ b/toolchain/check/testdata/interop/cpp/operators/operators.carbon @@ -1189,6 +1189,7 @@ fn F() { // CHECK:STDOUT: %int_3.1ba: Core.IntLiteral = int_value 3 [concrete] // CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] // CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %i32.builtin: type = int_type signed, %int_32 [concrete] // CHECK:STDOUT: %pattern_type.7ce: type = pattern_type %i32 [concrete] // CHECK:STDOUT: %operator_LessLess__carbon_thunk.type: type = fn_type @operator_LessLess__carbon_thunk [concrete] // CHECK:STDOUT: %operator_LessLess__carbon_thunk: %operator_LessLess__carbon_thunk.type = struct_value () [concrete] @@ -1252,8 +1253,12 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound.577: = bound_method %int_42.20e, %Core.IntLiteral.as.ImplicitAs.impl.Convert.f1a [concrete] // CHECK:STDOUT: %bound_method.cd5: = bound_method %int_42.20e, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_42.c68: %i32 = int_value 42 [concrete] -// CHECK:STDOUT: %Destroy.Op.type: type = fn_type @Destroy.Op [concrete] -// CHECK:STDOUT: %Destroy.Op: %Destroy.Op.type = struct_value () [concrete] +// CHECK:STDOUT: %.1a9: ref %i32 = temporary invalid, %int_42.c68 [concrete] +// CHECK:STDOUT: %Destroy.Op.type.bae255.2: type = fn_type @Destroy.Op.loc48_30.2 [concrete] +// CHECK:STDOUT: %Destroy.Op.651ba6.2: %Destroy.Op.type.bae255.2 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.Op.bound: = bound_method %.1a9, %Destroy.Op.651ba6.2 [concrete] +// CHECK:STDOUT: %Destroy.Op.type.bae255.3: type = fn_type @Destroy.Op.loc45 [concrete] +// CHECK:STDOUT: %Destroy.Op.651ba6.3: %Destroy.Op.type.bae255.3 = struct_value () [concrete] // CHECK:STDOUT: %C.cpp_destructor.type: type = fn_type @C.cpp_destructor [concrete] // CHECK:STDOUT: %C.cpp_destructor: %C.cpp_destructor.type = struct_value () [concrete] // CHECK:STDOUT: %C.Op.type: type = fn_type @C.Op [concrete] @@ -1875,24 +1880,26 @@ fn F() { // CHECK:STDOUT: %specific_fn.loc48: = specific_function %impl.elem0.loc48, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] // CHECK:STDOUT: %bound_method.loc48_30.2: = bound_method %int_42, %specific_fn.loc48 [concrete = constants.%bound_method.cd5] // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc48: init %i32 = call %bound_method.loc48_30.2(%int_42) [concrete = constants.%int_42.c68] -// CHECK:STDOUT: %.loc48_30.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc48 [concrete = constants.%int_42.c68] -// CHECK:STDOUT: %.loc48_30.2: %i32 = converted %int_42, %.loc48_30.1 [concrete = constants.%int_42.c68] -// CHECK:STDOUT: %C.cpp_operator.call: init %i32 = call %C.cpp_operator.bound(%c1.ref.loc48, %.loc48_30.2) +// CHECK:STDOUT: %.loc48_30.1: init %i32 = converted %int_42, %Core.IntLiteral.as.ImplicitAs.impl.Convert.call.loc48 [concrete = constants.%int_42.c68] +// CHECK:STDOUT: %.loc48_30.2: ref %i32 = temporary_storage +// CHECK:STDOUT: %.loc48_30.3: ref %i32 = temporary %.loc48_30.2, %.loc48_30.1 [concrete = constants.%.1a9] +// CHECK:STDOUT: %C.cpp_operator.call: init %i32 = call %C.cpp_operator.bound(%c1.ref.loc48, %.loc48_30.3) // CHECK:STDOUT: %i32: type = type_literal constants.%i32 [concrete = constants.%i32] // CHECK:STDOUT: %.loc48_32.1: %i32 = value_of_initializer %C.cpp_operator.call // CHECK:STDOUT: %.loc48_32.2: %i32 = converted %C.cpp_operator.call, %.loc48_32.1 // CHECK:STDOUT: %index: %i32 = value_binding index, %.loc48_32.2 -// CHECK:STDOUT: %Destroy.Op.bound.loc45: = bound_method %.loc45_44.3, constants.%Destroy.Op +// CHECK:STDOUT: %Destroy.Op.call.loc48: init %empty_tuple.type = call constants.%Destroy.Op.bound(constants.%.1a9) +// CHECK:STDOUT: %Destroy.Op.bound.loc45: = bound_method %.loc45_44.3, constants.%Destroy.Op.651ba6.3 // CHECK:STDOUT: %Destroy.Op.call.loc45: init %empty_tuple.type = call %Destroy.Op.bound.loc45(%.loc45_44.3) -// CHECK:STDOUT: %Destroy.Op.bound.loc44: = bound_method %.loc44_47.3, constants.%Destroy.Op +// CHECK:STDOUT: %Destroy.Op.bound.loc44: = bound_method %.loc44_47.3, constants.%Destroy.Op.651ba6.3 // CHECK:STDOUT: %Destroy.Op.call.loc44: init %empty_tuple.type = call %Destroy.Op.bound.loc44(%.loc44_47.3) -// CHECK:STDOUT: %Destroy.Op.bound.loc43: = bound_method %.loc43_35.3, constants.%Destroy.Op +// CHECK:STDOUT: %Destroy.Op.bound.loc43: = bound_method %.loc43_35.3, constants.%Destroy.Op.651ba6.3 // CHECK:STDOUT: %Destroy.Op.call.loc43: init %empty_tuple.type = call %Destroy.Op.bound.loc43(%.loc43_35.3) -// CHECK:STDOUT: %Destroy.Op.bound.loc42: = bound_method %.loc42_38.3, constants.%Destroy.Op +// CHECK:STDOUT: %Destroy.Op.bound.loc42: = bound_method %.loc42_38.3, constants.%Destroy.Op.651ba6.3 // CHECK:STDOUT: %Destroy.Op.call.loc42: init %empty_tuple.type = call %Destroy.Op.bound.loc42(%.loc42_38.3) -// CHECK:STDOUT: %Destroy.Op.bound.loc41: = bound_method %.loc41_35.3, constants.%Destroy.Op +// CHECK:STDOUT: %Destroy.Op.bound.loc41: = bound_method %.loc41_35.3, constants.%Destroy.Op.651ba6.3 // CHECK:STDOUT: %Destroy.Op.call.loc41: init %empty_tuple.type = call %Destroy.Op.bound.loc41(%.loc41_35.3) -// CHECK:STDOUT: %Destroy.Op.bound.loc40: = bound_method %.loc40_31.3, constants.%Destroy.Op +// CHECK:STDOUT: %Destroy.Op.bound.loc40: = bound_method %.loc40_31.3, constants.%Destroy.Op.651ba6.3 // CHECK:STDOUT: %Destroy.Op.call.loc40: init %empty_tuple.type = call %Destroy.Op.bound.loc40(%.loc40_31.3) // CHECK:STDOUT: // CHECK:STDOUT: %C.Op.bound.loc23: = bound_method %.loc23_38.3, constants.%C.Op @@ -1946,7 +1953,14 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: fn @Destroy.Op(%self.param: ref bool) = "no_op"; +// CHECK:STDOUT: fn @Destroy.Op.loc48_30.1(%self.param: ref %i32.builtin) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.Op.loc48_30.2(%self.param: ref %i32) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.Op.loc45(%self.param: ref bool) = "no_op"; // CHECK:STDOUT: // CHECK:STDOUT: --- multiple_calls.carbon // CHECK:STDOUT: @@ -3175,9 +3189,7 @@ fn F() { // CHECK:STDOUT: %c2.ref: ref %C = name_ref c2, %c2 // CHECK:STDOUT: %C.cpp_operator.bound.loc10: = bound_method %c1.ref.loc10, imports.%C.cpp_operator.decl.828f43.2 // CHECK:STDOUT: %.loc10_3: ref %C = splice_block %c3.var {} -// CHECK:STDOUT: %.loc10_31.1: %C = acquire_value %c2.ref -// CHECK:STDOUT: %.loc10_31.2: ref %C = value_as_ref %.loc10_31.1 -// CHECK:STDOUT: %addr.loc10_29.1: %ptr.d9e = addr_of %.loc10_31.2 +// CHECK:STDOUT: %addr.loc10_29.1: %ptr.d9e = addr_of %c2.ref // CHECK:STDOUT: %addr.loc10_29.2: %ptr.d9e = addr_of %.loc10_3 // CHECK:STDOUT: %operator_Plus__carbon_thunk.call: init %empty_tuple.type = call imports.%operator_Plus__carbon_thunk.decl(%c1.ref.loc10, %addr.loc10_29.1, %addr.loc10_29.2) // CHECK:STDOUT: %.loc10_29: init %C to %.loc10_3 = mark_in_place_init %operator_Plus__carbon_thunk.call diff --git a/toolchain/check/testdata/interop/cpp/operators/ordered_with.carbon b/toolchain/check/testdata/interop/cpp/operators/ordered_with.carbon index d189043e4b8d..dbaf9c00dc9f 100644 --- a/toolchain/check/testdata/interop/cpp/operators/ordered_with.carbon +++ b/toolchain/check/testdata/interop/cpp/operators/ordered_with.carbon @@ -377,26 +377,13 @@ fn Test(missing_less: Cpp.MissingLess, // CHECK:STDERR: OrderedWith(no_relevant_members, no_relevant_members); - // CHECK:STDERR: fail_never_valid.carbon:[[@LINE+20]]:3: error: cannot convert type `Cpp.LessReturnsVoid` into type implementing `Core.OrderedWith(Cpp.LessReturnsVoid)` [ConversionFailureTypeToFacet] + // CHECK:STDERR: fail_never_valid.carbon:[[@LINE+7]]:3: error: cannot convert type `Cpp.LessReturnsVoid` into type implementing `Core.OrderedWith(Cpp.LessReturnsVoid)` [ConversionFailureTypeToFacet] // CHECK:STDERR: OrderedWith(less_returns_void, less_returns_void); // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_never_valid.carbon:[[@LINE-62]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] // CHECK:STDERR: fn OrderedWith[U:! type, T:! Core.OrderedWith(U)](x: T, y: U) { // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: - // CHECK:STDERR: {{.*}}/prelude/operators/comparison.carbon:26:11: error: value expression passed to reference parameter [ValueForRefParam] - // CHECK:STDERR: fn Less[self: Self](other: Other) -> bool; - // CHECK:STDERR: ^~~~~~~~~~ - // CHECK:STDERR: fail_never_valid.carbon:[[@LINE-76]]:8: note: initializing function parameter [InCallToFunctionParam] - // CHECK:STDERR: auto operator<(LessNonConst) -> bool; - // CHECK:STDERR: ^ - // CHECK:STDERR: {{.*}}/prelude/operators/comparison.carbon:26:3: note: while building thunk to match the signature of this function [ThunkSignature] - // CHECK:STDERR: fn Less[self: Self](other: Other) -> bool; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: fail_never_valid.carbon:[[@LINE-75]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] - // CHECK:STDERR: fn OrderedWith[U:! type, T:! Core.OrderedWith(U)](x: T, y: U) { - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: OrderedWith(less_returns_void, less_returns_void); OrderedWith(less_non_const, less_non_const); diff --git a/toolchain/driver/testdata/stdin.carbon b/toolchain/driver/testdata/stdin.carbon index 7bfaf0d25988..5b559ac3671c 100644 --- a/toolchain/driver/testdata/stdin.carbon +++ b/toolchain/driver/testdata/stdin.carbon @@ -32,6 +32,7 @@ // CHECK:STDOUT: 'import_ir(Cpp)': {decl_id: inst, is_export: false} // CHECK:STDOUT: import_ir_insts: {} // CHECK:STDOUT: clang_decls: {} +// CHECK:STDOUT: clang_decl_signatures: {} // CHECK:STDOUT: name_scopes: // CHECK:STDOUT: name_scope0: {inst: instF, parent_scope: name_scope, has_error: false, extended_scopes: [], names: {}} // CHECK:STDOUT: entity_names: {} diff --git a/toolchain/lower/testdata/interop/cpp/constructor.carbon b/toolchain/lower/testdata/interop/cpp/constructor.carbon index a9d69a563635..5e6addf70679 100644 --- a/toolchain/lower/testdata/interop/cpp/constructor.carbon +++ b/toolchain/lower/testdata/interop/cpp/constructor.carbon @@ -181,12 +181,12 @@ fn Four() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc7_26.1.temp = alloca [8 x i8], align 1, !dbg !14 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_26.1.temp), !dbg !14 -// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk(ptr %.loc7_26.1.temp), !dbg !14 +// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk.(ptr %.loc7_26.1.temp), !dbg !14 // CHECK:STDOUT: ret void, !dbg !15 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !16 @@ -200,12 +200,12 @@ fn Four() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc11_19.2.temp = alloca [8 x i8], align 1, !dbg !20 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc11_19.2.temp), !dbg !20 -// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk_tuple(ptr %.loc11_19.2.temp), !dbg !20 +// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk_tuple.(ptr %.loc11_19.2.temp), !dbg !20 // CHECK:STDOUT: ret void, !dbg !21 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk_tuple(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk_tuple.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !16 @@ -286,7 +286,7 @@ fn Four() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !16 @@ -298,7 +298,7 @@ fn Four() { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Default.7b1e6a57c714cdb7.Core:C.Cpp"(ptr sret([8 x i8]) %return) #2 !dbg !19 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk(ptr %return), !dbg !24 +// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk.(ptr %return), !dbg !24 // CHECK:STDOUT: ret void, !dbg !24 // CHECK:STDOUT: } // CHECK:STDOUT: @@ -386,18 +386,18 @@ fn Four() { // CHECK:STDOUT: %.loc12_65.1.temp = alloca [4 x i8], align 1, !dbg !16 // CHECK:STDOUT: %_.var.loc13 = alloca [4 x i8], align 1, !dbg !17 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc8_65.1.temp), !dbg !14 -// CHECK:STDOUT: call void @_ZN26ImplicitlyDefaultedDefaultC1Ev.carbon_thunk(ptr %.loc8_65.1.temp), !dbg !14 +// CHECK:STDOUT: call void @_ZN26ImplicitlyDefaultedDefaultC1Ev.carbon_thunk.(ptr %.loc8_65.1.temp), !dbg !14 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var.loc9), !dbg !15 // CHECK:STDOUT: call void @"_COp.d288d62be0e5d791:DefaultOrUnformed.Core.22b4681b019423d7"(ptr %_.var.loc9), !dbg !15 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc12_65.1.temp), !dbg !16 -// CHECK:STDOUT: call void @_ZN26ExplicitlyDefaultedDefaultC1Ev.carbon_thunk(ptr %.loc12_65.1.temp), !dbg !16 +// CHECK:STDOUT: call void @_ZN26ExplicitlyDefaultedDefaultC1Ev.carbon_thunk.(ptr %.loc12_65.1.temp), !dbg !16 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var.loc13), !dbg !17 // CHECK:STDOUT: call void @"_COp.d288d62be0e5d791:DefaultOrUnformed.Core.1a27c303748a2360"(ptr %_.var.loc13), !dbg !17 // CHECK:STDOUT: ret void, !dbg !18 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable -// CHECK:STDOUT: define internal void @_ZN26ImplicitlyDefaultedDefaultC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN26ImplicitlyDefaultedDefaultC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !19 @@ -409,12 +409,12 @@ fn Four() { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Default.2e5fb550c65543cf.Core:ImplicitlyDefaultedDefault.Cpp"(ptr sret([4 x i8]) %return) #2 !dbg !22 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN26ImplicitlyDefaultedDefaultC1Ev.carbon_thunk(ptr %return), !dbg !27 +// CHECK:STDOUT: call void @_ZN26ImplicitlyDefaultedDefaultC1Ev.carbon_thunk.(ptr %return), !dbg !27 // CHECK:STDOUT: ret void, !dbg !27 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable -// CHECK:STDOUT: define internal void @_ZN26ExplicitlyDefaultedDefaultC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN26ExplicitlyDefaultedDefaultC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !28 @@ -426,7 +426,7 @@ fn Four() { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Default.cad83ce9b7db87bf.Core:ExplicitlyDefaultedDefault.Cpp"(ptr sret([4 x i8]) %return) #2 !dbg !30 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN26ExplicitlyDefaultedDefaultC1Ev.carbon_thunk(ptr %return), !dbg !31 +// CHECK:STDOUT: call void @_ZN26ExplicitlyDefaultedDefaultC1Ev.carbon_thunk.(ptr %return), !dbg !31 // CHECK:STDOUT: ret void, !dbg !31 // CHECK:STDOUT: } // CHECK:STDOUT: @@ -534,12 +534,12 @@ fn Four() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc7_10.1.temp = alloca [4 x i8], align 1, !dbg !17 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_10.1.temp), !dbg !17 -// CHECK:STDOUT: call void @_ZN4CopyC1ERKS_.carbon_thunk(ptr %c, ptr %return), !dbg !17 +// CHECK:STDOUT: call void @_ZN4CopyC1ERKS_.carbon_thunk._(ptr %c, ptr %return), !dbg !17 // CHECK:STDOUT: ret void, !dbg !18 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN4CopyC1ERKS_.carbon_thunk(ptr noundef %0, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN4CopyC1ERKS_.carbon_thunk._(ptr noundef %0, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 @@ -554,7 +554,7 @@ fn Four() { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Copy.692da64e78c7deec.Core:Copy.Cpp"(ptr sret([4 x i8]) %return, ptr %self) #2 !dbg !22 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN4CopyC1ERKS_.carbon_thunk(ptr %self, ptr %return), !dbg !26 +// CHECK:STDOUT: call void @_ZN4CopyC1ERKS_.carbon_thunk._(ptr %self, ptr %return), !dbg !26 // CHECK:STDOUT: ret void, !dbg !26 // CHECK:STDOUT: } // CHECK:STDOUT: @@ -633,12 +633,12 @@ fn Four() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc7_44.1.temp = alloca [8 x i8], align 1, !dbg !14 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_44.1.temp), !dbg !14 -// CHECK:STDOUT: call void @_ZN7DerivedC1Ev.carbon_thunk(ptr %.loc7_44.1.temp), !dbg !14 +// CHECK:STDOUT: call void @_ZN7DerivedC1Ev.carbon_thunk.(ptr %.loc7_44.1.temp), !dbg !14 // CHECK:STDOUT: ret void, !dbg !15 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable -// CHECK:STDOUT: define internal void @_ZN7DerivedC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN7DerivedC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !16 @@ -712,14 +712,14 @@ fn Four() { // CHECK:STDOUT: %.loc7_26.1.temp = alloca [1 x i8], align 1, !dbg !14 // CHECK:STDOUT: %.loc8_19.2.temp = alloca [1 x i8], align 1, !dbg !15 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_26.1.temp), !dbg !14 -// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk(ptr %.loc7_26.1.temp), !dbg !14 +// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk.(ptr %.loc7_26.1.temp), !dbg !14 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc8_19.2.temp), !dbg !15 -// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk_tuple(ptr %.loc8_19.2.temp), !dbg !15 +// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk_tuple.(ptr %.loc8_19.2.temp), !dbg !15 // CHECK:STDOUT: ret void, !dbg !16 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !17 @@ -729,7 +729,7 @@ fn Four() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk_tuple(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk_tuple.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !17 @@ -745,16 +745,16 @@ fn Four() { // CHECK:STDOUT: %.loc13_18.1.temp = alloca [1 x i8], align 1, !dbg !22 // CHECK:STDOUT: %.loc14_21.2.temp = alloca [1 x i8], align 1, !dbg !23 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc12_27.1.temp), !dbg !21 -// CHECK:STDOUT: call void @_ZN1CC1Ei.carbon_thunk(i32 1, ptr %.loc12_27.1.temp), !dbg !21 +// CHECK:STDOUT: call void @_ZN1CC1Ei.carbon_thunk._(i32 1, ptr %.loc12_27.1.temp), !dbg !21 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc13_18.1.temp), !dbg !22 -// CHECK:STDOUT: call void @_ZN1CC1Ei.carbon_thunk(i32 2, ptr %.loc13_18.1.temp), !dbg !22 +// CHECK:STDOUT: call void @_ZN1CC1Ei.carbon_thunk._(i32 2, ptr %.loc13_18.1.temp), !dbg !22 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc14_21.2.temp), !dbg !23 -// CHECK:STDOUT: call void @_ZN1CC1Ei.carbon_thunk_tuple(i32 3, ptr %.loc14_21.2.temp), !dbg !23 +// CHECK:STDOUT: call void @_ZN1CC1Ei.carbon_thunk_tuple._(i32 3, ptr %.loc14_21.2.temp), !dbg !23 // CHECK:STDOUT: ret void, !dbg !24 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ei.carbon_thunk(i32 noundef %0, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ei.carbon_thunk._(i32 noundef %0, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 @@ -767,7 +767,7 @@ fn Four() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ei.carbon_thunk_tuple(i32 noundef %0, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ei.carbon_thunk_tuple._(i32 noundef %0, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 @@ -785,14 +785,14 @@ fn Four() { // CHECK:STDOUT: %.loc18_30.1.temp = alloca [1 x i8], align 1, !dbg !26 // CHECK:STDOUT: %.loc19_23.2.temp = alloca [1 x i8], align 1, !dbg !27 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc18_30.1.temp), !dbg !26 -// CHECK:STDOUT: call void @_ZN1CC1Eii.carbon_thunk(i32 1, i32 2, ptr %.loc18_30.1.temp), !dbg !26 +// CHECK:STDOUT: call void @_ZN1CC1Eii.carbon_thunk.__(i32 1, i32 2, ptr %.loc18_30.1.temp), !dbg !26 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc19_23.2.temp), !dbg !27 -// CHECK:STDOUT: call void @_ZN1CC1Eii.carbon_thunk_tuple(i32 3, i32 4, ptr %.loc19_23.2.temp), !dbg !27 +// CHECK:STDOUT: call void @_ZN1CC1Eii.carbon_thunk_tuple.__(i32 3, i32 4, ptr %.loc19_23.2.temp), !dbg !27 // CHECK:STDOUT: ret void, !dbg !28 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Eii.carbon_thunk(i32 noundef %0, i32 noundef %1, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Eii.carbon_thunk.__(i32 noundef %0, i32 noundef %1, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 @@ -808,7 +808,7 @@ fn Four() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Eii.carbon_thunk_tuple(i32 noundef %0, i32 noundef %1, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Eii.carbon_thunk_tuple.__(i32 noundef %0, i32 noundef %1, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 @@ -829,14 +829,14 @@ fn Four() { // CHECK:STDOUT: %.loc23_33.1.temp = alloca [1 x i8], align 1, !dbg !30 // CHECK:STDOUT: %.loc24_26.2.temp = alloca [1 x i8], align 1, !dbg !31 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc23_33.1.temp), !dbg !30 -// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk3(i32 1, i32 2, i32 3, ptr %.loc23_33.1.temp), !dbg !30 +// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk.___(i32 1, i32 2, i32 3, ptr %.loc23_33.1.temp), !dbg !30 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc24_26.2.temp), !dbg !31 -// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk_tuple3(i32 4, i32 5, i32 6, ptr %.loc24_26.2.temp), !dbg !31 +// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk_tuple.___(i32 4, i32 5, i32 6, ptr %.loc24_26.2.temp), !dbg !31 // CHECK:STDOUT: ret void, !dbg !32 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk3(i32 noundef %0, i32 noundef %1, i32 noundef %2, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk.___(i32 noundef %0, i32 noundef %1, i32 noundef %2, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 @@ -855,7 +855,7 @@ fn Four() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk_tuple3(i32 noundef %0, i32 noundef %1, i32 noundef %2, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk_tuple.___(i32 noundef %0, i32 noundef %1, i32 noundef %2, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 @@ -879,14 +879,14 @@ fn Four() { // CHECK:STDOUT: %.loc28_36.1.temp = alloca [1 x i8], align 1, !dbg !34 // CHECK:STDOUT: %.loc29_29.2.temp = alloca [1 x i8], align 1, !dbg !35 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc28_36.1.temp), !dbg !34 -// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk(i32 1, i32 2, i32 3, i32 4, ptr %.loc28_36.1.temp), !dbg !34 +// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk.____(i32 1, i32 2, i32 3, i32 4, ptr %.loc28_36.1.temp), !dbg !34 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc29_29.2.temp), !dbg !35 -// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk_tuple(i32 5, i32 6, i32 7, i32 8, ptr %.loc29_29.2.temp), !dbg !35 +// CHECK:STDOUT: call void @_ZN1CC1Eiiii.carbon_thunk_tuple.____(i32 5, i32 6, i32 7, i32 8, ptr %.loc29_29.2.temp), !dbg !35 // CHECK:STDOUT: ret void, !dbg !36 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk.____(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 @@ -908,7 +908,7 @@ fn Four() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk_tuple(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Eiiii.carbon_thunk_tuple.____(i32 noundef %0, i32 noundef %1, i32 noundef %2, i32 noundef %3, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca i32, align 4 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 @@ -983,7 +983,7 @@ fn Four() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder ptr @_ZN1CC1Ei.carbon_thunk, { 1, 0 } +// CHECK:STDOUT: uselistorder ptr @_ZN1CC1Ei.carbon_thunk._, { 1, 0 } // CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nounwind } diff --git a/toolchain/lower/testdata/interop/cpp/copy_vs_move.carbon b/toolchain/lower/testdata/interop/cpp/copy_vs_move.carbon new file mode 100644 index 000000000000..1c47445c2885 --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/copy_vs_move.carbon @@ -0,0 +1,504 @@ +// 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/destroy.carbon +// EXTRA-ARGS: --clang-arg=-fno-exceptions +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/copy_vs_move.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/copy_vs_move.carbon + +// --- copyable.carbon +library "[[@TEST_NAME]]"; + +import Cpp; +inline Cpp ''' +struct Copyable { + Copyable(const Copyable&); + Copyable& operator=(const Copyable&); + ~Copyable(); +}; +Copyable make(); +void pass(Copyable); +'''; + +var c: Cpp.Copyable = Cpp.make(); + +fn PassGlobal() { + Cpp.pass(c); +} + +fn PassTemporary() { + Cpp.pass(Cpp.make()); +} + +fn PassValue(c: Cpp.Copyable) { + Cpp.pass(c); +} + +fn PassRef(ref c: Cpp.Copyable) { + Cpp.pass(c); +} + +// --- copy_or_move.carbon +library "[[@TEST_NAME]]"; + +import Cpp; +inline Cpp ''' +struct CopyOrMove { + CopyOrMove(const CopyOrMove&); + CopyOrMove& operator=(const CopyOrMove&); + CopyOrMove(CopyOrMove&&); + CopyOrMove& operator=(CopyOrMove&&); + ~CopyOrMove(); +}; +CopyOrMove make(); +void pass(CopyOrMove); +'''; + +var c: Cpp.CopyOrMove = Cpp.make(); + +fn PassGlobal() { + Cpp.pass(c); +} + +fn PassTemporary() { + Cpp.pass(Cpp.make()); +} + +fn PassValue(c: Cpp.CopyOrMove) { + Cpp.pass(c); +} + +fn PassRef(ref c: Cpp.CopyOrMove) { + Cpp.pass(c); +} + +// --- move_only.carbon +library "[[@TEST_NAME]]"; + +import Cpp; +inline Cpp ''' +namespace std { +template T&& move(T& t) { return static_cast(t); } +} + +struct MoveOnly { + MoveOnly(const MoveOnly&) = delete; + MoveOnly& operator=(const MoveOnly&) = delete; + MoveOnly(MoveOnly&&); + MoveOnly& operator=(MoveOnly&&); + ~MoveOnly(); +}; +MoveOnly make(); +void pass(MoveOnly); +'''; + +var c: Cpp.MoveOnly = Cpp.make(); + +fn PassGlobalByMove() { + // TODO: This should be accepted. + // Cpp.pass(Cpp.std.move(ref c)); +} + +fn PassTemporary() { + Cpp.pass(Cpp.make()); +} + +// CHECK:STDOUT: ; ModuleID = 'copyable.carbon' +// CHECK:STDOUT: source_filename = "copyable.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: %struct.Copyable = type { i8 } +// CHECK:STDOUT: +// CHECK:STDOUT: @_Cc.Main = global [1 x i8] zeroinitializer +// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }] +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_Z4makev.carbon_thunk.(ptr noundef %return) #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !11 +// CHECK:STDOUT: call void @_Z4makev(ptr dead_on_unwind writable sret(%struct.Copyable) align 1 %0) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassGlobal.Main() #1 !dbg !14 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4pass8Copyable.carbon_thunk._(ptr @_Cc.Main), !dbg !17 +// CHECK:STDOUT: ret void, !dbg !18 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_Z4pass8Copyable.carbon_thunk._(ptr noundef %0) #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.addr = alloca ptr, align 8 +// CHECK:STDOUT: %agg.tmp = alloca %struct.Copyable, align 1 +// CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %1 = load ptr, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: call void @_ZN8CopyableC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp, ptr noundef nonnull align 1 dereferenceable(1) %1) +// CHECK:STDOUT: call void @_Z4pass8Copyable(ptr noundef %agg.tmp) +// CHECK:STDOUT: call void @_ZN8CopyableD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp) #1 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassTemporary.Main() #1 !dbg !19 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc21_21.1.temp = alloca [1 x i8], align 1, !dbg !20 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc21_21.1.temp), !dbg !20 +// CHECK:STDOUT: call void @_Z4makev.carbon_thunk.(ptr %.loc21_21.1.temp), !dbg !20 +// CHECK:STDOUT: call void @_Z4pass8Copyable.carbon_thunk._(ptr %.loc21_21.1.temp), !dbg !21 +// CHECK:STDOUT: call void @_ZN8CopyableD1Ev(ptr %.loc21_21.1.temp), !dbg !20 +// CHECK:STDOUT: ret void, !dbg !22 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: declare void @_ZN8CopyableD1Ev(ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassValue.Main(ptr %c) #1 !dbg !23 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4pass8Copyable.carbon_thunk._(ptr %c), !dbg !29 +// CHECK:STDOUT: ret void, !dbg !30 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassRef.Main(ptr %c) #1 !dbg !31 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4pass8Copyable.carbon_thunk._(ptr %c), !dbg !34 +// CHECK:STDOUT: ret void, !dbg !35 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #3 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define internal void @_C__global_init.Main() #1 !dbg !36 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4makev.carbon_thunk.(ptr @_Cc.Main), !dbg !37 +// CHECK:STDOUT: ret void, !dbg !38 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z4makev(ptr dead_on_unwind writable sret(%struct.Copyable) align 1) #4 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z4pass8Copyable(ptr noundef) #4 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_ZN8CopyableC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1), ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #4 +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { alwaysinline mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #1 = { nounwind } +// CHECK:STDOUT: attributes #2 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #4 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// 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 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "copyable.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!8, !8, i64 0} +// CHECK:STDOUT: !8 = !{!"int", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"omnipotent char", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !11 = !{!12, !12, i64 0} +// CHECK:STDOUT: !12 = !{!"p1 _ZTS8Copyable", !13, i64 0} +// CHECK:STDOUT: !13 = !{!"any pointer", !9, i64 0} +// CHECK:STDOUT: !14 = distinct !DISubprogram(name: "PassGlobal", linkageName: "_CPassGlobal.Main", scope: null, file: !6, line: 16, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !15 = !DISubroutineType(types: !16) +// CHECK:STDOUT: !16 = !{null} +// CHECK:STDOUT: !17 = !DILocation(line: 17, column: 3, scope: !14) +// CHECK:STDOUT: !18 = !DILocation(line: 16, column: 1, scope: !14) +// CHECK:STDOUT: !19 = distinct !DISubprogram(name: "PassTemporary", linkageName: "_CPassTemporary.Main", scope: null, file: !6, line: 20, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !20 = !DILocation(line: 21, column: 12, scope: !19) +// CHECK:STDOUT: !21 = !DILocation(line: 21, column: 3, scope: !19) +// CHECK:STDOUT: !22 = !DILocation(line: 20, column: 1, scope: !19) +// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "PassValue", linkageName: "_CPassValue.Main", scope: null, file: !6, line: 24, type: !24, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !27) +// CHECK:STDOUT: !24 = !DISubroutineType(types: !25) +// CHECK:STDOUT: !25 = !{null, !26} +// CHECK:STDOUT: !26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !27 = !{!28} +// CHECK:STDOUT: !28 = !DILocalVariable(arg: 1, scope: !23, type: !26) +// CHECK:STDOUT: !29 = !DILocation(line: 25, column: 3, scope: !23) +// CHECK:STDOUT: !30 = !DILocation(line: 24, column: 1, scope: !23) +// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "PassRef", linkageName: "_CPassRef.Main", scope: null, file: !6, line: 28, type: !24, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !32) +// CHECK:STDOUT: !32 = !{!33} +// CHECK:STDOUT: !33 = !DILocalVariable(arg: 1, scope: !31, type: !26) +// CHECK:STDOUT: !34 = !DILocation(line: 29, column: 3, scope: !31) +// CHECK:STDOUT: !35 = !DILocation(line: 28, column: 1, scope: !31) +// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "__global_init", linkageName: "_C__global_init.Main", scope: null, file: !6, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !37 = !DILocation(line: 14, column: 23, scope: !36) +// CHECK:STDOUT: !38 = !DILocation(line: 0, scope: !36) +// CHECK:STDOUT: ; ModuleID = 'copy_or_move.carbon' +// CHECK:STDOUT: source_filename = "copy_or_move.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: %struct.CopyOrMove = type { i8 } +// CHECK:STDOUT: +// CHECK:STDOUT: @_Cc.Main = global [1 x i8] zeroinitializer +// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }] +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_Z4makev.carbon_thunk.(ptr noundef %return) #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !11 +// CHECK:STDOUT: call void @_Z4makev(ptr dead_on_unwind writable sret(%struct.CopyOrMove) align 1 %0) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassGlobal.Main() #1 !dbg !14 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4pass10CopyOrMove.carbon_thunk._(ptr @_Cc.Main), !dbg !17 +// CHECK:STDOUT: ret void, !dbg !18 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_Z4pass10CopyOrMove.carbon_thunk._(ptr noundef %0) #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.addr = alloca ptr, align 8 +// CHECK:STDOUT: %agg.tmp = alloca %struct.CopyOrMove, align 1 +// CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %1 = load ptr, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: call void @_ZN10CopyOrMoveC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp, ptr noundef nonnull align 1 dereferenceable(1) %1) +// CHECK:STDOUT: call void @_Z4pass10CopyOrMove(ptr noundef %agg.tmp) +// CHECK:STDOUT: call void @_ZN10CopyOrMoveD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp) #1 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassTemporary.Main() #1 !dbg !19 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %_.var = alloca [1 x i8], align 1, !dbg !20 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !20 +// CHECK:STDOUT: call void @_Z4makev.carbon_thunk.(ptr %_.var), !dbg !21 +// CHECK:STDOUT: call void @_Z4pass10CopyOrMove.carbon_thunk.v(ptr %_.var), !dbg !22 +// CHECK:STDOUT: call void @_ZN10CopyOrMoveD1Ev(ptr %_.var), !dbg !20 +// CHECK:STDOUT: ret void, !dbg !23 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_Z4pass10CopyOrMove.carbon_thunk.v(ptr noundef %0) #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.addr = alloca ptr, align 8 +// CHECK:STDOUT: %agg.tmp = alloca %struct.CopyOrMove, align 1 +// CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %1 = load ptr, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: call void @_ZN10CopyOrMoveC1EOS_(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp, ptr noundef nonnull align 1 dereferenceable(1) %1) +// CHECK:STDOUT: call void @_Z4pass10CopyOrMove(ptr noundef %agg.tmp) +// CHECK:STDOUT: call void @_ZN10CopyOrMoveD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp) #1 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: declare void @_ZN10CopyOrMoveD1Ev(ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassValue.Main(ptr %c) #1 !dbg !24 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4pass10CopyOrMove.carbon_thunk._(ptr %c), !dbg !30 +// CHECK:STDOUT: ret void, !dbg !31 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassRef.Main(ptr %c) #1 !dbg !32 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4pass10CopyOrMove.carbon_thunk._(ptr %c), !dbg !35 +// CHECK:STDOUT: ret void, !dbg !36 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #3 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define internal void @_C__global_init.Main() #1 !dbg !37 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4makev.carbon_thunk.(ptr @_Cc.Main), !dbg !38 +// CHECK:STDOUT: ret void, !dbg !39 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z4makev(ptr dead_on_unwind writable sret(%struct.CopyOrMove) align 1) #4 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z4pass10CopyOrMove(ptr noundef) #4 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_ZN10CopyOrMoveC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1), ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #4 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_ZN10CopyOrMoveC1EOS_(ptr noundef nonnull align 1 dereferenceable(1), ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #4 +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @_ZN10CopyOrMoveD1Ev, { 1, 2, 0 } +// CHECK:STDOUT: uselistorder ptr @_Z4pass10CopyOrMove, { 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { alwaysinline mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #1 = { nounwind } +// CHECK:STDOUT: attributes #2 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #4 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// 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 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "copy_or_move.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!8, !8, i64 0} +// CHECK:STDOUT: !8 = !{!"int", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"omnipotent char", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !11 = !{!12, !12, i64 0} +// CHECK:STDOUT: !12 = !{!"p1 _ZTS10CopyOrMove", !13, i64 0} +// CHECK:STDOUT: !13 = !{!"any pointer", !9, i64 0} +// CHECK:STDOUT: !14 = distinct !DISubprogram(name: "PassGlobal", linkageName: "_CPassGlobal.Main", scope: null, file: !6, line: 18, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !15 = !DISubroutineType(types: !16) +// CHECK:STDOUT: !16 = !{null} +// CHECK:STDOUT: !17 = !DILocation(line: 19, column: 3, scope: !14) +// CHECK:STDOUT: !18 = !DILocation(line: 18, column: 1, scope: !14) +// CHECK:STDOUT: !19 = distinct !DISubprogram(name: "PassTemporary", linkageName: "_CPassTemporary.Main", scope: null, file: !6, line: 22, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !20 = !DILocation(line: 13, column: 21, scope: !19) +// CHECK:STDOUT: !21 = !DILocation(line: 23, column: 12, scope: !19) +// CHECK:STDOUT: !22 = !DILocation(line: 23, column: 3, scope: !19) +// CHECK:STDOUT: !23 = !DILocation(line: 22, column: 1, scope: !19) +// CHECK:STDOUT: !24 = distinct !DISubprogram(name: "PassValue", linkageName: "_CPassValue.Main", scope: null, file: !6, line: 26, type: !25, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !28) +// CHECK:STDOUT: !25 = !DISubroutineType(types: !26) +// CHECK:STDOUT: !26 = !{null, !27} +// CHECK:STDOUT: !27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !28 = !{!29} +// CHECK:STDOUT: !29 = !DILocalVariable(arg: 1, scope: !24, type: !27) +// CHECK:STDOUT: !30 = !DILocation(line: 27, column: 3, scope: !24) +// CHECK:STDOUT: !31 = !DILocation(line: 26, column: 1, scope: !24) +// CHECK:STDOUT: !32 = distinct !DISubprogram(name: "PassRef", linkageName: "_CPassRef.Main", scope: null, file: !6, line: 30, type: !25, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !33) +// CHECK:STDOUT: !33 = !{!34} +// CHECK:STDOUT: !34 = !DILocalVariable(arg: 1, scope: !32, type: !27) +// CHECK:STDOUT: !35 = !DILocation(line: 31, column: 3, scope: !32) +// CHECK:STDOUT: !36 = !DILocation(line: 30, column: 1, scope: !32) +// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "__global_init", linkageName: "_C__global_init.Main", scope: null, file: !6, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !38 = !DILocation(line: 16, column: 25, scope: !37) +// CHECK:STDOUT: !39 = !DILocation(line: 0, scope: !37) +// CHECK:STDOUT: ; ModuleID = 'move_only.carbon' +// CHECK:STDOUT: source_filename = "move_only.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: %struct.MoveOnly = type { i8 } +// CHECK:STDOUT: +// CHECK:STDOUT: @_Cc.Main = global [1 x i8] zeroinitializer +// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }] +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_Z4makev.carbon_thunk.(ptr noundef %return) #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !11 +// CHECK:STDOUT: call void @_Z4makev(ptr dead_on_unwind writable sret(%struct.MoveOnly) align 1 %0) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassGlobalByMove.Main() #1 !dbg !14 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !17 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CPassTemporary.Main() #1 !dbg !18 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %_.var = alloca [1 x i8], align 1, !dbg !19 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !19 +// CHECK:STDOUT: call void @_Z4makev.carbon_thunk.(ptr %_.var), !dbg !20 +// CHECK:STDOUT: call void @_Z4pass8MoveOnly.carbon_thunk.v(ptr %_.var), !dbg !21 +// CHECK:STDOUT: call void @_ZN8MoveOnlyD1Ev(ptr %_.var), !dbg !19 +// CHECK:STDOUT: ret void, !dbg !22 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_Z4pass8MoveOnly.carbon_thunk.v(ptr noundef %0) #0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.addr = alloca ptr, align 8 +// CHECK:STDOUT: %agg.tmp = alloca %struct.MoveOnly, align 1 +// CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %1 = load ptr, ptr %.addr, align 8, !tbaa !11 +// CHECK:STDOUT: call void @_ZN8MoveOnlyC1EOS_(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp, ptr noundef nonnull align 1 dereferenceable(1) %1) +// CHECK:STDOUT: call void @_Z4pass8MoveOnly(ptr noundef %agg.tmp) +// CHECK:STDOUT: call void @_ZN8MoveOnlyD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %agg.tmp) #1 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: declare void @_ZN8MoveOnlyD1Ev(ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #2 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #3 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define internal void @_C__global_init.Main() #1 !dbg !23 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z4makev.carbon_thunk.(ptr @_Cc.Main), !dbg !24 +// CHECK:STDOUT: ret void, !dbg !25 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z4makev(ptr dead_on_unwind writable sret(%struct.MoveOnly) align 1) #4 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z4pass8MoveOnly(ptr noundef) #4 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_ZN8MoveOnlyC1EOS_(ptr noundef nonnull align 1 dereferenceable(1), ptr noundef nonnull align 1 dereferenceable(1)) unnamed_addr #4 +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @_ZN8MoveOnlyD1Ev, { 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { alwaysinline mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #1 = { nounwind } +// CHECK:STDOUT: attributes #2 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #4 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// 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 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "move_only.carbon", directory: "") +// CHECK:STDOUT: !7 = !{!8, !8, i64 0} +// CHECK:STDOUT: !8 = !{!"int", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"omnipotent char", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !11 = !{!12, !12, i64 0} +// CHECK:STDOUT: !12 = !{!"p1 _ZTS8MoveOnly", !13, i64 0} +// CHECK:STDOUT: !13 = !{!"any pointer", !9, i64 0} +// CHECK:STDOUT: !14 = distinct !DISubprogram(name: "PassGlobalByMove", linkageName: "_CPassGlobalByMove.Main", scope: null, file: !6, line: 22, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !15 = !DISubroutineType(types: !16) +// CHECK:STDOUT: !16 = !{null} +// CHECK:STDOUT: !17 = !DILocation(line: 22, column: 1, scope: !14) +// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "PassTemporary", linkageName: "_CPassTemporary.Main", scope: null, file: !6, line: 27, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !19 = !DILocation(line: 17, column: 19, scope: !18) +// CHECK:STDOUT: !20 = !DILocation(line: 28, column: 12, scope: !18) +// CHECK:STDOUT: !21 = !DILocation(line: 28, column: 3, scope: !18) +// CHECK:STDOUT: !22 = !DILocation(line: 27, column: 1, scope: !18) +// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "__global_init", linkageName: "_C__global_init.Main", scope: null, file: !6, type: !15, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !24 = !DILocation(line: 20, column: 23, scope: !23) +// CHECK:STDOUT: !25 = !DILocation(line: 0, scope: !23) diff --git a/toolchain/lower/testdata/interop/cpp/extern_c.carbon b/toolchain/lower/testdata/interop/cpp/extern_c.carbon index 2480c2ca3de4..5d398ee19039 100644 --- a/toolchain/lower/testdata/interop/cpp/extern_c.carbon +++ b/toolchain/lower/testdata/interop/cpp/extern_c.carbon @@ -227,12 +227,12 @@ fn MyF() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CMyF.Main(ptr sret({}) %return, ptr %a, ptr %b) #0 !dbg !11 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Zpl1XS_.carbon_thunk(ptr %a, ptr %b, ptr %return), !dbg !18 +// CHECK:STDOUT: call void @_Zpl1XS_.carbon_thunk.__(ptr %a, ptr %b, ptr %return), !dbg !18 // CHECK:STDOUT: ret void, !dbg !19 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Zpl1XS_.carbon_thunk(ptr noundef %0, ptr noundef %1, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Zpl1XS_.carbon_thunk.__(ptr noundef %0, ptr noundef %1, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %.addr1 = alloca ptr, align 8 diff --git a/toolchain/lower/testdata/interop/cpp/function_decl.carbon b/toolchain/lower/testdata/interop/cpp/function_decl.carbon index 8d2301d3de7c..6cfa765313c2 100644 --- a/toolchain/lower/testdata/interop/cpp/function_decl.carbon +++ b/toolchain/lower/testdata/interop/cpp/function_decl.carbon @@ -385,13 +385,13 @@ fn MyF() -> i32 { // CHECK:STDOUT: define i32 @_CMyF.Main() #0 !dbg !11 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %value.var = alloca i32, align 4, !dbg !15 -// CHECK:STDOUT: call void @_Z13NoReturnValueii.carbon_thunk0(), !dbg !16 -// CHECK:STDOUT: call void @_Z13NoReturnValueii.carbon_thunk1(i32 3), !dbg !17 +// CHECK:STDOUT: call void @_Z13NoReturnValueii.carbon_thunk.(), !dbg !16 +// CHECK:STDOUT: call void @_Z13NoReturnValueii.carbon_thunk._(i32 3), !dbg !17 // CHECK:STDOUT: call void @_Z13NoReturnValueii(i32 3, i32 4), !dbg !18 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %value.var), !dbg !15 -// CHECK:STDOUT: %SimpleReturnValue__carbon_thunk.call.loc11 = call i32 @_Z17SimpleReturnValueii.carbon_thunk0(), !dbg !19 +// CHECK:STDOUT: %SimpleReturnValue__carbon_thunk.call.loc11 = call i32 @_Z17SimpleReturnValueii.carbon_thunk.(), !dbg !19 // CHECK:STDOUT: store i32 %SimpleReturnValue__carbon_thunk.call.loc11, ptr %value.var, align 4, !dbg !15 -// CHECK:STDOUT: %SimpleReturnValue__carbon_thunk.call.loc12 = call i32 @_Z17SimpleReturnValueii.carbon_thunk1(i32 3), !dbg !20 +// CHECK:STDOUT: %SimpleReturnValue__carbon_thunk.call.loc12 = call i32 @_Z17SimpleReturnValueii.carbon_thunk._(i32 3), !dbg !20 // CHECK:STDOUT: store i32 %SimpleReturnValue__carbon_thunk.call.loc12, ptr %value.var, align 4, !dbg !21 // CHECK:STDOUT: %SimpleReturnValue.call = call i32 @_Z17SimpleReturnValueii(i32 3, i32 4), !dbg !22 // CHECK:STDOUT: store i32 %SimpleReturnValue.call, ptr %value.var, align 4, !dbg !23 @@ -401,14 +401,14 @@ fn MyF() -> i32 { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z13NoReturnValueii.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal void @_Z13NoReturnValueii.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: call void @_Z13NoReturnValueii(i32 noundef 1, i32 noundef 2) // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z13NoReturnValueii.carbon_thunk1(i32 noundef %a) #1 { +// CHECK:STDOUT: define internal void @_Z13NoReturnValueii.carbon_thunk._(i32 noundef %a) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %a.addr = alloca i32, align 4 // CHECK:STDOUT: store i32 %a, ptr %a.addr, align 4, !tbaa !7 @@ -420,14 +420,14 @@ fn MyF() -> i32 { // CHECK:STDOUT: declare void @_Z13NoReturnValueii(i32 noundef, i32 noundef) #2 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef i32 @_Z17SimpleReturnValueii.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal noundef i32 @_Z17SimpleReturnValueii.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %call = call noundef i32 @_Z17SimpleReturnValueii(i32 noundef 1, i32 noundef 2) // CHECK:STDOUT: ret i32 %call // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef i32 @_Z17SimpleReturnValueii.carbon_thunk1(i32 noundef %a) #1 { +// CHECK:STDOUT: define internal noundef i32 @_Z17SimpleReturnValueii.carbon_thunk._(i32 noundef %a) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %a.addr = alloca i32, align 4 // CHECK:STDOUT: store i32 %a, ptr %a.addr, align 4, !tbaa !7 diff --git a/toolchain/lower/testdata/interop/cpp/method.carbon b/toolchain/lower/testdata/interop/cpp/method.carbon index 007daf64e52c..994427704d4a 100644 --- a/toolchain/lower/testdata/interop/cpp/method.carbon +++ b/toolchain/lower/testdata/interop/cpp/method.carbon @@ -86,7 +86,7 @@ fn Call(n: Cpp.NeedThunk) { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define i32 @_CUseVal.Main(ptr %a) #0 !dbg !11 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %by_val__carbon_thunk.call = call i32 @_ZNK1A6by_valEv.carbon_thunk(ptr %a), !dbg !18 +// CHECK:STDOUT: %by_val__carbon_thunk.call = call i32 @_ZNK1A6by_valEv.carbon_thunk._(ptr %a), !dbg !18 // CHECK:STDOUT: ret i32 %by_val__carbon_thunk.call, !dbg !19 // CHECK:STDOUT: } // CHECK:STDOUT: @@ -95,7 +95,7 @@ fn Call(n: Cpp.NeedThunk) { // CHECK:STDOUT: declare void @_ZN1A5virt1Ev(ptr noundef nonnull align 8 dereferenceable(12)) unnamed_addr #1 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef i32 @_ZNK1A6by_valEv.carbon_thunk(ptr noundef nonnull align 8 dereferenceable(12) %this) #2 { +// CHECK:STDOUT: define internal noundef i32 @_ZNK1A6by_valEv.carbon_thunk._(ptr noundef nonnull align 8 dereferenceable(12) %this) #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !20 @@ -284,16 +284,16 @@ fn Call(n: Cpp.NeedThunk) { // CHECK:STDOUT: %.loc7_14.3.temp = alloca i8, align 1, !dbg !17 // CHECK:STDOUT: %.loc8_14.3.temp = alloca i8, align 1, !dbg !18 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_14.3.temp), !dbg !17 -// CHECK:STDOUT: call void @_ZNK9NeedThunk8ImplicitEa.carbon_thunk(ptr %n, ptr @int_1.30e), !dbg !19 +// CHECK:STDOUT: call void @_ZNK9NeedThunk8ImplicitEa.carbon_thunk.__(ptr %n, ptr @int_1.30e), !dbg !19 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc8_14.3.temp), !dbg !18 -// CHECK:STDOUT: call void @_ZNH9NeedThunk8ExplicitES_a.carbon_thunk(ptr %n, ptr @int_1.30e), !dbg !20 +// CHECK:STDOUT: call void @_ZNH9NeedThunk8ExplicitES_a.carbon_thunk.__(ptr %n, ptr @int_1.30e), !dbg !20 // CHECK:STDOUT: call void @"_COp.43bece552030817c:core.Destroy.Core"(ptr @int_1.30e), !dbg !18 // CHECK:STDOUT: call void @"_COp.43bece552030817c:core.Destroy.Core"(ptr @int_1.30e), !dbg !17 // CHECK:STDOUT: ret void, !dbg !21 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZNK9NeedThunk8ImplicitEa.carbon_thunk(ptr noundef nonnull align 1 dereferenceable(1) %this, ptr noundef %c) #1 { +// CHECK:STDOUT: define internal void @_ZNK9NeedThunk8ImplicitEa.carbon_thunk.__(ptr noundef nonnull align 1 dereferenceable(1) %this, ptr noundef %c) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %this.addr = alloca ptr, align 8 // CHECK:STDOUT: %c.addr = alloca ptr, align 8 @@ -307,7 +307,7 @@ fn Call(n: Cpp.NeedThunk) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZNH9NeedThunk8ExplicitES_a.carbon_thunk(ptr noundef %0, ptr noundef %c) #1 { +// CHECK:STDOUT: define internal void @_ZNH9NeedThunk8ExplicitES_a.carbon_thunk.__(ptr noundef %0, ptr noundef %c) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %c.addr = alloca ptr, align 8 diff --git a/toolchain/lower/testdata/interop/cpp/nullptr.carbon b/toolchain/lower/testdata/interop/cpp/nullptr.carbon index ea7a93b7394a..c5df966c4794 100644 --- a/toolchain/lower/testdata/interop/cpp/nullptr.carbon +++ b/toolchain/lower/testdata/interop/cpp/nullptr.carbon @@ -67,7 +67,7 @@ fn ConvertNullptrConstant() -> Core.Optional(i32*) { // CHECK:STDOUT: %Cpp.nullptr_t.as.Copy.impl.Op.call = call ptr @"_COp.NullptrT.CppCompat.Core:Copy.Core"(ptr poison), !dbg !15 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc14_22.1.temp), !dbg !15 // CHECK:STDOUT: store ptr %Cpp.nullptr_t.as.Copy.impl.Op.call, ptr %.loc14_22.1.temp, align 8, !dbg !15 -// CHECK:STDOUT: call void @_Z11TakeNullptrDn.carbon_thunk(ptr %.loc14_22.1.temp), !dbg !17 +// CHECK:STDOUT: call void @_Z11TakeNullptrDn.carbon_thunk._(ptr %.loc14_22.1.temp), !dbg !17 // CHECK:STDOUT: call void @"_COp.705e422c84320121:core.Destroy.Core"(ptr %.loc14_22.1.temp), !dbg !15 // CHECK:STDOUT: call void @"_COp.e34c165b4a1e692a:core.Destroy.Core"(ptr %.loc12_18.2.temp), !dbg !14 // CHECK:STDOUT: ret void, !dbg !18 @@ -76,7 +76,7 @@ fn ConvertNullptrConstant() -> Core.Optional(i32*) { // CHECK:STDOUT: declare void @_Z7TakePtrPi(ptr noundef) #1 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z11TakeNullptrDn.carbon_thunk(ptr noundef %n) #2 { +// CHECK:STDOUT: define internal void @_Z11TakeNullptrDn.carbon_thunk._(ptr noundef %n) #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %n.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %n, ptr %n.addr, align 8, !tbaa !19 @@ -130,7 +130,7 @@ fn ConvertNullptrConstant() -> Core.Optional(i32*) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %a.var = alloca ptr, align 8, !dbg !48 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a.var), !dbg !48 -// CHECK:STDOUT: call void @_Z13ReturnNullptrv.carbon_thunk(ptr %a.var), !dbg !49 +// CHECK:STDOUT: call void @_Z13ReturnNullptrv.carbon_thunk.(ptr %a.var), !dbg !49 // CHECK:STDOUT: %.loc28_10 = load ptr, ptr %a.var, align 8, !dbg !50 // CHECK:STDOUT: %Cpp.nullptr_t.as.ImplicitAs.impl.Convert.call = call ptr @"_CConvert.NullptrT.CppCompat.Core:ImplicitAs.a5972e826b98ae3c.Core.b88d1103f417c6d4"(ptr %.loc28_10), !dbg !51 // CHECK:STDOUT: call void @"_COp.705e422c84320121:core.Destroy.Core"(ptr %a.var), !dbg !48 @@ -138,7 +138,7 @@ fn ConvertNullptrConstant() -> Core.Optional(i32*) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z13ReturnNullptrv.carbon_thunk(ptr noundef %return) #2 { +// CHECK:STDOUT: define internal void @_Z13ReturnNullptrv.carbon_thunk.(ptr noundef %return) #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !19 @@ -153,7 +153,7 @@ fn ConvertNullptrConstant() -> Core.Optional(i32*) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc32_28.1.temp = alloca ptr, align 8, !dbg !55 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc32_28.1.temp), !dbg !55 -// CHECK:STDOUT: call void @_Z13ReturnNullptrv.carbon_thunk(ptr %.loc32_28.1.temp), !dbg !55 +// CHECK:STDOUT: call void @_Z13ReturnNullptrv.carbon_thunk.(ptr %.loc32_28.1.temp), !dbg !55 // CHECK:STDOUT: %.loc32_28.4 = load ptr, ptr %.loc32_28.1.temp, align 8, !dbg !55 // CHECK:STDOUT: %Cpp.nullptr_t.as.ImplicitAs.impl.Convert.call = call ptr @"_CConvert.NullptrT.CppCompat.Core:ImplicitAs.a5972e826b98ae3c.Core.b88d1103f417c6d4"(ptr %.loc32_28.4), !dbg !56 // CHECK:STDOUT: call void @"_COp.705e422c84320121:core.Destroy.Core"(ptr %.loc32_28.1.temp), !dbg !55 diff --git a/toolchain/lower/testdata/interop/cpp/operators.carbon b/toolchain/lower/testdata/interop/cpp/operators.carbon index e839e38cf840..b00db6aacf14 100644 --- a/toolchain/lower/testdata/interop/cpp/operators.carbon +++ b/toolchain/lower/testdata/interop/cpp/operators.carbon @@ -93,7 +93,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Zeq1AS_.carbon_thunk(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Zeq1AS_.carbon_thunk.__(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 @@ -119,7 +119,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Zne1AS_.carbon_thunk(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Zne1AS_.carbon_thunk.__(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 @@ -149,7 +149,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.3.temp = alloca i1, align 1, !dbg !34 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.3.temp), !dbg !34 -// CHECK:STDOUT: call void @_Zeq1AS_.carbon_thunk(ptr %self, ptr %other, ptr %.3.temp), !dbg !34 +// CHECK:STDOUT: call void @_Zeq1AS_.carbon_thunk.__(ptr %self, ptr %other, ptr %.3.temp), !dbg !34 // CHECK:STDOUT: %0 = load i1, ptr %.3.temp, align 1, !dbg !34 // CHECK:STDOUT: ret i1 %0, !dbg !34 // CHECK:STDOUT: } @@ -159,7 +159,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.3.temp = alloca i1, align 1, !dbg !39 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.3.temp), !dbg !39 -// CHECK:STDOUT: call void @_Zne1AS_.carbon_thunk(ptr %self, ptr %other, ptr %.3.temp), !dbg !39 +// CHECK:STDOUT: call void @_Zne1AS_.carbon_thunk.__(ptr %self, ptr %other, ptr %.3.temp), !dbg !39 // CHECK:STDOUT: %0 = load i1, ptr %.3.temp, align 1, !dbg !39 // CHECK:STDOUT: ret i1 %0, !dbg !39 // CHECK:STDOUT: } @@ -304,7 +304,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Zlt1AS_.carbon_thunk(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Zlt1AS_.carbon_thunk.__(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 @@ -330,7 +330,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Zle1AS_.carbon_thunk(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Zle1AS_.carbon_thunk.__(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 @@ -356,7 +356,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Zgt1AS_.carbon_thunk(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Zgt1AS_.carbon_thunk.__(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 @@ -382,7 +382,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Zge1AS_.carbon_thunk(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Zge1AS_.carbon_thunk.__(ptr noundef %x, ptr noundef %y, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %y.addr = alloca ptr, align 8 @@ -412,7 +412,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.3.temp = alloca i1, align 1, !dbg !34 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.3.temp), !dbg !34 -// CHECK:STDOUT: call void @_Zlt1AS_.carbon_thunk(ptr %self, ptr %other, ptr %.3.temp), !dbg !34 +// CHECK:STDOUT: call void @_Zlt1AS_.carbon_thunk.__(ptr %self, ptr %other, ptr %.3.temp), !dbg !34 // CHECK:STDOUT: %0 = load i1, ptr %.3.temp, align 1, !dbg !34 // CHECK:STDOUT: ret i1 %0, !dbg !34 // CHECK:STDOUT: } @@ -422,7 +422,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.3.temp = alloca i1, align 1, !dbg !39 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.3.temp), !dbg !39 -// CHECK:STDOUT: call void @_Zle1AS_.carbon_thunk(ptr %self, ptr %other, ptr %.3.temp), !dbg !39 +// CHECK:STDOUT: call void @_Zle1AS_.carbon_thunk.__(ptr %self, ptr %other, ptr %.3.temp), !dbg !39 // CHECK:STDOUT: %0 = load i1, ptr %.3.temp, align 1, !dbg !39 // CHECK:STDOUT: ret i1 %0, !dbg !39 // CHECK:STDOUT: } @@ -432,7 +432,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.3.temp = alloca i1, align 1, !dbg !44 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.3.temp), !dbg !44 -// CHECK:STDOUT: call void @_Zgt1AS_.carbon_thunk(ptr %self, ptr %other, ptr %.3.temp), !dbg !44 +// CHECK:STDOUT: call void @_Zgt1AS_.carbon_thunk.__(ptr %self, ptr %other, ptr %.3.temp), !dbg !44 // CHECK:STDOUT: %0 = load i1, ptr %.3.temp, align 1, !dbg !44 // CHECK:STDOUT: ret i1 %0, !dbg !44 // CHECK:STDOUT: } @@ -442,7 +442,7 @@ fn Driver(x: Cpp.A, y: Cpp.A) { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.3.temp = alloca i1, align 1, !dbg !49 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.3.temp), !dbg !49 -// CHECK:STDOUT: call void @_Zge1AS_.carbon_thunk(ptr %self, ptr %other, ptr %.3.temp), !dbg !49 +// CHECK:STDOUT: call void @_Zge1AS_.carbon_thunk.__(ptr %self, ptr %other, ptr %.3.temp), !dbg !49 // CHECK:STDOUT: %0 = load i1, ptr %.3.temp, align 1, !dbg !49 // CHECK:STDOUT: ret i1 %0, !dbg !49 // CHECK:STDOUT: } diff --git a/toolchain/lower/testdata/interop/cpp/parameters.carbon b/toolchain/lower/testdata/interop/cpp/parameters.carbon index ed79da3dddf8..02649c4aa022 100644 --- a/toolchain/lower/testdata/interop/cpp/parameters.carbon +++ b/toolchain/lower/testdata/interop/cpp/parameters.carbon @@ -129,10 +129,10 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: %.loc9_24.3.temp = alloca i16, align 2, !dbg !17 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_19.3.temp), !dbg !14 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_22.3.temp), !dbg !15 -// CHECK:STDOUT: call void @_Z11pass_signedasil.carbon_thunk(ptr @int_1.30e, ptr @int_2.305, i32 3, i64 4), !dbg !18 +// CHECK:STDOUT: call void @_Z11pass_signedasil.carbon_thunk.____(ptr @int_1.30e, ptr @int_2.305, i32 3, i64 4), !dbg !18 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc9_21.3.temp), !dbg !16 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc9_24.3.temp), !dbg !17 -// CHECK:STDOUT: call void @_Z13pass_unsignedhtjm.carbon_thunk(ptr @int_1.e80, ptr @int_2.fb2, i32 3, i64 4), !dbg !19 +// CHECK:STDOUT: call void @_Z13pass_unsignedhtjm.carbon_thunk.____(ptr @int_1.e80, ptr @int_2.fb2, i32 3, i64 4), !dbg !19 // CHECK:STDOUT: call void @"_COp.ecaf8c3e76291eee:core.Destroy.Core"(ptr @int_2.fb2), !dbg !17 // CHECK:STDOUT: call void @"_COp.3de38e83520d6bec:core.Destroy.Core"(ptr @int_1.e80), !dbg !16 // CHECK:STDOUT: call void @"_COp.406738f1b62008ed:core.Destroy.Core"(ptr @int_2.305), !dbg !15 @@ -141,7 +141,7 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z11pass_signedasil.carbon_thunk(ptr noundef %0, ptr noundef %1, i32 noundef %2, i64 noundef %3) #1 { +// CHECK:STDOUT: define internal void @_Z11pass_signedasil.carbon_thunk.____(ptr noundef %0, ptr noundef %1, i32 noundef %2, i64 noundef %3) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %.addr1 = alloca ptr, align 8 @@ -162,7 +162,7 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z13pass_unsignedhtjm.carbon_thunk(ptr noundef %0, ptr noundef %1, i32 noundef %2, i64 noundef %3) #1 { +// CHECK:STDOUT: define internal void @_Z13pass_unsignedhtjm.carbon_thunk.____(ptr noundef %0, ptr noundef %1, i32 noundef %2, i64 noundef %3) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %.addr1 = alloca ptr, align 8 @@ -217,19 +217,19 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: %.loc20_28.3.temp = alloca i16, align 2, !dbg !69 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc17_18.1.temp), !dbg !66 // CHECK:STDOUT: store i16 %a, ptr %.loc17_18.1.temp, align 2, !dbg !66 -// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk(ptr %.loc17_18.1.temp), !dbg !70 +// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk._(ptr %.loc17_18.1.temp), !dbg !70 // CHECK:STDOUT: %.loc18_18.2 = load i16, ptr %b, align 2, !dbg !67 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc18_18.3.temp), !dbg !67 // CHECK:STDOUT: store i16 %.loc18_18.2, ptr %.loc18_18.3.temp, align 2, !dbg !67 -// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk(ptr %.loc18_18.3.temp), !dbg !71 +// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk._(ptr %.loc18_18.3.temp), !dbg !71 // CHECK:STDOUT: %.loc19_18.1 = load i16, ptr @_Cc.Main, align 2, !dbg !68 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc19_18.2.temp), !dbg !68 // CHECK:STDOUT: store i16 %.loc19_18.1, ptr %.loc19_18.2.temp, align 2, !dbg !68 -// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk(ptr %.loc19_18.2.temp), !dbg !72 +// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk._(ptr %.loc19_18.2.temp), !dbg !72 // CHECK:STDOUT: %MakeShort.call = call i16 @_CMakeShort.Main(), !dbg !69 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc20_28.3.temp), !dbg !69 // CHECK:STDOUT: store i16 %MakeShort.call, ptr %.loc20_28.3.temp, align 2, !dbg !69 -// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk(ptr %.loc20_28.3.temp), !dbg !73 +// CHECK:STDOUT: call void @_Z10pass_shorts.carbon_thunk._(ptr %.loc20_28.3.temp), !dbg !73 // CHECK:STDOUT: call void @"_COp.406738f1b62008ed:core.Destroy.Core"(ptr %.loc20_28.3.temp), !dbg !69 // CHECK:STDOUT: call void @"_COp.406738f1b62008ed:core.Destroy.Core"(ptr %.loc19_18.2.temp), !dbg !68 // CHECK:STDOUT: call void @"_COp.406738f1b62008ed:core.Destroy.Core"(ptr %.loc18_18.3.temp), !dbg !67 @@ -238,7 +238,7 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z10pass_shorts.carbon_thunk(ptr noundef %0) #1 { +// CHECK:STDOUT: define internal void @_Z10pass_shorts.carbon_thunk._(ptr noundef %0) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !24 @@ -265,7 +265,7 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: declare void @_Z10pass_shorts(i16 noundef signext) #3 // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder ptr @_Z10pass_shorts.carbon_thunk, { 3, 2, 1, 0 } +// CHECK:STDOUT: uselistorder ptr @_Z10pass_shorts.carbon_thunk._, { 3, 2, 1, 0 } // CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 7, 6, 5, 4, 3, 2, 1, 0 } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nounwind } @@ -374,12 +374,12 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: store i32 2, ptr %.loc9_4.b, align 4, !dbg !16 // CHECK:STDOUT: %.loc10_4.c = getelementptr inbounds nuw [12 x i8], ptr %x.var, i32 0, i32 8, !dbg !17 // CHECK:STDOUT: store i32 3, ptr %.loc10_4.c, align 4, !dbg !17 -// CHECK:STDOUT: call void @_Z11pass_struct1X.carbon_thunk(ptr %x.var), !dbg !18 +// CHECK:STDOUT: call void @_Z11pass_struct1X.carbon_thunk._(ptr %x.var), !dbg !18 // CHECK:STDOUT: ret void, !dbg !19 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable -// CHECK:STDOUT: define internal void @_ZN1XC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1XC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !20 @@ -390,12 +390,12 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Default.17a84649916546b3.Core:X.Cpp"(ptr sret([12 x i8]) %return) #2 !dbg !23 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN1XC1Ev.carbon_thunk(ptr %return), !dbg !28 +// CHECK:STDOUT: call void @_ZN1XC1Ev.carbon_thunk.(ptr %return), !dbg !28 // CHECK:STDOUT: ret void, !dbg !28 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z11pass_struct1X.carbon_thunk(ptr noundef %0) #3 { +// CHECK:STDOUT: define internal void @_Z11pass_struct1X.carbon_thunk._(ptr noundef %0) #3 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %struct.X, align 4 @@ -493,12 +493,12 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: store i32 2, ptr %.loc9_4.b, align 4, !dbg !16 // CHECK:STDOUT: %.loc10_4.c = getelementptr inbounds nuw [12 x i8], ptr %y.var, i32 0, i32 8, !dbg !17 // CHECK:STDOUT: store i32 3, ptr %.loc10_4.c, align 4, !dbg !17 -// CHECK:STDOUT: call void @_Z11pass_struct1Y.carbon_thunk(ptr %y.var), !dbg !18 +// CHECK:STDOUT: call void @_Z11pass_struct1Y.carbon_thunk._(ptr %y.var), !dbg !18 // CHECK:STDOUT: ret void, !dbg !19 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z11pass_struct1Y.carbon_thunk(ptr noundef %0) #1 { +// CHECK:STDOUT: define internal void @_Z11pass_struct1Y.carbon_thunk._(ptr noundef %0) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.Y, align 4 @@ -517,14 +517,14 @@ fn PassValueExpr(y: Cpp.Y) { // CHECK:STDOUT: %.loc17_24.1.temp = alloca [12 x i8], align 1, !dbg !24 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc17_24.1.temp), !dbg !24 // CHECK:STDOUT: call void @_CMake.Main(ptr %.loc17_24.1.temp), !dbg !24 -// CHECK:STDOUT: call void @_Z11pass_struct1Y.carbon_thunk(ptr %.loc17_24.1.temp), !dbg !25 +// CHECK:STDOUT: call void @_Z11pass_struct1Y.carbon_thunk._(ptr %.loc17_24.1.temp), !dbg !25 // CHECK:STDOUT: ret void, !dbg !26 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CPassValueExpr.Main(ptr %y) #0 !dbg !27 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z11pass_struct1Y.carbon_thunk(ptr %y), !dbg !33 +// CHECK:STDOUT: call void @_Z11pass_struct1Y.carbon_thunk._(ptr %y), !dbg !33 // CHECK:STDOUT: ret void, !dbg !34 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/testdata/interop/cpp/pointer.carbon b/toolchain/lower/testdata/interop/cpp/pointer.carbon index 3b340a725505..eab466cb2aa5 100644 --- a/toolchain/lower/testdata/interop/cpp/pointer.carbon +++ b/toolchain/lower/testdata/interop/cpp/pointer.carbon @@ -128,12 +128,12 @@ fn Convert() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CPassPtrWithThunk.Main(ptr %p) #0 !dbg !24 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z16TakePtrWithThunkP1Ci.carbon_thunk1(ptr %p), !dbg !27 +// CHECK:STDOUT: call void @_Z16TakePtrWithThunkP1Ci.carbon_thunk._(ptr %p), !dbg !27 // CHECK:STDOUT: ret void, !dbg !28 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z16TakePtrWithThunkP1Ci.carbon_thunk1(ptr noundef %0) #2 { +// CHECK:STDOUT: define internal void @_Z16TakePtrWithThunkP1Ci.carbon_thunk._(ptr noundef %0) #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !29 @@ -145,12 +145,12 @@ fn Convert() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define ptr @_CReturnPtrWithThunk.Main() #0 !dbg !32 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %ReturnPtrWithThunk__carbon_thunk.call = call ptr @_Z18ReturnPtrWithThunki.carbon_thunk0(), !dbg !33 +// CHECK:STDOUT: %ReturnPtrWithThunk__carbon_thunk.call = call ptr @_Z18ReturnPtrWithThunki.carbon_thunk.(), !dbg !33 // CHECK:STDOUT: ret ptr %ReturnPtrWithThunk__carbon_thunk.call, !dbg !34 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef ptr @_Z18ReturnPtrWithThunki.carbon_thunk0() #2 { +// CHECK:STDOUT: define internal noundef ptr @_Z18ReturnPtrWithThunki.carbon_thunk.() #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %call = call noundef ptr @_Z18ReturnPtrWithThunki(i32 noundef 0) // CHECK:STDOUT: ret ptr %call @@ -264,13 +264,13 @@ fn Convert() { // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc35_24.2.temp), !dbg !44 // CHECK:STDOUT: store ptr %U.as_type.as.ImplicitAs.impl.Convert.call, ptr %.loc35_24.2.temp, align 8, !dbg !44 // CHECK:STDOUT: %.loc35_24.4 = load ptr, ptr %.loc35_24.2.temp, align 8, !dbg !44 -// CHECK:STDOUT: call void @_Z16TakePtrWithThunkP1Ci.carbon_thunk1(ptr %.loc35_24.4), !dbg !45 +// CHECK:STDOUT: call void @_Z16TakePtrWithThunkP1Ci.carbon_thunk._(ptr %.loc35_24.4), !dbg !45 // CHECK:STDOUT: call void @"_COp.f6ed00b54444c4a3:core.Destroy.Core"(ptr %.loc35_24.2.temp), !dbg !44 // CHECK:STDOUT: ret void, !dbg !46 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z16TakePtrWithThunkP1Ci.carbon_thunk1(ptr noundef %0) #2 { +// CHECK:STDOUT: define internal void @_Z16TakePtrWithThunkP1Ci.carbon_thunk._(ptr noundef %0) #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !47 @@ -282,12 +282,12 @@ fn Convert() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define ptr @_CReturnPtrWithThunk.Main() #0 !dbg !50 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %ReturnPtrWithThunk__carbon_thunk.call = call ptr @_Z18ReturnPtrWithThunki.carbon_thunk0(), !dbg !51 +// CHECK:STDOUT: %ReturnPtrWithThunk__carbon_thunk.call = call ptr @_Z18ReturnPtrWithThunki.carbon_thunk.(), !dbg !51 // CHECK:STDOUT: ret ptr %ReturnPtrWithThunk__carbon_thunk.call, !dbg !52 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef ptr @_Z18ReturnPtrWithThunki.carbon_thunk0() #2 { +// CHECK:STDOUT: define internal noundef ptr @_Z18ReturnPtrWithThunki.carbon_thunk.() #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %call = call noundef ptr @_Z18ReturnPtrWithThunki(i32 noundef 0) // CHECK:STDOUT: ret ptr %call diff --git a/toolchain/lower/testdata/interop/cpp/reference.carbon b/toolchain/lower/testdata/interop/cpp/reference.carbon index 393bb2f6e0ea..7cb67c4ca083 100644 --- a/toolchain/lower/testdata/interop/cpp/reference.carbon +++ b/toolchain/lower/testdata/interop/cpp/reference.carbon @@ -148,18 +148,18 @@ fn GetRefs() { // CHECK:STDOUT: call void @_Z8TakeCRefR1C(ptr %c.var), !dbg !19 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var.1), !dbg !15 // CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %_.var.1, ptr align 1 @C.val.loc19_20, i64 0, i1 false), !dbg !15 -// CHECK:STDOUT: call void @_Z9TakeCRRefO1C.carbon_thunk(ptr %_.var.1), !dbg !20 -// CHECK:STDOUT: call void @_Z13TakeConstCRefRK1C.carbon_thunk(ptr %c.var), !dbg !21 +// CHECK:STDOUT: call void @_Z9TakeCRRefO1C.carbon_thunk.v(ptr %_.var.1), !dbg !20 +// CHECK:STDOUT: call void @_Z13TakeConstCRefRK1C.carbon_thunk._(ptr %c.var), !dbg !21 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %n.var), !dbg !16 // CHECK:STDOUT: store i32 poison, ptr %n.var, align 4, !dbg !16 // CHECK:STDOUT: call void @_Z10TakeIntRefRi(ptr %n.var), !dbg !22 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var.2), !dbg !17 // CHECK:STDOUT: store i32 42, ptr %_.var.2, align 4, !dbg !17 -// CHECK:STDOUT: call void @_Z11TakeIntRRefOi.carbon_thunk(ptr %_.var.2), !dbg !23 +// CHECK:STDOUT: call void @_Z11TakeIntRRefOi.carbon_thunk.v(ptr %_.var.2), !dbg !23 // CHECK:STDOUT: %.loc25_23.1 = load i32, ptr %n.var, align 4, !dbg !18 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc25_23.2.temp), !dbg !18 // CHECK:STDOUT: store i32 %.loc25_23.1, ptr %.loc25_23.2.temp, align 4, !dbg !18 -// CHECK:STDOUT: call void @_Z15TakeConstIntRefRKi.carbon_thunk(ptr %.loc25_23.2.temp), !dbg !24 +// CHECK:STDOUT: call void @_Z15TakeConstIntRefRKi.carbon_thunk._(ptr %.loc25_23.2.temp), !dbg !24 // CHECK:STDOUT: call void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %.loc25_23.2.temp), !dbg !18 // CHECK:STDOUT: call void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %_.var.2), !dbg !17 // CHECK:STDOUT: call void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %n.var), !dbg !16 @@ -167,7 +167,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !26 @@ -178,14 +178,14 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Default.7b1e6a57c714cdb7.Core:C.Cpp"(ptr sret({}) %return) #2 !dbg !29 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk(ptr %return), !dbg !33 +// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk.(ptr %return), !dbg !33 // CHECK:STDOUT: ret void, !dbg !33 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: declare void @_Z8TakeCRefR1C(ptr noundef nonnull align 1 dereferenceable(1)) #3 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z9TakeCRRefO1C.carbon_thunk(ptr noundef %0) #4 { +// CHECK:STDOUT: define internal void @_Z9TakeCRRefO1C.carbon_thunk.v(ptr noundef %0) #4 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !26 @@ -195,7 +195,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z13TakeConstCRefRK1C.carbon_thunk(ptr noundef %0) #4 { +// CHECK:STDOUT: define internal void @_Z13TakeConstCRefRK1C.carbon_thunk._(ptr noundef %0) #4 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !26 @@ -207,7 +207,7 @@ fn GetRefs() { // CHECK:STDOUT: declare void @_Z10TakeIntRefRi(ptr noundef nonnull align 4 dereferenceable(4)) #3 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z11TakeIntRRefOi.carbon_thunk(ptr noundef %0) #4 { +// CHECK:STDOUT: define internal void @_Z11TakeIntRRefOi.carbon_thunk.v(ptr noundef %0) #4 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !34 @@ -217,7 +217,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z15TakeConstIntRefRKi.carbon_thunk(ptr noundef %0) #4 { +// CHECK:STDOUT: define internal void @_Z15TakeConstIntRefRKi.carbon_thunk._(ptr noundef %0) #4 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !34 @@ -335,20 +335,20 @@ fn GetRefs() { // CHECK:STDOUT: %.loc26_23.2.temp = alloca i32, align 4, !dbg !18 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c.var), !dbg !14 // CHECK:STDOUT: call void @"_COp.d288d62be0e5d791:DefaultOrUnformed.Core.93349b0fe912a29b"(ptr %c.var), !dbg !14 -// CHECK:STDOUT: call void @_Z8TakeCRefR1C10ForceThunk.carbon_thunk1(ptr %c.var), !dbg !19 +// CHECK:STDOUT: call void @_Z8TakeCRefR1C10ForceThunk.carbon_thunk.r(ptr %c.var), !dbg !19 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc20_18.2.temp), !dbg !15 -// CHECK:STDOUT: call void @_Z9TakeCRRefRK1C10ForceThunk.carbon_thunk1(ptr @C.val.loc20_20.3), !dbg !20 -// CHECK:STDOUT: call void @_Z13TakeConstCRefRK1C10ForceThunk.carbon_thunk1(ptr %c.var), !dbg !21 +// CHECK:STDOUT: call void @_Z9TakeCRRefRK1C10ForceThunk.carbon_thunk._(ptr @C.val.loc20_20.3), !dbg !20 +// CHECK:STDOUT: call void @_Z13TakeConstCRefRK1C10ForceThunk.carbon_thunk._(ptr %c.var), !dbg !21 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %n.var), !dbg !16 // CHECK:STDOUT: store i32 poison, ptr %n.var, align 4, !dbg !16 -// CHECK:STDOUT: call void @_Z10TakeIntRefRi10ForceThunk.carbon_thunk1(ptr %n.var), !dbg !22 +// CHECK:STDOUT: call void @_Z10TakeIntRefRi10ForceThunk.carbon_thunk.r(ptr %n.var), !dbg !22 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !17 // CHECK:STDOUT: store i32 42, ptr %_.var, align 4, !dbg !17 -// CHECK:STDOUT: call void @_Z11TakeIntRRefOi10ForceThunk.carbon_thunk1(ptr %_.var), !dbg !23 +// CHECK:STDOUT: call void @_Z11TakeIntRRefOi10ForceThunk.carbon_thunk.v(ptr %_.var), !dbg !23 // CHECK:STDOUT: %.loc26_23.1 = load i32, ptr %n.var, align 4, !dbg !18 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc26_23.2.temp), !dbg !18 // CHECK:STDOUT: store i32 %.loc26_23.1, ptr %.loc26_23.2.temp, align 4, !dbg !18 -// CHECK:STDOUT: call void @_Z15TakeConstIntRefRKi10ForceThunk.carbon_thunk1(ptr %.loc26_23.2.temp), !dbg !24 +// CHECK:STDOUT: call void @_Z15TakeConstIntRefRKi10ForceThunk.carbon_thunk._(ptr %.loc26_23.2.temp), !dbg !24 // CHECK:STDOUT: call void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %.loc26_23.2.temp), !dbg !18 // CHECK:STDOUT: call void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %_.var), !dbg !17 // CHECK:STDOUT: call void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %n.var), !dbg !16 @@ -356,7 +356,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable -// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1CC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !26 @@ -367,12 +367,12 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Default.7b1e6a57c714cdb7.Core:C.Cpp"(ptr sret({}) %return) #2 !dbg !29 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk(ptr %return), !dbg !33 +// CHECK:STDOUT: call void @_ZN1CC1Ev.carbon_thunk.(ptr %return), !dbg !33 // CHECK:STDOUT: ret void, !dbg !33 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z8TakeCRefR1C10ForceThunk.carbon_thunk1(ptr noundef nonnull align 1 dereferenceable(1) %0) #3 { +// CHECK:STDOUT: define internal void @_Z8TakeCRefR1C10ForceThunk.carbon_thunk.r(ptr noundef nonnull align 1 dereferenceable(1) %0) #3 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 @@ -383,7 +383,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z9TakeCRRefRK1C10ForceThunk.carbon_thunk1(ptr noundef %0) #3 { +// CHECK:STDOUT: define internal void @_Z9TakeCRRefRK1C10ForceThunk.carbon_thunk._(ptr noundef %0) #3 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 @@ -394,7 +394,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z13TakeConstCRefRK1C10ForceThunk.carbon_thunk1(ptr noundef %0) #3 { +// CHECK:STDOUT: define internal void @_Z13TakeConstCRefRK1C10ForceThunk.carbon_thunk._(ptr noundef %0) #3 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 @@ -405,7 +405,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z10TakeIntRefRi10ForceThunk.carbon_thunk1(ptr noundef nonnull align 4 dereferenceable(4) %0) #3 { +// CHECK:STDOUT: define internal void @_Z10TakeIntRefRi10ForceThunk.carbon_thunk.r(ptr noundef nonnull align 4 dereferenceable(4) %0) #3 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 @@ -416,7 +416,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z11TakeIntRRefOi10ForceThunk.carbon_thunk1(ptr noundef %0) #3 { +// CHECK:STDOUT: define internal void @_Z11TakeIntRRefOi10ForceThunk.carbon_thunk.v(ptr noundef %0) #3 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 @@ -427,7 +427,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z15TakeConstIntRefRKi10ForceThunk.carbon_thunk1(ptr noundef %0) #3 { +// CHECK:STDOUT: define internal void @_Z15TakeConstIntRefRKi10ForceThunk.carbon_thunk._(ptr noundef %0) #3 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 @@ -595,17 +595,17 @@ fn GetRefs() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CGetRefs.Main() #0 !dbg !11 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %ReturnCRef__carbon_thunk.call = call ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk0(), !dbg !14 -// CHECK:STDOUT: %ReturnCRRef__carbon_thunk.call = call ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk0(), !dbg !15 -// CHECK:STDOUT: %ReturnConstCRef__carbon_thunk.call = call ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk0(), !dbg !16 -// CHECK:STDOUT: %ReturnIntRef__carbon_thunk.call = call ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk0(), !dbg !17 -// CHECK:STDOUT: %ReturnIntRRef__carbon_thunk.call = call ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk0(), !dbg !18 -// CHECK:STDOUT: %ReturnConstIntRef__carbon_thunk.call = call ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk0(), !dbg !19 +// CHECK:STDOUT: %ReturnCRef__carbon_thunk.call = call ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk.(), !dbg !14 +// CHECK:STDOUT: %ReturnCRRef__carbon_thunk.call = call ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk.(), !dbg !15 +// CHECK:STDOUT: %ReturnConstCRef__carbon_thunk.call = call ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk.(), !dbg !16 +// CHECK:STDOUT: %ReturnIntRef__carbon_thunk.call = call ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk.(), !dbg !17 +// CHECK:STDOUT: %ReturnIntRRef__carbon_thunk.call = call ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk.(), !dbg !18 +// CHECK:STDOUT: %ReturnConstIntRef__carbon_thunk.call = call ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk.(), !dbg !19 // CHECK:STDOUT: ret void, !dbg !20 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z10ReturnCRef10ForceThunk() @@ -613,7 +613,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z11ReturnCRRef10ForceThunk() @@ -621,7 +621,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 1 dereferenceable(1) ptr @_Z15ReturnConstCRef10ForceThunk() @@ -629,7 +629,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z12ReturnIntRef10ForceThunk() @@ -637,7 +637,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z13ReturnIntRRef10ForceThunk() @@ -645,7 +645,7 @@ fn GetRefs() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk0() #1 { +// CHECK:STDOUT: define internal noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk.carbon_thunk.() #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %agg.tmp = alloca %class.ForceThunk, align 1 // CHECK:STDOUT: %call = call noundef nonnull align 4 dereferenceable(4) ptr @_Z17ReturnConstIntRef10ForceThunk() diff --git a/toolchain/lower/testdata/interop/cpp/return.carbon b/toolchain/lower/testdata/interop/cpp/return.carbon index 69d8f449ed34..5a0204c7c7c9 100644 --- a/toolchain/lower/testdata/interop/cpp/return.carbon +++ b/toolchain/lower/testdata/interop/cpp/return.carbon @@ -122,13 +122,13 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc6_40.1.temp = alloca i8, align 1, !dbg !15 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc6_40.1.temp), !dbg !15 -// CHECK:STDOUT: call void @_Z8ReturnU8v.carbon_thunk(ptr %.loc6_40.1.temp), !dbg !15 +// CHECK:STDOUT: call void @_Z8ReturnU8v.carbon_thunk.(ptr %.loc6_40.1.temp), !dbg !15 // CHECK:STDOUT: %0 = load i8, ptr %.loc6_40.1.temp, align 1, !dbg !16 // CHECK:STDOUT: ret i8 %0, !dbg !16 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z8ReturnU8v.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Z8ReturnU8v.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !17 @@ -143,13 +143,13 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc7_43.1.temp = alloca i16, align 2, !dbg !25 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc7_43.1.temp), !dbg !25 -// CHECK:STDOUT: call void @_Z9ReturnU16v.carbon_thunk(ptr %.loc7_43.1.temp), !dbg !25 +// CHECK:STDOUT: call void @_Z9ReturnU16v.carbon_thunk.(ptr %.loc7_43.1.temp), !dbg !25 // CHECK:STDOUT: %0 = load i16, ptr %.loc7_43.1.temp, align 2, !dbg !26 // CHECK:STDOUT: ret i16 %0, !dbg !26 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z9ReturnU16v.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Z9ReturnU16v.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !27 @@ -182,13 +182,13 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc11_40.1.temp = alloca i8, align 1, !dbg !47 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc11_40.1.temp), !dbg !47 -// CHECK:STDOUT: call void @_Z8ReturnI8v.carbon_thunk(ptr %.loc11_40.1.temp), !dbg !47 +// CHECK:STDOUT: call void @_Z8ReturnI8v.carbon_thunk.(ptr %.loc11_40.1.temp), !dbg !47 // CHECK:STDOUT: %0 = load i8, ptr %.loc11_40.1.temp, align 1, !dbg !48 // CHECK:STDOUT: ret i8 %0, !dbg !48 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z8ReturnI8v.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Z8ReturnI8v.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !17 @@ -203,13 +203,13 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc12_43.1.temp = alloca i16, align 2, !dbg !53 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc12_43.1.temp), !dbg !53 -// CHECK:STDOUT: call void @_Z9ReturnI16v.carbon_thunk(ptr %.loc12_43.1.temp), !dbg !53 +// CHECK:STDOUT: call void @_Z9ReturnI16v.carbon_thunk.(ptr %.loc12_43.1.temp), !dbg !53 // CHECK:STDOUT: %0 = load i16, ptr %.loc12_43.1.temp, align 2, !dbg !54 // CHECK:STDOUT: ret i16 %0, !dbg !54 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z9ReturnI16v.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Z9ReturnI16v.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !27 @@ -247,18 +247,18 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: %.loc24_32.1.temp = alloca i8, align 1, !dbg !72 // CHECK:STDOUT: %.loc25_35.1.temp = alloca i16, align 2, !dbg !73 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc19_32.1.temp), !dbg !70 -// CHECK:STDOUT: call void @_Z8ReturnU8v.carbon_thunk(ptr %.loc19_32.1.temp), !dbg !70 +// CHECK:STDOUT: call void @_Z8ReturnU8v.carbon_thunk.(ptr %.loc19_32.1.temp), !dbg !70 // CHECK:STDOUT: %.loc19_32.4 = load i8, ptr %.loc19_32.1.temp, align 1, !dbg !70 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc20_35.1.temp), !dbg !71 -// CHECK:STDOUT: call void @_Z9ReturnU16v.carbon_thunk(ptr %.loc20_35.1.temp), !dbg !71 +// CHECK:STDOUT: call void @_Z9ReturnU16v.carbon_thunk.(ptr %.loc20_35.1.temp), !dbg !71 // CHECK:STDOUT: %.loc20_35.4 = load i16, ptr %.loc20_35.1.temp, align 2, !dbg !71 // CHECK:STDOUT: %ReturnU32.call = call i32 @_Z9ReturnU32v(), !dbg !74 // CHECK:STDOUT: %ReturnU64.call = call i64 @_Z9ReturnU64v(), !dbg !75 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc24_32.1.temp), !dbg !72 -// CHECK:STDOUT: call void @_Z8ReturnI8v.carbon_thunk(ptr %.loc24_32.1.temp), !dbg !72 +// CHECK:STDOUT: call void @_Z8ReturnI8v.carbon_thunk.(ptr %.loc24_32.1.temp), !dbg !72 // CHECK:STDOUT: %.loc24_32.4 = load i8, ptr %.loc24_32.1.temp, align 1, !dbg !72 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc25_35.1.temp), !dbg !73 -// CHECK:STDOUT: call void @_Z9ReturnI16v.carbon_thunk(ptr %.loc25_35.1.temp), !dbg !73 +// CHECK:STDOUT: call void @_Z9ReturnI16v.carbon_thunk.(ptr %.loc25_35.1.temp), !dbg !73 // CHECK:STDOUT: %.loc25_35.4 = load i16, ptr %.loc25_35.1.temp, align 2, !dbg !73 // CHECK:STDOUT: %ReturnI32.call = call i32 @_Z9ReturnI32v(), !dbg !76 // CHECK:STDOUT: %ReturnI64.call = call i64 @_Z9ReturnI64v(), !dbg !77 @@ -306,9 +306,9 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: %my_i32.var = alloca i32, align 4, !dbg !111 // CHECK:STDOUT: %my_i64.var = alloca i64, align 8, !dbg !112 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %my_u8.var), !dbg !105 -// CHECK:STDOUT: call void @_Z8ReturnU8v.carbon_thunk(ptr %my_u8.var), !dbg !113 +// CHECK:STDOUT: call void @_Z8ReturnU8v.carbon_thunk.(ptr %my_u8.var), !dbg !113 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %my_u16.var), !dbg !106 -// CHECK:STDOUT: call void @_Z9ReturnU16v.carbon_thunk(ptr %my_u16.var), !dbg !114 +// CHECK:STDOUT: call void @_Z9ReturnU16v.carbon_thunk.(ptr %my_u16.var), !dbg !114 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %my_u32.var), !dbg !107 // CHECK:STDOUT: %ReturnU32.call = call i32 @_Z9ReturnU32v(), !dbg !115 // CHECK:STDOUT: store i32 %ReturnU32.call, ptr %my_u32.var, align 4, !dbg !107 @@ -316,9 +316,9 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: %ReturnU64.call = call i64 @_Z9ReturnU64v(), !dbg !116 // CHECK:STDOUT: store i64 %ReturnU64.call, ptr %my_u64.var, align 8, !dbg !108 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %my_i8.var), !dbg !109 -// CHECK:STDOUT: call void @_Z8ReturnI8v.carbon_thunk(ptr %my_i8.var), !dbg !117 +// CHECK:STDOUT: call void @_Z8ReturnI8v.carbon_thunk.(ptr %my_i8.var), !dbg !117 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %my_i16.var), !dbg !110 -// CHECK:STDOUT: call void @_Z9ReturnI16v.carbon_thunk(ptr %my_i16.var), !dbg !118 +// CHECK:STDOUT: call void @_Z9ReturnI16v.carbon_thunk.(ptr %my_i16.var), !dbg !118 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %my_i32.var), !dbg !111 // CHECK:STDOUT: %ReturnI32.call = call i32 @_Z9ReturnI32v(), !dbg !119 // CHECK:STDOUT: store i32 %ReturnI32.call, ptr %my_i32.var, align 4, !dbg !111 @@ -557,12 +557,12 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CGetX.Main(ptr sret([16 x i8]) %return) #0 !dbg !11 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z4Makev.carbon_thunk(ptr %return), !dbg !15 +// CHECK:STDOUT: call void @_Z4Makev.carbon_thunk.(ptr %return), !dbg !15 // CHECK:STDOUT: ret void, !dbg !16 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z4Makev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Z4Makev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !17 @@ -576,7 +576,7 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc9_27.1.temp = alloca [16 x i8], align 1, !dbg !23 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc9_27.1.temp), !dbg !23 -// CHECK:STDOUT: call void @_Z4Makev.carbon_thunk(ptr %.loc9_27.1.temp), !dbg !23 +// CHECK:STDOUT: call void @_Z4Makev.carbon_thunk.(ptr %.loc9_27.1.temp), !dbg !23 // CHECK:STDOUT: call void @_ZN1XD1Ev(ptr %.loc9_27.1.temp), !dbg !23 // CHECK:STDOUT: ret void, !dbg !24 // CHECK:STDOUT: } @@ -589,7 +589,7 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: entry: // CHECK:STDOUT: %_.var = alloca [16 x i8], align 1, !dbg !26 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !26 -// CHECK:STDOUT: call void @_Z4Makev.carbon_thunk(ptr %_.var), !dbg !27 +// CHECK:STDOUT: call void @_Z4Makev.carbon_thunk.(ptr %_.var), !dbg !27 // CHECK:STDOUT: call void @_ZN1XD1Ev(ptr %_.var), !dbg !26 // CHECK:STDOUT: ret void, !dbg !28 // CHECK:STDOUT: } @@ -652,12 +652,12 @@ fn Call(x: Cpp.D) -> Cpp.C { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CCall.Main(ptr sret({}) %return, ptr %x) #0 !dbg !11 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z1f1D.carbon_thunk(ptr %x, ptr %return), !dbg !17 +// CHECK:STDOUT: call void @_Z1f1D.carbon_thunk._(ptr %x, ptr %return), !dbg !17 // CHECK:STDOUT: ret void, !dbg !18 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z1f1D.carbon_thunk(ptr noundef %0, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_Z1f1D.carbon_thunk._(ptr noundef %0, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 diff --git a/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon b/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon index 859c43f9606c..828f2cab777d 100644 --- a/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon +++ b/toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon @@ -178,7 +178,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: store ptr @array.loc13_50.15, ptr %initializer_list.initializer_list.call.init_list.begin, align 8, !dbg !34 // CHECK:STDOUT: %initializer_list.initializer_list.call.init_list.end = getelementptr inbounds nuw [16 x i8], ptr %.loc18_36.2.temp, i32 0, i32 8, !dbg !34 // CHECK:STDOUT: store ptr getelementptr inbounds ([3 x i32], ptr @array.loc13_50.15, i32 1), ptr %initializer_list.initializer_list.call.init_list.end, align 8, !dbg !34 -// CHECK:STDOUT: call void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk(ptr %.loc18_36.2.temp, ptr %_.var), !dbg !33 +// CHECK:STDOUT: call void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk._(ptr %.loc18_36.2.temp, ptr %_.var), !dbg !33 // CHECK:STDOUT: call void @_CWithinLifetime.Main(), !dbg !35 // CHECK:STDOUT: call void @"_COp.bfd302cd235977c4:core.Destroy.Core"(ptr @array), !dbg !34 // CHECK:STDOUT: call void @_ZN11vector_likeD2Ev(ptr %_.var), !dbg !33 @@ -186,7 +186,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk(ptr noundef %list, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk._(ptr noundef %list, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %list.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 @@ -221,11 +221,11 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !46 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc23_69.17.temp), !dbg !47 // CHECK:STDOUT: %.loc23_69.18.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 0, !dbg !47 -// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.18.array.index), !dbg !47 +// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr %.loc23_69.18.array.index), !dbg !47 // CHECK:STDOUT: %.loc23_69.16.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 1, !dbg !47 -// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.16.array.index), !dbg !47 +// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr %.loc23_69.16.array.index), !dbg !47 // CHECK:STDOUT: %.loc23_69.15.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 2, !dbg !47 -// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.15.array.index), !dbg !47 +// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr %.loc23_69.15.array.index), !dbg !47 // CHECK:STDOUT: %initializer_list.initializer_list.call.init_list.begin = getelementptr inbounds nuw [16 x i8], ptr %_.var, i32 0, i32 0, !dbg !46 // CHECK:STDOUT: store ptr %.loc23_69.17.temp, ptr %initializer_list.initializer_list.call.init_list.begin, align 8, !dbg !46 // CHECK:STDOUT: %initializer_list.initializer_list.call.init_list.end = getelementptr inbounds nuw [16 x i8], ptr %_.var, i32 0, i32 8, !dbg !46 @@ -237,7 +237,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !50 @@ -291,7 +291,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder ptr @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple, { 2, 1, 0 } +// CHECK:STDOUT: uselistorder ptr @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple., { 2, 1, 0 } // CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 6, 5, 4, 3, 2, 1, 0 } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nounwind } @@ -427,7 +427,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: store ptr @array.loc13_50.15, ptr %initializer_list.initializer_list.call.init_list.begin, align 8, !dbg !34 // CHECK:STDOUT: %initializer_list.initializer_list.call.init_list.size = getelementptr inbounds nuw [16 x i8], ptr %.loc18_36.2.temp, i32 0, i32 8, !dbg !34 // CHECK:STDOUT: store i64 3, ptr %initializer_list.initializer_list.call.init_list.size, align 8, !dbg !34 -// CHECK:STDOUT: call void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk(ptr %.loc18_36.2.temp, ptr %_.var), !dbg !33 +// CHECK:STDOUT: call void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk._(ptr %.loc18_36.2.temp, ptr %_.var), !dbg !33 // CHECK:STDOUT: call void @_CWithinLifetime.Main(), !dbg !35 // CHECK:STDOUT: call void @"_COp.bfd302cd235977c4:core.Destroy.Core"(ptr @array), !dbg !34 // CHECK:STDOUT: call void @_ZN11vector_likeD2Ev(ptr %_.var), !dbg !33 @@ -435,7 +435,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk(ptr noundef %list, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN11vector_likeC1ESt16initializer_listIiE.carbon_thunk._(ptr noundef %list, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %list.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 @@ -470,11 +470,11 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !48 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc23_69.17.temp), !dbg !49 // CHECK:STDOUT: %.loc23_69.18.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 0, !dbg !49 -// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.18.array.index), !dbg !49 +// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr %.loc23_69.18.array.index), !dbg !49 // CHECK:STDOUT: %.loc23_69.16.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 1, !dbg !49 -// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.16.array.index), !dbg !49 +// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr %.loc23_69.16.array.index), !dbg !49 // CHECK:STDOUT: %.loc23_69.15.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 2, !dbg !49 -// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.15.array.index), !dbg !49 +// CHECK:STDOUT: call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr %.loc23_69.15.array.index), !dbg !49 // CHECK:STDOUT: %initializer_list.initializer_list.call.init_list.begin = getelementptr inbounds nuw [16 x i8], ptr %_.var, i32 0, i32 0, !dbg !48 // CHECK:STDOUT: store ptr %.loc23_69.17.temp, ptr %initializer_list.initializer_list.call.init_list.begin, align 8, !dbg !48 // CHECK:STDOUT: %initializer_list.initializer_list.call.init_list.size = getelementptr inbounds nuw [16 x i8], ptr %_.var, i32 0, i32 8, !dbg !48 @@ -485,7 +485,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !52 @@ -539,7 +539,7 @@ fn InitNontrivialDtor() { // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; uselistorder directives -// CHECK:STDOUT: uselistorder ptr @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple, { 2, 1, 0 } +// CHECK:STDOUT: uselistorder ptr @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple., { 2, 1, 0 } // CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 6, 5, 4, 3, 2, 1, 0 } // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { nounwind } diff --git a/toolchain/lower/testdata/interop/cpp/template.carbon b/toolchain/lower/testdata/interop/cpp/template.carbon index 0c0c2e569373..da13de41b9ad 100644 --- a/toolchain/lower/testdata/interop/cpp/template.carbon +++ b/toolchain/lower/testdata/interop/cpp/template.carbon @@ -126,12 +126,12 @@ fn Call3() { // CHECK:STDOUT: ; Function Attrs: nounwind // CHECK:STDOUT: define void @_CPassClass.Main(ptr sret({}) %return, ptr %a) #0 !dbg !24 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z8identityI5ClassET_S1_.carbon_thunk(ptr %a, ptr %return), !dbg !30 +// CHECK:STDOUT: call void @_Z8identityI5ClassET_S1_.carbon_thunk._(ptr %a, ptr %return), !dbg !30 // CHECK:STDOUT: ret void, !dbg !31 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z8identityI5ClassET_S1_.carbon_thunk(ptr noundef %x, ptr noundef %return) #2 { +// CHECK:STDOUT: define internal void @_Z8identityI5ClassET_S1_.carbon_thunk._(ptr noundef %x, ptr noundef %return) #2 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %x.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 @@ -271,12 +271,12 @@ fn Call3() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc12_12.2.temp = alloca {}, align 8, !dbg !14 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc12_12.2.temp), !dbg !14 -// CHECK:STDOUT: call void @_Z3fooIJEEv1XDpT_.carbon_thunk(ptr @X.val.loc12_14.3), !dbg !15 +// CHECK:STDOUT: call void @_Z3fooIJEEv1XDpT_.carbon_thunk._(ptr @X.val.loc12_14.3), !dbg !15 // CHECK:STDOUT: ret void, !dbg !16 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z3fooIJEEv1XDpT_.carbon_thunk(ptr noundef %0) #1 { +// CHECK:STDOUT: define internal void @_Z3fooIJEEv1XDpT_.carbon_thunk._(ptr noundef %0) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %agg.tmp = alloca %class.X, align 1 @@ -291,12 +291,12 @@ fn Call3() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc18_12.2.temp = alloca {}, align 8, !dbg !21 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc18_12.2.temp), !dbg !21 -// CHECK:STDOUT: call void @_Z3fooIJiEEv1XDpT_.carbon_thunk(ptr @X.val.loc12_14.3, i32 2), !dbg !22 +// CHECK:STDOUT: call void @_Z3fooIJiEEv1XDpT_.carbon_thunk.__(ptr @X.val.loc12_14.3, i32 2), !dbg !22 // CHECK:STDOUT: ret void, !dbg !23 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z3fooIJiEEv1XDpT_.carbon_thunk(ptr noundef %0, i32 noundef %1) #1 { +// CHECK:STDOUT: define internal void @_Z3fooIJiEEv1XDpT_.carbon_thunk.__(ptr noundef %0, i32 noundef %1) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 @@ -314,12 +314,12 @@ fn Call3() { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.loc24_12.2.temp = alloca {}, align 8, !dbg !25 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc24_12.2.temp), !dbg !25 -// CHECK:STDOUT: call void @_Z3fooIJiiEEv1XDpT_.carbon_thunk(ptr @X.val.loc12_14.3, i32 2, i32 3), !dbg !26 +// CHECK:STDOUT: call void @_Z3fooIJiiEEv1XDpT_.carbon_thunk.___(ptr @X.val.loc12_14.3, i32 2, i32 3), !dbg !26 // CHECK:STDOUT: ret void, !dbg !27 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_Z3fooIJiiEEv1XDpT_.carbon_thunk(ptr noundef %0, i32 noundef %1, i32 noundef %2) #1 { +// CHECK:STDOUT: define internal void @_Z3fooIJiiEEv1XDpT_.carbon_thunk.___(ptr noundef %0, i32 noundef %1, i32 noundef %2) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %.addr1 = alloca i32, align 4 diff --git a/toolchain/lower/testdata/interop/cpp/thunks.carbon b/toolchain/lower/testdata/interop/cpp/thunks.carbon index 6c5b25772758..51e7327f5d2d 100644 --- a/toolchain/lower/testdata/interop/cpp/thunks.carbon +++ b/toolchain/lower/testdata/interop/cpp/thunks.carbon @@ -43,12 +43,12 @@ fn Call(n: Cpp.NeedThunk) { // CHECK:STDOUT: %.loc9_34.1.temp = alloca [1 x i8], align 1, !dbg !18 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %n2.var), !dbg !17 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc9_34.1.temp), !dbg !18 -// CHECK:STDOUT: call void @_ZN9NeedThunkC1ERKS_.carbon_thunk(ptr %n, ptr %n2.var), !dbg !18 +// CHECK:STDOUT: call void @_ZN9NeedThunkC1ERKS_.carbon_thunk._(ptr %n, ptr %n2.var), !dbg !18 // CHECK:STDOUT: ret void, !dbg !19 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN9NeedThunkC1ERKS_.carbon_thunk(ptr noundef %0, ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN9NeedThunkC1ERKS_.carbon_thunk._(ptr noundef %0, ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %.addr = alloca ptr, align 8 // CHECK:STDOUT: %return.addr = alloca ptr, align 8 @@ -63,7 +63,7 @@ fn Call(n: Cpp.NeedThunk) { // CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind // CHECK:STDOUT: define void @"_COp:thunk:Copy.fdeb6dbda014bd1f.Core:NeedThunk.Cpp"(ptr sret([1 x i8]) %return, ptr %self) #2 !dbg !23 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_ZN9NeedThunkC1ERKS_.carbon_thunk(ptr %self, ptr %return), !dbg !29 +// CHECK:STDOUT: call void @_ZN9NeedThunkC1ERKS_.carbon_thunk._(ptr %self, ptr %return), !dbg !29 // CHECK:STDOUT: ret void, !dbg !29 // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/lower/testdata/interop/cpp/virtual_base.carbon b/toolchain/lower/testdata/interop/cpp/virtual_base.carbon index 71eb3bed3f48..8543a080f5cc 100644 --- a/toolchain/lower/testdata/interop/cpp/virtual_base.carbon +++ b/toolchain/lower/testdata/interop/cpp/virtual_base.carbon @@ -113,12 +113,12 @@ fn AccessD(d: Cpp.D) -> i32 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %_.var = alloca [40 x i8], align 1, !dbg !14 // CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !14 -// CHECK:STDOUT: call void @_ZN1DC1Ev.carbon_thunk(ptr %_.var), !dbg !15 +// CHECK:STDOUT: call void @_ZN1DC1Ev.carbon_thunk.(ptr %_.var), !dbg !15 // CHECK:STDOUT: ret void, !dbg !16 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable -// CHECK:STDOUT: define internal void @_ZN1DC1Ev.carbon_thunk(ptr noundef %return) #1 { +// CHECK:STDOUT: define internal void @_ZN1DC1Ev.carbon_thunk.(ptr noundef %return) #1 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %return.addr = alloca ptr, align 8 // CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !17 diff --git a/toolchain/sem_ir/clang_decl.cpp b/toolchain/sem_ir/clang_decl.cpp index dcdf591a2643..8752e0740d57 100644 --- a/toolchain/sem_ir/clang_decl.cpp +++ b/toolchain/sem_ir/clang_decl.cpp @@ -11,6 +11,50 @@ namespace Carbon::SemIR { +auto ClangDeclSignature::Print(llvm::raw_ostream& out) const -> void { + out << "{kind: "; + switch (kind) { + case Normal: + out << "normal"; + break; + case TuplePattern: + out << "tuple"; + break; + } + out << ", num_params: " << num_params; + + auto print_mode = [&](PassingMode mode) { + switch (mode) { + case PassingMode::ByValue: + out << "value"; + break; + case PassingMode::ByVar: + out << "var"; + break; + case PassingMode::ByRef: + out << "ref"; + break; + } + }; + + if (!passing_modes.empty() && llvm::any_of(passing_modes, [](auto mode) { + return mode != PassingMode::ByVar; + })) { + out << ", modes: ["; + llvm::ListSeparator sep; + for (auto mode : passing_modes) { + out << sep; + print_mode(mode); + } + out << "]"; + } + if (self_passing_mode != PassingMode::ByRef) { + out << ", self_mode: "; + print_mode(self_passing_mode); + } + out << "}"; +} + auto ClangDeclKey::Print(llvm::raw_ostream& out) const -> void { RawStringOstream decl_stream; auto policy = decl->getASTContext().getPrintingPolicy(); @@ -21,20 +65,11 @@ auto ClangDeclKey::Print(llvm::raw_ostream& out) const -> void { decl->print(decl_stream, policy); } - if (signature.num_params != -1) { - out << "{decl: \"" << FormatEscaped(decl_stream.TakeStr()) << "\", kind: "; - switch (signature.kind) { - case ClangDeclKey::Signature::Normal: - out << "normal"; - break; - case ClangDeclKey::Signature::TuplePattern: - out << "tuple"; - break; - } - out << ", num_params: " << signature.num_params << "}"; - } else { - out << "\"" << FormatEscaped(decl_stream.TakeStr()) << "\""; + out << "{decl: \"" << FormatEscaped(decl_stream.TakeStr()) << "\""; + if (signature_id != ClangDeclSignatureId::None) { + out << ", clang_decl_signature_id: " << signature_id; } + out << "}"; } auto ClangDecl::Print(llvm::raw_ostream& out) const -> void { diff --git a/toolchain/sem_ir/clang_decl.h b/toolchain/sem_ir/clang_decl.h index 4a3a99ec9ff1..d9920ba47a74 100644 --- a/toolchain/sem_ir/clang_decl.h +++ b/toolchain/sem_ir/clang_decl.h @@ -15,6 +15,95 @@ namespace Carbon::SemIR { +// Information about how to form the Carbon function signature from the Clang +// function declaration. +struct ClangDeclSignature : public Printable { + // A passing mode for a parameter in a C++ function signature. + enum class PassingMode : int8_t { + // This parameter is passed by Carbon value. This is used for a C++ + // non-reference parameter that would be copied at the call site, and for a + // C++ const reference parameter (either lvalue or rvalue reference). + ByValue, + // This parameter is passed as a Carbon var parameter. This is used for a + // C++ non-reference parameter that would be moved or constructed in-place + // at the call site, or for a C++ non-const rvalue reference parameter. + ByVar, + // This parameter is passed as a Carbon ref parameter. This is used for a + // C++ non-const lvalue reference parameter. + ByRef, + }; + + enum Kind : int8_t { + // A normal function signature: each C++ parameter maps into a Carbon + // parameter. + Normal, + // A function signature taking a tuple pattern that contains the C++ + // parameters. This is used when importing a constructor that is used for + // list initialization from a Carbon tuple. + TuplePattern, + }; + + // The kind of function signature being imported. + Kind kind = Normal; + + // The number of parameters to import. This can be less than the number of + // parameters in the Clang declaration if the Clang declaration has default + // arguments. Excludes the (implicit or explicit) object parameter, if there + // is one. + // TODO: Remove in favor of `passing_modes`. + int32_t num_params = -1; + + // The passing mode for the (implicit or explicit) object parameter, if there + // is one. Otherwise PassingMode::ByRef. + PassingMode self_passing_mode = PassingMode::ByRef; + + // The passing mode for each parameter. Excludes the (implicit or explicit) + // object parameter, if there is one. This must be the same size as + // `num_params`. + // TODO: Generalize this to be parameter info, not just passing mode. + llvm::SmallVector passing_modes; + + // Convenience function to make a fixed signature. + static auto Make( + std::initializer_list modes, + Kind kind = Normal, PassingMode self_passing_mode = PassingMode::ByRef) + -> ClangDeclSignature { + ClangDeclSignature signature; + signature.kind = kind; + signature.num_params = static_cast(modes.size()); + signature.self_passing_mode = self_passing_mode; + signature.passing_modes.assign(modes.begin(), modes.end()); + return signature; + } + + // Returns the passing mode for the i-th parameter. + auto GetPassingMode(int32_t i) const -> PassingMode { + return i < static_cast(passing_modes.size()) ? passing_modes[i] + : PassingMode::ByVar; + } + + auto Print(llvm::raw_ostream& out) const -> void; + + auto operator==(const ClangDeclSignature& rhs) const -> bool { + return kind == rhs.kind && num_params == rhs.num_params && + passing_modes == rhs.passing_modes && + self_passing_mode == rhs.self_passing_mode; + } + + // Hashing for ClangDeclSignature. + friend auto CarbonHashValue(const ClangDeclSignature& value, uint64_t seed) + -> HashCode { + HashCode code = + HashValue(std::tuple{value.kind, value.num_params, + static_cast(value.self_passing_mode)}, + seed); + for (auto mode : value.passing_modes) { + code = HashValue(static_cast(mode), static_cast(code)); + } + return code; + } +}; + // A key describing a Clang declaration that can be looked up in the value // store. This is a `clang::Decl*` pointing to a canonical declaration, plus any // other information that affects the mapping into Carbon. Currently this @@ -24,29 +113,6 @@ namespace Carbon::SemIR { // A canonical declaration pointer is used so that we can perform direct address // comparisons and hash this structure based on its contents. struct ClangDeclKey : public Printable { - // Information about how to form the Carbon function signature from the Clang - // function declaration. - struct Signature { - enum Kind : int8_t { - // A normal function signature: each C++ parameter maps into a Carbon - // parameter. - Normal, - // A function signature taking a tuple pattern that contains the C++ - // parameters. This is used when importing a constructor that is used for - // list initialization from a Carbon tuple. - TuplePattern, - }; - // The kind of function signature being imported. - Kind kind = Normal; - // The number of parameters to import. This can be less than the number of - // parameters in the Clang declaration if the Clang declaration has default - // arguments. Excludes the implicit object parameter, if there is one. - int32_t num_params = -1; - - friend auto operator==(const Signature& lhs, const Signature& rhs) - -> bool = default; - }; - // For declaration classes that are unrelated to FunctionDecl, no parameter // count is expected. template @@ -54,35 +120,33 @@ struct ClangDeclKey : public Printable { !std::derived_from && !std::derived_from) explicit ClangDeclKey(DeclT* decl) - : ClangDeclKey(decl, Signature{}, UncheckedTag()) {} + : ClangDeclKey(decl, ClangDeclSignatureId::None, UncheckedTag()) {} // For declaration classes that are derived from FunctionDecl, a parameter // count is required. - static auto ForFunctionDecl(clang::FunctionDecl* decl, Signature signature) + static auto ForFunctionDecl(clang::FunctionDecl* decl, + ClangDeclSignatureId signature_id) -> ClangDeclKey { - return ClangDeclKey(decl, signature, UncheckedTag()); + return ClangDeclKey(decl, signature_id, UncheckedTag()); } // Factory function for clang declaration that is dynamically known to not be // a function declaration. static auto ForNonFunctionDecl(clang::Decl* decl) -> ClangDeclKey { CARBON_CHECK(!isa(decl)); - return ClangDeclKey(decl, Signature{}, UncheckedTag()); + return ClangDeclKey(decl, ClangDeclSignatureId::None, UncheckedTag()); } auto Print(llvm::raw_ostream& out) const -> void; auto operator==(const ClangDeclKey& rhs) const -> bool { - return decl == rhs.decl && signature == rhs.signature; + return decl == rhs.decl && signature_id == rhs.signature_id; } // Hashing for ClangDecl. See common/hashing.h. friend auto CarbonHashValue(const ClangDeclKey& value, uint64_t seed) -> HashCode { - // Manual hashing support is required because `Signature` has padding. - return HashValue(std::tuple{value.decl, value.signature.num_params, - value.signature.kind}, - seed); + return HashValue(std::tuple{value.decl, value.signature_id}, seed); } // The Clang declaration pointing to the Clang AST. @@ -90,16 +154,17 @@ struct ClangDeclKey : public Printable { // `clang::LazyDeclPtr`. clang::Decl* decl; - // The parameters to import for a function declaration. Otherwise a - // default-constructed value. - Signature signature; + // The parameters to import for a function declaration. Otherwise + // ClangDeclSignatureId::None. + ClangDeclSignatureId signature_id; private: struct UncheckedTag { explicit UncheckedTag() = default; }; - ClangDeclKey(clang::Decl* decl, Signature signature, UncheckedTag /*_*/) - : decl(decl->getCanonicalDecl()), signature(signature) {} + ClangDeclKey(clang::Decl* decl, ClangDeclSignatureId signature_id, + UncheckedTag /*_*/) + : decl(decl->getCanonicalDecl()), signature_id(signature_id) {} }; // A Clang declaration mapped to a Carbon instruction. @@ -151,6 +216,11 @@ class ClangDeclStore { Map inst_id_to_clang_decl_id_; }; +// A ClangDeclSignature mapped to an ID. +using ClangDeclSignatureStore = + CanonicalValueStore, ClangDeclSignature>; + } // namespace Carbon::SemIR #endif // CARBON_TOOLCHAIN_SEM_IR_CLANG_DECL_H_ diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index aa6b89ab0548..47460acd1d98 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -56,6 +56,7 @@ File::File(const Parse::Tree* parse_tree, CheckIRId check_ir_id, // `ImportIRId::{ApiForImpl,Cpp}`. import_irs_(check_ir_id, 2), clang_decls_(check_ir_id), + clang_decl_signatures_(check_ir_id), // The `+1` prevents adding a tag to the global `NameSpace::PackageInstId` // instruction. It's not a "singleton" instruction, but it's a unique // instruction id that comes right after the singletons. @@ -143,42 +144,43 @@ auto File::OutputYaml(bool include_singletons) const -> Yaml::OutputMapping { return Yaml::OutputMapping([this, include_singletons]( Yaml::OutputMapping::Map map) { map.Add("filename", filename_); - map.Add("sem_ir", Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { - map.Add("names", names().OutputYaml()); - map.Add("import_irs", import_irs_.OutputYaml()); - map.Add("import_ir_insts", import_ir_insts_.OutputYaml()); - map.Add("clang_decls", clang_decls_.OutputYaml()); - map.Add("name_scopes", name_scopes_.OutputYaml()); - map.Add("entity_names", entity_names_.OutputYaml()); - map.Add("cpp_global_vars", cpp_global_vars_.OutputYaml()); - map.Add("functions", functions_.OutputYaml()); - map.Add("classes", classes_.OutputYaml()); - map.Add("interfaces", interfaces_.OutputYaml()); - map.Add("associated_constants", - associated_constants_.OutputYaml()); - map.Add("impls", impls_.OutputYaml()); - map.Add("generics", generics_.OutputYaml()); - map.Add("specifics", specifics_.OutputYaml()); - map.Add("specific_interfaces", specific_interfaces_.OutputYaml()); - map.Add("struct_type_fields", struct_type_fields_.OutputYaml()); - map.Add("types", types_.OutputYaml()); - map.Add("facet_types", facet_types_.OutputYaml()); - map.Add("insts", - Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { - for (auto [id, inst] : insts_.enumerate()) { - inst.CacheBundleDebugKinds(bundles_); - if (!include_singletons && IsSingletonInstId(id)) { - continue; - } - map.Add(PrintToString(id), Yaml::OutputScalar(inst)); - } - })); - map.Add("bundles", bundles_.OutputYaml()); - map.Add("constant_values", - constant_values_.OutputYaml(include_singletons)); - map.Add("inst_blocks", inst_blocks_.OutputYaml()); - map.Add("value_stores", value_stores_->OutputYaml()); - })); + map.Add( + "sem_ir", Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + map.Add("names", names().OutputYaml()); + map.Add("import_irs", import_irs_.OutputYaml()); + map.Add("import_ir_insts", import_ir_insts_.OutputYaml()); + map.Add("clang_decls", clang_decls_.OutputYaml()); + map.Add("clang_decl_signatures", clang_decl_signatures_.OutputYaml()); + map.Add("name_scopes", name_scopes_.OutputYaml()); + map.Add("entity_names", entity_names_.OutputYaml()); + map.Add("cpp_global_vars", cpp_global_vars_.OutputYaml()); + map.Add("functions", functions_.OutputYaml()); + map.Add("classes", classes_.OutputYaml()); + map.Add("interfaces", interfaces_.OutputYaml()); + map.Add("associated_constants", associated_constants_.OutputYaml()); + map.Add("impls", impls_.OutputYaml()); + map.Add("generics", generics_.OutputYaml()); + map.Add("specifics", specifics_.OutputYaml()); + map.Add("specific_interfaces", specific_interfaces_.OutputYaml()); + map.Add("struct_type_fields", struct_type_fields_.OutputYaml()); + map.Add("types", types_.OutputYaml()); + map.Add("facet_types", facet_types_.OutputYaml()); + map.Add("insts", + Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) { + for (auto [id, inst] : insts_.enumerate()) { + inst.CacheBundleDebugKinds(bundles_); + if (!include_singletons && IsSingletonInstId(id)) { + continue; + } + map.Add(PrintToString(id), Yaml::OutputScalar(inst)); + } + })); + map.Add("bundles", bundles_.OutputYaml()); + map.Add("constant_values", + constant_values_.OutputYaml(include_singletons)); + map.Add("inst_blocks", inst_blocks_.OutputYaml()); + map.Add("value_stores", value_stores_->OutputYaml()); + })); }); } @@ -200,6 +202,8 @@ auto File::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const mem_usage.Collect(MemUsage::ConcatLabel(label, "import_ir_insts_"), import_ir_insts_); mem_usage.Collect(MemUsage::ConcatLabel(label, "clang_decls_"), clang_decls_); + mem_usage.Collect(MemUsage::ConcatLabel(label, "clang_decl_signatures_"), + clang_decl_signatures_); mem_usage.Collect(MemUsage::ConcatLabel(label, "struct_type_fields_"), struct_type_fields_); mem_usage.Collect(MemUsage::ConcatLabel(label, "insts_"), insts_); diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 81541b3b0960..d14ac487d83b 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -238,6 +238,12 @@ class File : public Printable { auto set_cpp_file(std::unique_ptr cpp_file) -> void; auto clang_decls() -> ClangDeclStore& { return clang_decls_; } auto clang_decls() const -> const ClangDeclStore& { return clang_decls_; } + auto clang_decl_signatures() -> ClangDeclSignatureStore& { + return clang_decl_signatures_; + } + auto clang_decl_signatures() const -> const ClangDeclSignatureStore& { + return clang_decl_signatures_; + } auto names() const -> NameStoreWrapper { return NameStoreWrapper(&identifiers()); } @@ -393,6 +399,9 @@ class File : public Printable { // not add multiple entries with the same `decl` and different `inst_id`. ClangDeclStore clang_decls_ = ClangDeclStore(check_ir_id()); + // Storage for function signatures used in C++ interop. + ClangDeclSignatureStore clang_decl_signatures_; + // All instructions. The first entries will always be the singleton // instructions. InstStore insts_; diff --git a/toolchain/sem_ir/ids.h b/toolchain/sem_ir/ids.h index 81b5307e3d06..3b8bc7c8e55a 100644 --- a/toolchain/sem_ir/ids.h +++ b/toolchain/sem_ir/ids.h @@ -493,6 +493,13 @@ struct ClangDeclId : public IdBase { using IdBase::IdBase; }; +// The ID of a `ClangDeclSignature`. +struct ClangDeclSignatureId : public IdBase { + static constexpr llvm::StringLiteral Label = "clang_decl_signature_id"; + + using IdBase::IdBase; +}; + // A boolean value. struct BoolValue : public IdBase { // Not used by `Print`, but for `IdKind`. diff --git a/toolchain/sem_ir/yaml_test.cpp b/toolchain/sem_ir/yaml_test.cpp index a2842e3ea009..f777848edd83 100644 --- a/toolchain/sem_ir/yaml_test.cpp +++ b/toolchain/sem_ir/yaml_test.cpp @@ -61,6 +61,7 @@ TEST(SemIRTest, Yaml) { Pair("import_irs", Yaml::Mapping(SizeIs(2))), Pair("import_ir_insts", Yaml::Mapping(SizeIs(0))), Pair("clang_decls", Yaml::Mapping(SizeIs(0))), + Pair("clang_decl_signatures", Yaml::Mapping(SizeIs(0))), Pair("name_scopes", Yaml::Mapping(SizeIs(1))), Pair("entity_names", Yaml::Mapping(SizeIs(1))), Pair("cpp_global_vars", Yaml::Mapping(SizeIs(0))),