From 3c9d267388a783441d9faaff83a662788c7219dd Mon Sep 17 00:00:00 2001 From: Boaz Brickner Date: Wed, 6 Aug 2025 12:27:33 +0200 Subject: [PATCH] Generate and use a C++ thunk to call non simple ABI C++ functions (#5850) When the C++ function has a parameter that is not a pointer and not a signed integer of 32 or 64 bits, generate a thunk. Terminology: * Callee function: The C++ function we actually want to call. * Thunk function: The C++ function we generated that calls the callee function. * A simple ABI type, for now, is one of: * A pointer * signed integer with 32 bits * signed integer with 64 bits The thunk function is marked `always_inline` and uses the `asm` attribute to set its mangled to the callee function mangled name suffixed with `".carbon_thunk"`. When importing a C++ function, we decide whether calling it requires a thunk and if so we generate it and import it as well, which is currently a recursive call. When calling the thunk function, we initialize a temporary storage for each non simple ABI parameter type and take its address. This can be optimized when the variable is already in storage. Not supported yet: * Functions with non void return values. * Member methods. Moved unsigned int param test from `arithmetic_types_direct.carbon` to `arithmetic_types_bridged.carbon`, since only signed integers aren't bridged using a thunk. C++ Interop Demo: ```c++ // hello_world.h struct S { S() {} S(const S&) { x = 1; } int x; }; void hello_world(S s); ``` ```c++ // hello_world.cpp #include "hello_world.h" #include void hello_world2(S s) { printf("hello_world2: %d\n", s.x); } void hello_world(S s) { printf("hello_world: %d\n", s.x); hello_world2(s); } ``` ```carbon // main.carbon library "Main"; import Cpp library "hello_world.h"; fn Run() -> i32 { var s : Cpp.S; Cpp.hello_world(s); return 0; } ``` ```shell $ clang -c hello_world.cpp $ bazel-bin/toolchain/carbon compile main.carbon $ bazel-bin/toolchain/carbon link hello_world.o main.o --output=demo $ ./demo hello_world: 1 hello_world2: 1 ``` Before this change (no thunk - copy constructor not called when calling `hello_world()`): ```shell $ ./demo hello_world: -1219172304 hello_world2: 1 ``` --- toolchain/check/BUILD | 2 + toolchain/check/call.cpp | 49 ++- toolchain/check/cpp_thunk.cpp | 371 ++++++++++++++++ toolchain/check/cpp_thunk.h | 38 ++ toolchain/check/import_cpp.cpp | 155 ++++--- toolchain/check/import_ref.cpp | 5 + .../function/arithmetic_types_bridged.carbon | 391 ++++++++++++++++- .../function/arithmetic_types_direct.carbon | 176 ++++---- .../interop/cpp/function/class.carbon | 387 +++++++++++++--- .../interop/cpp/function/full_semir.carbon | 44 +- .../interop/cpp/function/struct.carbon | 415 +++++++++++++++--- .../interop/cpp/function/union.carbon | 342 +++++++++++---- .../check/testdata/interop/cpp/import.carbon | 120 +++++ toolchain/lower/mangler.cpp | 2 + .../lower/testdata/interop/cpp/thunk.carbon | 85 ++++ toolchain/sem_ir/function.h | 31 +- 16 files changed, 2191 insertions(+), 422 deletions(-) create mode 100644 toolchain/check/cpp_thunk.cpp create mode 100644 toolchain/check/cpp_thunk.h create mode 100644 toolchain/check/testdata/interop/cpp/import.carbon create mode 100644 toolchain/lower/testdata/interop/cpp/thunk.carbon diff --git a/toolchain/check/BUILD b/toolchain/check/BUILD index 6232b9865792..d6e7d15723f9 100644 --- a/toolchain/check/BUILD +++ b/toolchain/check/BUILD @@ -21,6 +21,7 @@ cc_library( "context.cpp", "control_flow.cpp", "convert.cpp", + "cpp_thunk.cpp", "decl_name_stack.cpp", "deduce.cpp", "deferred_definition_worklist.cpp", @@ -65,6 +66,7 @@ cc_library( "context.h", "control_flow.h", "convert.h", + "cpp_thunk.h", "decl_introducer_state.h", "decl_name_stack.h", "deduce.h", diff --git a/toolchain/check/call.cpp b/toolchain/check/call.cpp index b41549fe5701..ba0be1e421c4 100644 --- a/toolchain/check/call.cpp +++ b/toolchain/check/call.cpp @@ -10,6 +10,7 @@ #include "toolchain/check/context.h" #include "toolchain/check/control_flow.h" #include "toolchain/check/convert.h" +#include "toolchain/check/cpp_thunk.h" #include "toolchain/check/deduce.h" #include "toolchain/check/facet_type.h" #include "toolchain/check/function.h" @@ -255,27 +256,39 @@ static auto PerformCallToFunction(Context& context, SemIR::LocId loc_id, ConvertCallArgs(context, loc_id, callee_function.self_id, arg_ids, return_slot_arg_id, callee, *callee_specific_id); - // If we're about to form a direct call to a thunk, inline it. - if (callee.special_function_kind == - SemIR::Function::SpecialFunctionKind::Thunk) { - LoadImportRef(context, callee.thunk_decl_id()); + switch (callee.special_function_kind) { + case SemIR::Function::SpecialFunctionKind::Thunk: { + // If we're about to form a direct call to a thunk, inline it. + LoadImportRef(context, callee.thunk_decl_id()); - // Name the thunk target within the enclosing scope of the thunk. - auto thunk_ref_id = - BuildNameRef(context, loc_id, callee.name_id, callee.thunk_decl_id(), - callee_function.enclosing_specific_id); + // Name the thunk target within the enclosing scope of the thunk. + auto thunk_ref_id = + BuildNameRef(context, loc_id, callee.name_id, callee.thunk_decl_id(), + callee_function.enclosing_specific_id); - // This recurses back into `PerformCall`. However, we never form a thunk to - // a thunk, so we only recurse once. - return PerformThunkCall(context, loc_id, callee_function.function_id, - context.inst_blocks().Get(converted_args_id), - thunk_ref_id); + // This recurses back into `PerformCall`. However, we never form a thunk + // to a thunk, so we only recurse once. + return PerformThunkCall(context, loc_id, callee_function.function_id, + context.inst_blocks().Get(converted_args_id), + thunk_ref_id); + } + + case SemIR::Function::SpecialFunctionKind::HasCppThunk: { + // This recurses back into `PerformCall`. However, we never form a C++ + // thunk to a C++ thunk, so we only recurse once. + return PerformCppThunkCall(context, loc_id, callee_function.function_id, + context.inst_blocks().Get(converted_args_id), + callee.cpp_thunk_decl_id()); + } + + case SemIR::Function::SpecialFunctionKind::None: + case SemIR::Function::SpecialFunctionKind::Builtin: { + return GetOrAddInst(context, loc_id, + {.type_id = return_info.type_id, + .callee_id = callee_id, + .args_id = converted_args_id}); + } } - - return GetOrAddInst(context, loc_id, - {.type_id = return_info.type_id, - .callee_id = callee_id, - .args_id = converted_args_id}); } auto PerformCall(Context& context, SemIR::LocId loc_id, SemIR::InstId callee_id, diff --git a/toolchain/check/cpp_thunk.cpp b/toolchain/check/cpp_thunk.cpp new file mode 100644 index 000000000000..508a08e9ec7e --- /dev/null +++ b/toolchain/check/cpp_thunk.cpp @@ -0,0 +1,371 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/check/cpp_thunk.h" + +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/Mangle.h" +#include "clang/Sema/Sema.h" +#include "toolchain/check/call.h" +#include "toolchain/check/context.h" +#include "toolchain/check/control_flow.h" +#include "toolchain/check/literal.h" +#include "toolchain/check/type.h" +#include "toolchain/check/type_completion.h" +#include "toolchain/sem_ir/ids.h" +#include "toolchain/sem_ir/typed_insts.h" + +namespace Carbon::Check { + +// Returns the C++ thunk mangled name given the callee function. +static auto GenerateThunkMangledName( + clang::ASTContext& ast_context, + const clang::FunctionDecl& callee_function_decl) -> std::string { + RawStringOstream mangled_name_stream; + { + // TODO: Create `MangleContext` once. + std::unique_ptr mangle_context( + ast_context.createMangleContext()); + mangle_context->mangleName(clang::GlobalDecl(&callee_function_decl), + mangled_name_stream); + } + + mangled_name_stream << ".carbon_thunk"; + + return mangled_name_stream.TakeStr(); +} + +// Returns true if a C++ thunk is required for the given type. A C++ thunk is +// required for any type except for void, pointer types and signed 32-bit and +// 64-bit integers. +static auto IsThunkRequiredForType(Context& context, SemIR::TypeId type_id) + -> bool { + if (!type_id.has_value() || type_id == SemIR::ErrorInst::TypeId) { + return false; + } + + type_id = context.types().GetUnqualifiedType(type_id); + + switch (context.types().GetAsInst(type_id).kind()) { + case SemIR::PointerType::Kind: { + return false; + } + + case SemIR::ClassType::Kind: { + if (!context.types().IsComplete(type_id)) { + // Signed integers of 32 or 64 bits should be completed when imported. + return true; + } + + if (!context.types().IsSignedInt(type_id)) { + return true; + } + + llvm::APInt bit_width = + context.ints().Get(context.types().GetIntTypeInfo(type_id).bit_width); + return bit_width != 32 && bit_width != 64; + } + + default: + return true; + } +} + +auto IsCppThunkRequired(Context& context, const SemIR::Function& function) + -> bool { + if (!function.clang_decl_id.has_value()) { + return false; + } + + if (function.self_param_id.has_value()) { + // TODO: Support member methods. + return false; + } + + SemIR::TypeId return_type_id = + function.GetDeclaredReturnType(context.sem_ir()); + if (return_type_id.has_value()) { + // TODO: Support non-void return values. + return false; + } + + bool thunk_required_for_param = false; + for (auto param_id : + context.inst_blocks().GetOrEmpty(function.call_params_id)) { + if (param_id == SemIR::ErrorInst::InstId) { + return false; + } + if (!thunk_required_for_param && + IsThunkRequiredForType( + context, + context.insts().GetAs(param_id).type_id)) { + thunk_required_for_param = true; + } + } + + return thunk_required_for_param; +} + +// Returns whether the type is a pointer or a signed int of 32 or 64 bits. +static auto IsSimpleAbiType(clang::ASTContext& ast_context, + clang::QualType type) -> bool { + if (type->isPointerType()) { + return true; + } + + if (const auto* builtin_type = type->getAs()) { + if (builtin_type->isSignedInteger()) { + uint64_t type_size = ast_context.getIntWidth(type); + return type_size == 32 || type_size == 64; + } + } + + return false; +} + +// Creates the thunk parameter types given the callee function. Also returns for +// each type whether it is different from the matching callee function parameter +// type. +static auto BuildThunkParameterTypes( + clang::ASTContext& ast_context, + const clang::FunctionDecl& callee_function_decl) + -> std::tuple, llvm::SmallVector> { + std::tuple, llvm::SmallVector> + result; + auto& [thunk_param_types, param_type_changed] = result; + + unsigned num_params = callee_function_decl.getNumParams(); + thunk_param_types.reserve(num_params); + param_type_changed.reserve(num_params); + + for (const clang::ParmVarDecl* callee_param : + callee_function_decl.parameters()) { + clang::QualType param_type = callee_param->getType(); + bool is_simple_abi_type = IsSimpleAbiType(ast_context, param_type); + if (!is_simple_abi_type) { + clang::QualType pointer_type = ast_context.getPointerType(param_type); + param_type = ast_context.getAttributedType( + clang::NullabilityKind::NonNull, pointer_type, pointer_type); + } + param_type_changed.push_back(!is_simple_abi_type); + thunk_param_types.push_back(param_type); + } + + return result; +} + +// Returns the thunk parameters using the callee function parameter identifiers. +static auto BuildThunkParameters( + clang::ASTContext& ast_context, + const clang::FunctionDecl& callee_function_decl, + clang::FunctionDecl* thunk_function_decl) + -> llvm::SmallVector { + clang::SourceLocation clang_loc = callee_function_decl.getLocation(); + + unsigned num_params = thunk_function_decl->getNumParams(); + CARBON_CHECK(callee_function_decl.getNumParams() == num_params); + + const auto* thunk_function_proto_type = + thunk_function_decl->getFunctionType()->getAs(); + + llvm::SmallVector thunk_params; + thunk_params.reserve(num_params); + for (unsigned i = 0; i < num_params; ++i) { + clang::ParmVarDecl* thunk_param = clang::ParmVarDecl::Create( + ast_context, thunk_function_decl, clang_loc, clang_loc, + callee_function_decl.getParamDecl(i)->getIdentifier(), + thunk_function_proto_type->getParamType(i), nullptr, clang::SC_None, + nullptr); + thunk_params.push_back(thunk_param); + } + return thunk_params; +} + +// Returns the thunk function declaration given the callee function and the +// thunk parameter types. +static auto CreateThunkFunctionDecl( + clang::ASTContext& ast_context, + const clang::FunctionDecl& callee_function_decl, + llvm::ArrayRef thunk_param_types) -> clang::FunctionDecl* { + clang::SourceLocation clang_loc = callee_function_decl.getLocation(); + + clang::IdentifierInfo& identifier_info = ast_context.Idents.get( + callee_function_decl.getNameAsString() + "__carbon_thunk"); + + const auto* callee_function_type = callee_function_decl.getFunctionType() + ->castAs(); + + // TODO: Check whether we need to modify `ExtParameterInfo` in `ExtProtoInfo`. + clang::QualType thunk_function_type = ast_context.getFunctionType( + callee_function_decl.getReturnType(), thunk_param_types, + callee_function_type->getExtProtoInfo()); + + // TODO: Thunks should not have external linkage, consider using `SC_Static`. + clang::FunctionDecl* thunk_function_decl = clang::FunctionDecl::Create( + ast_context, ast_context.getTranslationUnitDecl(), clang_loc, clang_loc, + clang::DeclarationName(&identifier_info), thunk_function_type, + /*TInfo=*/nullptr, clang::SC_Extern); + + thunk_function_decl->setParams(BuildThunkParameters( + ast_context, callee_function_decl, thunk_function_decl)); + + // Set always_inline. + thunk_function_decl->addAttr( + clang::AlwaysInlineAttr::CreateImplicit(ast_context)); + + // Set asm(".carbon_thunk"). + thunk_function_decl->addAttr(clang::AsmLabelAttr::CreateImplicit( + ast_context, GenerateThunkMangledName(ast_context, callee_function_decl), + clang_loc)); + + return thunk_function_decl; +} + +// Takes the thunk function parameters and for each one creates an arg for the +// callee function which is the thunk parameter or its address. +static auto BuildCalleeArgs(clang::Sema& sema, + clang::FunctionDecl* thunk_function_decl, + llvm::ArrayRef param_type_changed) + -> llvm::SmallVector { + llvm::SmallVector call_args; + size_t num_params = thunk_function_decl->getNumParams(); + CARBON_CHECK(param_type_changed.size() == num_params); + call_args.reserve(num_params); + for (unsigned i = 0; i < num_params; ++i) { + clang::ParmVarDecl* thunk_param = thunk_function_decl->getParamDecl(i); + clang::SourceLocation clang_loc = thunk_param->getLocation(); + + clang::Expr* call_arg = sema.BuildDeclRefExpr( + thunk_param, thunk_param->getType(), clang::VK_LValue, clang_loc); + if (param_type_changed[i]) { + // TODO: Insert a cast to an rvalue. + clang::ExprResult deref_result = + sema.BuildUnaryOp(nullptr, clang_loc, clang::UO_Deref, call_arg); + CARBON_CHECK(deref_result.isUsable()); + call_arg = deref_result.get(); + } + call_args.push_back(call_arg); + } + + return call_args; +} + +// Builds the thunk function body which calls the callee function using the call +// args and returns the callee function return value. Returns nullptr on +// failure. +static auto BuildThunkBody(clang::Sema& sema, + clang::FunctionDecl* callee_function_decl, + llvm::MutableArrayRef call_args) + -> clang::Stmt* { + clang::SourceLocation clang_loc = callee_function_decl->getLocation(); + + clang::DeclRefExpr* callee_function_ref = sema.BuildDeclRefExpr( + callee_function_decl, callee_function_decl->getType(), clang::VK_PRValue, + clang_loc); + + clang::ExprResult call_result = sema.BuildCallExpr( + nullptr, callee_function_ref, clang_loc, call_args, clang_loc); + if (!call_result.isUsable()) { + return nullptr; + } + clang::Expr* call = call_result.get(); + + clang::StmtResult return_result = sema.BuildReturnStmt(clang_loc, call); + CARBON_CHECK(return_result.isUsable()); + return return_result.get(); +} + +auto BuildCppThunk(Context& context, const SemIR::Function& callee_function) + -> clang::FunctionDecl* { + clang::ASTContext& ast_context = context.ast_context(); + + clang::FunctionDecl* callee_function_decl = + context.sem_ir() + .clang_decls() + .Get(callee_function.clang_decl_id) + .decl->getAsFunction(); + CARBON_CHECK(callee_function_decl); + + // Build the thunk function declaration. + auto [thunk_param_types, param_type_changed] = + BuildThunkParameterTypes(ast_context, *callee_function_decl); + clang::FunctionDecl* thunk_function_decl = CreateThunkFunctionDecl( + ast_context, *callee_function_decl, thunk_param_types); + + // Build the thunk function body. + clang::Sema& sema = context.sem_ir().cpp_ast()->getSema(); + clang::Sema::ContextRAII context_raii(sema, thunk_function_decl); + sema.ActOnStartOfFunctionDef(nullptr, thunk_function_decl); + + llvm::SmallVector call_args = + BuildCalleeArgs(sema, thunk_function_decl, param_type_changed); + clang::Stmt* body = BuildThunkBody(sema, callee_function_decl, call_args); + sema.ActOnFinishFunctionBody(thunk_function_decl, body); + if (!body) { + return nullptr; + } + + return thunk_function_decl; +} + +auto PerformCppThunkCall(Context& context, SemIR::LocId loc_id, + SemIR::FunctionId callee_function_id, + llvm::ArrayRef callee_arg_ids, + SemIR::InstId thunk_callee_id) -> SemIR::InstId { + llvm::ArrayRef callee_function_params = + context.inst_blocks().GetOrEmpty( + context.functions().Get(callee_function_id).call_params_id); + + llvm::ArrayRef thunk_function_params = + context.inst_blocks().GetOrEmpty( + context.functions() + .Get(GetCalleeFunction(context.sem_ir(), thunk_callee_id) + .function_id) + .call_params_id); + + size_t num_params = callee_function_params.size(); + CARBON_CHECK(thunk_function_params.size() == num_params); + CARBON_CHECK(callee_arg_ids.size() == num_params); + llvm::SmallVector thunk_arg_ids; + thunk_arg_ids.reserve(callee_arg_ids.size()); + for (size_t i = 0; i < callee_function_params.size(); ++i) { + SemIR::TypeId callee_param_type_id = + context.insts() + .GetAs(callee_function_params[i]) + .type_id; + SemIR::TypeId thunk_param_type_id = + context.insts() + .GetAs(thunk_function_params[i]) + .type_id; + + SemIR::InstId arg_id = callee_arg_ids[i]; + if (callee_param_type_id != thunk_param_type_id) { + CARBON_CHECK(thunk_param_type_id == + GetPointerType(context, context.types().GetInstId( + callee_param_type_id))); + + // TODO: Don't create storage if it's already in a storage (depends on + // expression category). + SemIR::InstId temporary_storage_inst_id = AddInstWithCleanup( + context, loc_id, + SemIR::TemporaryStorage{.type_id = callee_param_type_id}); + AddInst(context, loc_id, + SemIR::InitializeFrom{.type_id = callee_param_type_id, + .src_id = arg_id, + .dest_id = temporary_storage_inst_id}); + + // TODO: Do not use `InitializeFrom` directly. Use the `Initialize` + // machinery. See + // https://github.com/carbon-language/carbon-lang/pull/5850/files#r2249030529. + arg_id = AddInst(context, loc_id, + SemIR::AddrOf{.type_id = thunk_param_type_id, + .lvalue_id = temporary_storage_inst_id}); + } + thunk_arg_ids.push_back(arg_id); + } + + return PerformCall(context, loc_id, thunk_callee_id, thunk_arg_ids); +} + +} // namespace Carbon::Check diff --git a/toolchain/check/cpp_thunk.h b/toolchain/check/cpp_thunk.h new file mode 100644 index 000000000000..0256e70b4c48 --- /dev/null +++ b/toolchain/check/cpp_thunk.h @@ -0,0 +1,38 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef CARBON_TOOLCHAIN_CHECK_CPP_THUNK_H_ +#define CARBON_TOOLCHAIN_CHECK_CPP_THUNK_H_ + +#include "toolchain/check/context.h" +#include "toolchain/sem_ir/ids.h" + +namespace Carbon::Check { + +// Returns whether the given C++ imported function requires a C++ thunk to be +// used to call it. A C++ thunk is required for functions that use any type +// except void, pointer types and signed 32-bit and 64-bit integers. +auto IsCppThunkRequired(Context& context, const SemIR::Function& function) + -> bool; + +// Given a function signature and a callee function, builds a C++ thunk with +// simple ABI (pointers, i32 and i64 types) that calls the specified callee. +// Assumes `IsCppThunkRequired()` return true for `callee_function`. Returns +// `nullptr` on failure. +auto BuildCppThunk(Context& context, const SemIR::Function& callee_function) + -> clang::FunctionDecl*; + +// Builds a call to a thunk function that forwards a call argument list built +// for `callee_function_id` to a call to `thunk_callee_id`, for use when +// building a call from a C++ thunk to its target. This is like `PerformCall`, +// except that it takes a list of call arguments for `callee_function_id`, not a +// syntactic argument list. +auto PerformCppThunkCall(Context& context, SemIR::LocId loc_id, + SemIR::FunctionId callee_function_id, + llvm::ArrayRef callee_arg_ids, + SemIR::InstId thunk_callee_id) -> SemIR::InstId; + +} // namespace Carbon::Check + +#endif // CARBON_TOOLCHAIN_CHECK_CPP_THUNK_H_ diff --git a/toolchain/check/import_cpp.cpp b/toolchain/check/import_cpp.cpp index d0cc1662a3e9..9df4855339aa 100644 --- a/toolchain/check/import_cpp.cpp +++ b/toolchain/check/import_cpp.cpp @@ -29,6 +29,7 @@ #include "toolchain/check/class.h" #include "toolchain/check/context.h" #include "toolchain/check/convert.h" +#include "toolchain/check/cpp_thunk.h" #include "toolchain/check/diagnostic_helpers.h" #include "toolchain/check/eval.h" #include "toolchain/check/function.h" @@ -38,11 +39,13 @@ #include "toolchain/check/pattern.h" #include "toolchain/check/pattern_match.h" #include "toolchain/check/type.h" +#include "toolchain/check/type_completion.h" #include "toolchain/diagnostics/diagnostic.h" #include "toolchain/diagnostics/diagnostic_emitter.h" #include "toolchain/diagnostics/format_providers.h" #include "toolchain/parse/node_ids.h" #include "toolchain/sem_ir/clang_decl.h" +#include "toolchain/sem_ir/function.h" #include "toolchain/sem_ir/ids.h" #include "toolchain/sem_ir/inst.h" #include "toolchain/sem_ir/name_scope.h" @@ -932,7 +935,8 @@ static auto MakeIntType(Context& context, IntId size_id, bool is_signed) // Maps a C++ builtin type to a Carbon type. // TODO: Support more builtin types. -static auto MapBuiltinType(Context& context, clang::QualType qual_type, +static auto MapBuiltinType(Context& context, SemIR::LocId loc_id, + clang::QualType qual_type, const clang::BuiltinType& type) -> TypeExpr { clang::ASTContext& ast_context = context.ast_context(); if (type.isBooleanType()) { @@ -942,11 +946,22 @@ static auto MapBuiltinType(Context& context, clang::QualType qual_type, context, SemIR::BoolType::TypeInstId))); } if (type.isInteger()) { - auto width = ast_context.getIntWidth(qual_type); + unsigned width = context.ast_context().getIntWidth(qual_type); bool is_signed = type.isSignedInteger(); - auto int_n_type = ast_context.getIntTypeForBitwidth(width, is_signed); - if (ast_context.hasSameType(qual_type, int_n_type)) { - return MakeIntType(context, context.ints().Add(width), is_signed); + auto int_n_type = + context.ast_context().getIntTypeForBitwidth(width, is_signed); + if (context.ast_context().hasSameType(qual_type, int_n_type)) { + TypeExpr type_expr = + MakeIntType(context, context.ints().Add(width), is_signed); + // Try to make sure signed integer of 32 or 64 bits are complete so we can + // check against them when deciding whether we need to generate a thunk. + if (is_signed && (width == 32 || width == 64)) { + SemIR::TypeId type_id = type_expr.type_id; + if (!context.types().IsComplete(type_id)) { + TryToCompleteType(context, type_id, loc_id); + } + } + return type_expr; } // TODO: Handle integer types that map to named aliases. } else if (type.isDoubleType()) { @@ -986,10 +1001,10 @@ static auto MapRecordType(Context& context, const clang::RecordType& type) // Maps a C++ type that is not a wrapper type such as a pointer to a Carbon // type. // TODO: Support more types. -static auto MapNonWrapperType(Context& context, clang::QualType type) - -> TypeExpr { +static auto MapNonWrapperType(Context& context, SemIR::LocId loc_id, + clang::QualType type) -> TypeExpr { if (const auto* builtin_type = type->getAs()) { - return MapBuiltinType(context, type, *builtin_type); + return MapBuiltinType(context, loc_id, type, *builtin_type); } if (const auto* record_type = type->getAs()) { @@ -1066,7 +1081,7 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type) wrapper_types.push_back(orig_type); } - auto mapped = MapNonWrapperType(context, type); + auto mapped = MapNonWrapperType(context, loc_id, type); for (auto wrapper : llvm::reverse(wrapper_types)) { if (!mapped.inst_id.has_value() || @@ -1300,6 +1315,64 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id, .call_params_id = call_params_id}}; } +// Creates a `FunctionDecl` and a `Function` without C++ thunk information. +// Returns std::nullopt on failure. The given Clang declaration is assumed to: +// * Have not been imported before. +// * Be of supported type (ignoring parameters). +static auto ImportFunction(Context& context, SemIR::LocId loc_id, + clang::FunctionDecl* clang_decl) + -> std::optional { + context.scope_stack().PushForDeclName(); + context.inst_block_stack().Push(); + context.pattern_block_stack().Push(); + + auto function_params_insts = + CreateFunctionParamsInsts(context, loc_id, clang_decl); + + auto pattern_block_id = context.pattern_block_stack().Pop(); + auto decl_block_id = context.inst_block_stack().Pop(); + context.scope_stack().Pop(); + + if (!function_params_insts.has_value()) { + return std::nullopt; + } + + auto function_decl = SemIR::FunctionDecl{ + SemIR::TypeId::None, SemIR::FunctionId::None, decl_block_id}; + auto decl_id = + AddPlaceholderInstInNoBlock(context, Parse::NodeId::None, function_decl); + context.imports().push_back(decl_id); + + auto function_info = SemIR::Function{ + {.name_id = AddIdentifierName(context, clang_decl->getName()), + .parent_scope_id = GetParentNameScopeId(context, clang_decl), + .generic_id = SemIR::GenericId::None, + .first_param_node_id = Parse::NodeId::None, + .last_param_node_id = Parse::NodeId::None, + .pattern_block_id = pattern_block_id, + .implicit_param_patterns_id = + function_params_insts->implicit_param_patterns_id, + .param_patterns_id = function_params_insts->param_patterns_id, + .is_extern = false, + .extern_library_id = SemIR::LibraryNameId::None, + .non_owning_decl_id = SemIR::InstId::None, + .first_owning_decl_id = decl_id, + .definition_id = SemIR::InstId::None}, + {.call_params_id = function_params_insts->call_params_id, + .return_slot_pattern_id = function_params_insts->return_slot_pattern_id, + .virtual_modifier = SemIR::FunctionFields::VirtualModifier::None, + .self_param_id = FindSelfPattern( + context, function_params_insts->implicit_param_patterns_id), + .clang_decl_id = context.sem_ir().clang_decls().Add( + {.decl = clang_decl, .inst_id = decl_id})}}; + + function_decl.function_id = context.functions().Add(function_info); + function_decl.type_id = GetFunctionType(context, function_decl.function_id, + SemIR::SpecificId::None); + ReplaceInstBeforeConstantUse(context, decl_id, function_decl); + return function_decl.function_id; +} + // Imports a function declaration from Clang to Carbon. If successful, returns // the new Carbon function declaration `InstId`. If the declaration was already // imported, returns the mapped instruction. @@ -1334,59 +1407,29 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, } } - context.scope_stack().PushForDeclName(); - context.inst_block_stack().Push(); - context.pattern_block_stack().Push(); + CARBON_CHECK(clang_decl->getFunctionType()->isFunctionProtoType(), + "Not Prototype function (non-C++ code)"); - auto function_params_insts = - CreateFunctionParamsInsts(context, loc_id, clang_decl); - - auto pattern_block_id = context.pattern_block_stack().Pop(); - auto decl_block_id = context.inst_block_stack().Pop(); - context.scope_stack().Pop(); - - if (!function_params_insts.has_value()) { + auto function_id = ImportFunction(context, loc_id, clang_decl); + if (!function_id) { MarkFailedDecl(context, clang_decl); return SemIR::ErrorInst::InstId; } - auto function_decl = SemIR::FunctionDecl{ - SemIR::TypeId::None, SemIR::FunctionId::None, decl_block_id}; - auto decl_id = - AddPlaceholderInstInNoBlock(context, Parse::NodeId::None, function_decl); - context.imports().push_back(decl_id); + SemIR::Function& function_info = context.functions().Get(*function_id); + if (IsCppThunkRequired(context, function_info)) { + clang::FunctionDecl* thunk_clang_decl = + BuildCppThunk(context, function_info); + if (thunk_clang_decl) { + SemIR::FunctionId thunk_function_id = + *ImportFunction(context, loc_id, thunk_clang_decl); + SemIR::InstId thunk_function_decl_id = + context.functions().Get(thunk_function_id).first_owning_decl_id; + function_info.SetHasCppThunk(thunk_function_decl_id); + } + } - auto function_info = SemIR::Function{ - {.name_id = AddIdentifierName(context, clang_decl->getName()), - .parent_scope_id = GetParentNameScopeId(context, clang_decl), - .generic_id = SemIR::GenericId::None, - .first_param_node_id = Parse::NodeId::None, - .last_param_node_id = Parse::NodeId::None, - .pattern_block_id = pattern_block_id, - .implicit_param_patterns_id = - function_params_insts->implicit_param_patterns_id, - .param_patterns_id = function_params_insts->param_patterns_id, - .is_extern = false, - .extern_library_id = SemIR::LibraryNameId::None, - .non_owning_decl_id = SemIR::InstId::None, - .first_owning_decl_id = decl_id, - .definition_id = SemIR::InstId::None}, - {.call_params_id = function_params_insts->call_params_id, - .return_slot_pattern_id = function_params_insts->return_slot_pattern_id, - .virtual_modifier = SemIR::FunctionFields::VirtualModifier::None, - .self_param_id = FindSelfPattern( - context, function_params_insts->implicit_param_patterns_id), - .clang_decl_id = context.sem_ir().clang_decls().Add( - {.decl = clang_decl, .inst_id = decl_id})}}; - - function_decl.function_id = context.functions().Add(function_info); - - function_decl.type_id = GetFunctionType(context, function_decl.function_id, - SemIR::SpecificId::None); - - ReplaceInstBeforeConstantUse(context, decl_id, function_decl); - - return decl_id; + return function_info.first_owning_decl_id; } using DeclSet = llvm::SetVector; diff --git a/toolchain/check/import_ref.cpp b/toolchain/check/import_ref.cpp index 348510fdabc3..2d5fc829f8f7 100644 --- a/toolchain/check/import_ref.cpp +++ b/toolchain/check/import_ref.cpp @@ -1956,6 +1956,11 @@ static auto TryResolveTypedInst(ImportRefResolver& resolver, resolver, import_function.thunk_decl_id(), entity_name_id)); break; } + case SemIR::Function::SpecialFunctionKind::HasCppThunk: { + resolver.local_context().TODO(SemIR::LocId::None, + "Unsupported: Importing C++ functions that " + "require thunks indirectly"); + } } return ResolveResult::Done(function_const_id, new_function.first_decl_id()); diff --git a/toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon b/toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon index f4dd0bb45325..4799374ffe5c 100644 --- a/toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon +++ b/toolchain/check/testdata/interop/cpp/function/arithmetic_types_bridged.carbon @@ -13,7 +13,6 @@ // Tests for the case where we need a thunk when calling a C++ function from // Carbon, because the parameter and return types might have a non-trivial // calling convention. -// TODO: Create thunks for these cases. // ============================================================================ // bool param @@ -418,6 +417,81 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// unsigned int param +// ============================================================================ + +// --- unsigned_int_param.h + +auto foo(unsigned int a) -> void; + +// --- import_unsigned_int_param.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "unsigned_int_param.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.foo(1); + //@dump-sem-ir-end +} + +// --- fail_import_unsigned_int_param_overflow.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "unsigned_int_param.h"; + +fn F() { + Cpp.foo(0); + + // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon:[[@LINE+5]]:11: error: negative integer value -1 converted to unsigned type `u32` [NegativeIntInUnsignedType] + // CHECK:STDERR: Cpp.foo(-1); + // CHECK:STDERR: ^~ + // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: + Cpp.foo(-1); + + Cpp.foo(0x0_FFFF_FFFF); + + // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon:[[@LINE+5]]:11: error: integer value 4294967296 too large for type `u32` [IntTooLargeForType] + // CHECK:STDERR: Cpp.foo(0x1_0000_0000); + // CHECK:STDERR: ^~~~~~~~~~~~~ + // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: + Cpp.foo(0x1_0000_0000); +} + +// ============================================================================ +// _BitInt(24) param +// ============================================================================ + +// --- bit_int_24_param.h + +using bit_int_24 = _BitInt(24); + +auto foo(bit_int_24 x) -> void; + +// --- fail_todo_import_bit_int_24_param.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "bit_int_24_param.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_todo_import_bit_int_24_param.carbon:[[@LINE+7]]:3: error: semantics TODO: `Unsupported: parameter type: bit_int_24` [SemanticsTodo] + // CHECK:STDERR: Cpp.foo(1); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_import_bit_int_24_param.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(1); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo(1); + //@dump-sem-ir-end +} + // ============================================================================ // double return // ============================================================================ @@ -438,14 +512,18 @@ fn F() { //@dump-sem-ir-end } - // CHECK:STDOUT: --- import_bool_param_true.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.bb2: type = ptr_type bool [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: %true: bool = bool_literal true [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.655: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(bool) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.8b7: %T.as.Destroy.impl.Op.type.655 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -458,6 +536,11 @@ fn F() { // 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() { @@ -465,7 +548,15 @@ fn F() { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %true: bool = bool_literal true [concrete = constants.%true] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%true) +// CHECK:STDOUT: %.loc8_15.1: ref bool = temporary_storage +// CHECK:STDOUT: %.loc8_15.2: init bool = initialize_from %true to %.loc8_15.1 [concrete = constants.%true] +// CHECK:STDOUT: %addr.loc8_15.1: %ptr.bb2 = addr_of %.loc8_15.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_15.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_15.1, constants.%T.as.Destroy.impl.Op.8b7 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc8_15.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_15.2: %ptr.bb2 = addr_of %.loc8_15.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_15.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -475,7 +566,12 @@ fn F() { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.bb2: type = ptr_type bool [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: %false: bool = bool_literal false [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.655: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(bool) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.8b7: %T.as.Destroy.impl.Op.type.655 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -488,6 +584,11 @@ fn F() { // 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() { @@ -495,7 +596,15 @@ fn F() { // CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] // CHECK:STDOUT: %false: bool = bool_literal false [concrete = constants.%false] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%false) +// CHECK:STDOUT: %.loc8_16.1: ref bool = temporary_storage +// CHECK:STDOUT: %.loc8_16.2: init bool = initialize_from %false to %.loc8_16.1 [concrete = constants.%false] +// CHECK:STDOUT: %addr.loc8_16.1: %ptr.bb2 = addr_of %.loc8_16.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_16.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_16.1, constants.%T.as.Destroy.impl.Op.8b7 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc8_16.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_16.2: %ptr.bb2 = addr_of %.loc8_16.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_16.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -507,6 +616,9 @@ fn F() { // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %As.Convert.type.be5: type = fn_type @As.Convert, @As(%i16) [concrete] @@ -522,6 +634,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.489, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_1.f90: %i16 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -534,6 +648,11 @@ fn F() { // 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: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] // CHECK:STDOUT: } @@ -552,7 +671,15 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc8_13.2(%int_1) [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.2: %i16 = converted %int_1, %.loc8_13.1 [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_13.2) +// CHECK:STDOUT: %.loc8_19.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_19.2: init %i16 = initialize_from %.loc8_13.2 to %.loc8_19.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %addr.loc8_19.1: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_19.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_19.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_19: = bound_method %.loc8_19.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_19.2: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_19(%addr.loc8_19.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -564,6 +691,9 @@ fn F() { // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [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: %int_32767.f4b: Core.IntLiteral = int_value 32767 [concrete] // CHECK:STDOUT: %ImplicitAs.type.adb: type = facet_type <@ImplicitAs, @ImplicitAs(%i16)> [concrete] // CHECK:STDOUT: %ImplicitAs.Convert.type.fa6: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i16) [concrete] @@ -579,6 +709,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.d0a, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_32767.f4b, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_32767.faa: %i16 = int_value 32767 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -591,6 +723,11 @@ fn F() { // 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: %Core.import_ref.a5b: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f06)] // CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @Core.IntLiteral.as.ImplicitAs.impl [concrete] // CHECK:STDOUT: } @@ -607,7 +744,15 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i16 = call %bound_method.loc8_11.2(%int_32767) [concrete = constants.%int_32767.faa] // CHECK:STDOUT: %.loc8_11.1: %i16 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_32767.faa] // CHECK:STDOUT: %.loc8_11.2: %i16 = converted %int_32767, %.loc8_11.1 [concrete = constants.%int_32767.faa] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_11.2) +// CHECK:STDOUT: %.loc8_17.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_17.2: init %i16 = initialize_from %.loc8_11.2 to %.loc8_17.1 [concrete = constants.%int_32767.faa] +// CHECK:STDOUT: %addr.loc8_17.1: %ptr.251 = addr_of %.loc8_17.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_17.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_17.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_17: = bound_method %.loc8_17.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_17.2: %ptr.251 = addr_of %.loc8_17.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_17(%addr.loc8_17.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -619,6 +764,9 @@ fn F() { // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [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: %int_32768: Core.IntLiteral = int_value 32768 [concrete] // CHECK:STDOUT: %Negate.type: type = facet_type <@Negate> [concrete] // CHECK:STDOUT: %Negate.Op.type: type = fn_type @Negate.Op [concrete] @@ -643,6 +791,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.d0a, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_-32768.882, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_-32768.7e5: %i16 = int_value -32768 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -655,6 +805,11 @@ fn F() { // 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: %Core.import_ref.abd = import_ref Core//prelude/parts/int_literal, loc13_50, unloaded // CHECK:STDOUT: %Core.import_ref.5e6: %Core.IntLiteral.as.Negate.impl.Op.type = import_ref Core//prelude/parts/int_literal, loc14_31, loaded [concrete = constants.%Core.IntLiteral.as.Negate.impl.Op] // CHECK:STDOUT: %Negate.impl_witness_table.b22 = impl_witness_table (%Core.import_ref.abd, %Core.import_ref.5e6), @Core.IntLiteral.as.Negate.impl [concrete] @@ -679,7 +834,15 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i16 = call %bound_method.loc8_11.3(%.loc8_11.2) [concrete = constants.%int_-32768.7e5] // CHECK:STDOUT: %.loc8_11.3: %i16 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_-32768.7e5] // CHECK:STDOUT: %.loc8_11.4: %i16 = converted %Core.IntLiteral.as.Negate.impl.Op.call, %.loc8_11.3 [concrete = constants.%int_-32768.7e5] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_11.4) +// CHECK:STDOUT: %.loc8_18.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_18.2: init %i16 = initialize_from %.loc8_11.4 to %.loc8_18.1 [concrete = constants.%int_-32768.7e5] +// CHECK:STDOUT: %addr.loc8_18.1: %ptr.251 = addr_of %.loc8_18.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_18.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_18.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_18: = bound_method %.loc8_18.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_18.2: %ptr.251 = addr_of %.loc8_18.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_18(%addr.loc8_18.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -691,6 +854,9 @@ fn F() { // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %As.Convert.type.be5: type = fn_type @As.Convert, @As(%i16) [concrete] @@ -706,6 +872,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.489, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_1.f90: %i16 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -718,6 +886,11 @@ fn F() { // 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: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] // CHECK:STDOUT: } @@ -736,7 +909,15 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc8_13.2(%int_1) [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.2: %i16 = converted %int_1, %.loc8_13.1 [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_13.2) +// CHECK:STDOUT: %.loc8_19.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_19.2: init %i16 = initialize_from %.loc8_13.2 to %.loc8_19.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %addr.loc8_19.1: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_19.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_19.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_19: = bound_method %.loc8_19.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_19.2: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_19(%addr.loc8_19.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -748,6 +929,9 @@ fn F() { // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %As.Convert.type.be5: type = fn_type @As.Convert, @As(%i16) [concrete] @@ -763,6 +947,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.489, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_1.f90: %i16 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -775,6 +961,11 @@ fn F() { // 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: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] // CHECK:STDOUT: } @@ -793,7 +984,15 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc8_13.2(%int_1) [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.2: %i16 = converted %int_1, %.loc8_13.1 [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_13.2) +// CHECK:STDOUT: %.loc8_19.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_19.2: init %i16 = initialize_from %.loc8_13.2 to %.loc8_19.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %addr.loc8_19.1: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_19.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_19.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_19: = bound_method %.loc8_19.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_19.2: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_19(%addr.loc8_19.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -805,6 +1004,9 @@ fn F() { // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %As.Convert.type.be5: type = fn_type @As.Convert, @As(%i16) [concrete] @@ -820,6 +1022,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.489, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_1.f90: %i16 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -832,6 +1036,11 @@ fn F() { // 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: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] // CHECK:STDOUT: } @@ -850,7 +1059,15 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc8_13.2(%int_1) [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.2: %i16 = converted %int_1, %.loc8_13.1 [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_13.2) +// CHECK:STDOUT: %.loc8_19.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_19.2: init %i16 = initialize_from %.loc8_13.2 to %.loc8_19.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %addr.loc8_19.1: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_19.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_19.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_19: = bound_method %.loc8_19.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_19.2: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_19(%addr.loc8_19.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -862,6 +1079,9 @@ fn F() { // CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %As.Convert.type.be5: type = fn_type @As.Convert, @As(%i16) [concrete] @@ -877,6 +1097,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.489, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_1.f90: %i16 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -889,6 +1111,11 @@ fn F() { // 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: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] // CHECK:STDOUT: } @@ -907,7 +1134,15 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc8_13.2(%int_1) [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc8_13.2: %i16 = converted %int_1, %.loc8_13.1 [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_13.2) +// CHECK:STDOUT: %.loc8_19.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_19.2: init %i16 = initialize_from %.loc8_13.2 to %.loc8_19.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %addr.loc8_19.1: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_19.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_19.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_19: = bound_method %.loc8_19.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_19.2: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_19(%addr.loc8_19.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -920,6 +1155,9 @@ fn F() { // CHECK:STDOUT: %const: type = const_type %i16 [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.758: type = ptr_type %const [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %As.Convert.type.be5: type = fn_type @As.Convert, @As(%i16) [concrete] @@ -935,6 +1173,8 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.489, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_1.f90: %i16 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.913: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%const) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.571: %T.as.Destroy.impl.Op.type.913 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -947,6 +1187,11 @@ fn F() { // 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: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] // CHECK:STDOUT: } @@ -966,7 +1211,15 @@ fn F() { // CHECK:STDOUT: %.loc16_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc16_13.2: %i16 = converted %int_1, %.loc16_13.1 [concrete = constants.%int_1.f90] // CHECK:STDOUT: %.loc16_13.3: %const = converted %.loc16_13.2, [concrete = ] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc16_19.1: ref %const = temporary_storage +// CHECK:STDOUT: %.loc16_19.2: init %const = initialize_from to %.loc16_19.1 [concrete = ] +// CHECK:STDOUT: %addr.loc16_19.1: %ptr.758 = addr_of %.loc16_19.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc16_19.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc16_19.1, constants.%T.as.Destroy.impl.Op.571 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc16_19: = bound_method %.loc16_19.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc16_19.2: %ptr.758 = addr_of %.loc16_19.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc16_19(%addr.loc16_19.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1096,7 +1349,12 @@ fn F() { // CHECK:STDOUT: %Float: %Float.type = struct_value () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.ef1: type = ptr_type f64 [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: %float: f64 = float_value 0.80000000000000004 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.3ef: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(f64) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.868: %T.as.Destroy.impl.Op.type.3ef = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -1109,6 +1367,11 @@ fn F() { // 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() { @@ -1120,7 +1383,15 @@ fn F() { // CHECK:STDOUT: %Float.call: init type = call constants.%Float(%int_64) [concrete = f64] // CHECK:STDOUT: %.loc8_18.1: type = value_of_initializer %Float.call [concrete = f64] // CHECK:STDOUT: %.loc8_18.2: type = converted %Float.call, %.loc8_18.1 [concrete = f64] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%float) +// CHECK:STDOUT: %.loc8_21.1: ref f64 = temporary_storage +// CHECK:STDOUT: %.loc8_21.2: init f64 = initialize_from %float to %.loc8_21.1 [concrete = constants.%float] +// CHECK:STDOUT: %addr.loc8_21.1: %ptr.ef1 = addr_of %.loc8_21.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_21.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_21.1, constants.%T.as.Destroy.impl.Op.868 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc8_21.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_21.2: %ptr.ef1 = addr_of %.loc8_21.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc8_21.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -1205,6 +1476,100 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- import_unsigned_int_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %u32: type = class_type @UInt, @UInt(%int_32) [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.6fd: type = ptr_type %u32 [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.9b4: type = facet_type <@ImplicitAs, @ImplicitAs(%u32)> [concrete] +// CHECK:STDOUT: %ImplicitAs.Convert.type.92a: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%u32) [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.30e: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.d1a: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.30e = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.ac5: = impl_witness imports.%ImplicitAs.impl_witness_table.bb8, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.feb: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.319: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.feb = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.9b4 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.ac5) [concrete] +// CHECK:STDOUT: %.bd1: type = fn_type_with_self_type %ImplicitAs.Convert.type.92a, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.319 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.319, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_1.c1d: %u32 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.4b6: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%u32) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.63d: %T.as.Destroy.impl.Op.type.4b6 = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %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: %Core.import_ref.c3d: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.30e) = import_ref Core//prelude/parts/uint, loc16_40, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.d1a)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.bb8 = impl_witness_table (%Core.import_ref.c3d), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] +// CHECK:STDOUT: %impl.elem0: %.bd1 = impl_witness_access constants.%ImplicitAs.impl_witness.ac5, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.319] +// CHECK:STDOUT: %bound_method.loc8_11.1: = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_11.2: = bound_method %int_1, %specific_fn [concrete = constants.%bound_method] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %u32 = call %bound_method.loc8_11.2(%int_1) [concrete = constants.%int_1.c1d] +// CHECK:STDOUT: %.loc8_11.1: %u32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.c1d] +// CHECK:STDOUT: %.loc8_11.2: %u32 = converted %int_1, %.loc8_11.1 [concrete = constants.%int_1.c1d] +// CHECK:STDOUT: %.loc8_12.1: ref %u32 = temporary_storage +// CHECK:STDOUT: %.loc8_12.2: init %u32 = initialize_from %.loc8_11.2 to %.loc8_12.1 [concrete = constants.%int_1.c1d] +// CHECK:STDOUT: %addr.loc8_12.1: %ptr.6fd = addr_of %.loc8_12.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_12.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.1, constants.%T.as.Destroy.impl.Op.63d +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_12.2: %ptr.6fd = addr_of %.loc8_12.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12.2) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_todo_import_bit_int_24_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: = name_ref foo, [concrete = ] +// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1] +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: --- import_double_return.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/testdata/interop/cpp/function/arithmetic_types_direct.carbon b/toolchain/check/testdata/interop/cpp/function/arithmetic_types_direct.carbon index eb3f2a0f2890..9b5ed0964fce 100644 --- a/toolchain/check/testdata/interop/cpp/function/arithmetic_types_direct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/arithmetic_types_direct.carbon @@ -106,52 +106,6 @@ fn F() { //@dump-sem-ir-end } -// ============================================================================ -// unsigned int param -// ============================================================================ - -// --- unsigned_int_param.h - -auto foo(unsigned int a) -> void; - -// --- import_unsigned_int_param.carbon - -library "[[@TEST_NAME]]"; - -import Cpp library "unsigned_int_param.h"; - -fn F() { - //@dump-sem-ir-begin - Cpp.foo(1); - //@dump-sem-ir-end -} - -// --- fail_import_unsigned_int_param_overflow.carbon - -library "[[@TEST_NAME]]"; - -import Cpp library "unsigned_int_param.h"; - -fn F() { - Cpp.foo(0); - - // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon:[[@LINE+5]]:11: error: negative integer value -1 converted to unsigned type `u32` [NegativeIntInUnsignedType] - // CHECK:STDERR: Cpp.foo(-1); - // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon: note: initializing function parameter [InCallToFunctionParam] - // CHECK:STDERR: - Cpp.foo(-1); - - Cpp.foo(0x0_FFFF_FFFF); - - // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon:[[@LINE+5]]:11: error: integer value 4294967296 too large for type `u32` [IntTooLargeForType] - // CHECK:STDERR: Cpp.foo(0x1_0000_0000); - // CHECK:STDERR: ^~~~~~~~~~~~~ - // CHECK:STDERR: fail_import_unsigned_int_param_overflow.carbon: note: initializing function parameter [InCallToFunctionParam] - // CHECK:STDERR: - Cpp.foo(0x1_0000_0000); -} - // ============================================================================ // signed param // ============================================================================ @@ -453,6 +407,26 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// long param +// ============================================================================ + +// --- long_param.h + +auto foo(long a) -> void; + +// --- import_long_param.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "long_param.h"; + +fn F() { + //@dump-sem-ir-begin + Cpp.foo(1); + //@dump-sem-ir-end +} + // CHECK:STDOUT: --- import_int_param_max.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -635,61 +609,6 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: --- import_unsigned_int_param.carbon -// CHECK:STDOUT: -// CHECK:STDOUT: constants { -// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] -// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] -// CHECK:STDOUT: %u32: type = class_type @UInt, @UInt(%int_32) [concrete] -// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] -// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] -// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] -// CHECK:STDOUT: %ImplicitAs.type.9b4: type = facet_type <@ImplicitAs, @ImplicitAs(%u32)> [concrete] -// CHECK:STDOUT: %ImplicitAs.Convert.type.92a: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%u32) [concrete] -// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] -// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.30e: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] -// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.d1a: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.30e = struct_value () [symbolic] -// CHECK:STDOUT: %ImplicitAs.impl_witness.ac5: = impl_witness imports.%ImplicitAs.impl_witness_table.bb8, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] -// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.feb: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] -// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.319: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.feb = struct_value () [concrete] -// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.9b4 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.ac5) [concrete] -// CHECK:STDOUT: %.bd1: type = fn_type_with_self_type %ImplicitAs.Convert.type.92a, %ImplicitAs.facet [concrete] -// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.319 [concrete] -// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.319, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] -// CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] -// CHECK:STDOUT: %int_1.c1d: %u32 = int_value 1 [concrete] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: imports { -// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { -// CHECK:STDOUT: .foo = %foo.decl -// CHECK:STDOUT: import Cpp//... -// CHECK:STDOUT: } -// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { -// CHECK:STDOUT: -// CHECK:STDOUT: } { -// CHECK:STDOUT: -// CHECK:STDOUT: } -// CHECK:STDOUT: %Core.import_ref.c3d: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.30e) = import_ref Core//prelude/parts/uint, loc16_40, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.d1a)] -// CHECK:STDOUT: %ImplicitAs.impl_witness_table.bb8 = impl_witness_table (%Core.import_ref.c3d), @Core.IntLiteral.as.ImplicitAs.impl [concrete] -// CHECK:STDOUT: } -// CHECK:STDOUT: -// CHECK:STDOUT: fn @F() { -// CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] -// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] -// CHECK:STDOUT: %impl.elem0: %.bd1 = impl_witness_access constants.%ImplicitAs.impl_witness.ac5, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.319] -// CHECK:STDOUT: %bound_method.loc8_11.1: = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] -// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_32) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] -// CHECK:STDOUT: %bound_method.loc8_11.2: = bound_method %int_1, %specific_fn [concrete = constants.%bound_method] -// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %u32 = call %bound_method.loc8_11.2(%int_1) [concrete = constants.%int_1.c1d] -// CHECK:STDOUT: %.loc8_11.1: %u32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.c1d] -// CHECK:STDOUT: %.loc8_11.2: %u32 = converted %int_1, %.loc8_11.1 [concrete = constants.%int_1.c1d] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_11.2) -// CHECK:STDOUT: -// CHECK:STDOUT: } -// CHECK:STDOUT: // CHECK:STDOUT: --- import_signed_param.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { @@ -1291,3 +1210,58 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: --- import_long_param.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %int_64: Core.IntLiteral = int_value 64 [concrete] +// CHECK:STDOUT: %i64: type = class_type @Int, @Int(%int_64) [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.131: type = facet_type <@ImplicitAs, @ImplicitAs(%i64)> [concrete] +// CHECK:STDOUT: %ImplicitAs.Convert.type.94e: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i64) [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.f06: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9 = struct_value () [symbolic] +// CHECK:STDOUT: %ImplicitAs.impl_witness.241: = impl_witness imports.%ImplicitAs.impl_witness_table.a2f, @Core.IntLiteral.as.ImplicitAs.impl(%int_64) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.401: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_64) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.77d: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.401 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.131 = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.241) [concrete] +// CHECK:STDOUT: %.4c2: type = fn_type_with_self_type %ImplicitAs.Convert.type.94e, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.77d [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.77d, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_64) [concrete] +// CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_1.41a: %i64 = int_value 1 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %Core.import_ref.a5b: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0f9) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.f06)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.a2f = impl_witness_table (%Core.import_ref.a5b), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %int_1: Core.IntLiteral = int_value 1 [concrete = constants.%int_1.5b8] +// CHECK:STDOUT: %impl.elem0: %.4c2 = impl_witness_access constants.%ImplicitAs.impl_witness.241, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.77d] +// CHECK:STDOUT: %bound_method.loc8_11.1: = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Core.IntLiteral.as.ImplicitAs.impl.Convert(constants.%int_64) [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_11.2: = bound_method %int_1, %specific_fn [concrete = constants.%bound_method] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i64 = call %bound_method.loc8_11.2(%int_1) [concrete = constants.%int_1.41a] +// CHECK:STDOUT: %.loc8_11.1: %i64 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_1.41a] +// CHECK:STDOUT: %.loc8_11.2: %i64 = converted %int_1, %.loc8_11.1 [concrete = constants.%int_1.41a] +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_11.2) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/class.carbon b/toolchain/check/testdata/interop/cpp/function/class.carbon index 295cc9914166..0dce99339708 100644 --- a/toolchain/check/testdata/interop/cpp/function/class.carbon +++ b/toolchain/check/testdata/interop/cpp/function/class.carbon @@ -20,17 +20,29 @@ class C; auto foo(C) -> void; -// --- fail_todo_import_decl_value_param_type.carbon +// --- fail_import_decl_value_param_type.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:4:6: error: argument type 'C' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo(C) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:2:7: note: forward declaration of 'C' [CppInteropParseNote] +// CHECK:STDERR: 2 | class C; +// CHECK:STDERR: | ^ import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+8]]:11: error: invalid use of incomplete type `Cpp.C` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+12]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({} as Cpp.C); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+8]]:11: error: invalid use of incomplete type `Cpp.C` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo({} as Cpp.C); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-10]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: class C; // CHECK:STDERR: ^ @@ -38,26 +50,38 @@ fn F() { Cpp.foo({} as Cpp.C); } -// --- fail_todo_import_decl_value_param_type_previously_imported.carbon +// --- fail_import_decl_value_param_type_previously_imported.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:4:6: error: argument type 'C' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo(C) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:2:7: note: forward declaration of 'C' [CppInteropParseNote] +// CHECK:STDERR: 2 | class C; +// CHECK:STDERR: | ^ import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+12]]:10: error: binding pattern has incomplete type `C` in name binding declaration [IncompleteTypeInBindingDecl] + let c: Cpp.C; + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+16]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(c); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-5]]:10: error: binding pattern has incomplete type `C` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let c: Cpp.C; // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-11]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: class C; // CHECK:STDERR: ^ // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-13]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let c: Cpp.C; // CHECK:STDERR: ^ // CHECK:STDERR: - let c: Cpp.C; Cpp.foo(c); } @@ -72,26 +96,50 @@ class C; auto foo1(C) -> void; auto foo2(C) -> void; -// --- fail_todo_import_double_decl_value_param_type.carbon +// --- fail_import_double_decl_value_param_type.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./double_decl_value_param_type.h:4:6: error: argument type 'C' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo1(C) -> void; +// CHECK:STDERR: | ^~~~ +// CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: forward declaration of 'C' [CppInteropParseNote] +// CHECK:STDERR: 2 | class C; +// CHECK:STDERR: | ^ import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.C` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+12]]:3: note: in `Cpp` name lookup for `foo1` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo1({} as Cpp.C); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-7]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:5:6: error: argument type 'C' is incomplete [CppInteropParseError] + // CHECK:STDERR: 5 | auto foo2(C) -> void; + // CHECK:STDERR: | ^~~~ + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-11]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: forward declaration of 'C' [CppInteropParseNote] + // CHECK:STDERR: 2 | class C; + // CHECK:STDERR: | ^ + Cpp.foo1({} as Cpp.C); + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+20]]:3: note: in `Cpp` name lookup for `foo2` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo2({} as Cpp.C); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-5]]:12: error: invalid use of incomplete type `Cpp.C` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo1({} as Cpp.C); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-23]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: class C; // CHECK:STDERR: ^ // CHECK:STDERR: - Cpp.foo1({} as Cpp.C); - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.C` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.C` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo2({} as Cpp.C); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-15]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-31]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: class C; // CHECK:STDERR: ^ @@ -121,6 +169,46 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// Non copyable class as parameter type +// ============================================================================ + +// --- non_copyable_param_type.h + +class C { + C(const C&) = delete; +}; + +auto foo(C) -> void; + +// --- fail_import_non_copyable_param_type.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+12]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./non_copyable_param_type.h:6:6: error: call to deleted constructor of 'C' [CppInteropParseError] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./non_copyable_param_type.h:3:3: note: 'C' has been explicitly marked deleted here [CppInteropParseNote] +// CHECK:STDERR: 3 | C(const C&) = delete; +// CHECK:STDERR: | ^ +// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./non_copyable_param_type.h:6:11: note: passing argument to parameter here [CppInteropParseNote] +// CHECK:STDERR: 6 | auto foo(C) -> void; +// CHECK:STDERR: | ^ +import Cpp library "non_copyable_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({} as Cpp.C); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({} as Cpp.C); + //@dump-sem-ir-end +} + // ============================================================================ // Defined class with a single data member as parameter type // ============================================================================ @@ -355,21 +443,21 @@ class C; auto foo() -> C; -// --- fail_todo_import_decl_value_return_type.carbon +// --- fail_import_decl_value_return_type.carbon library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.C` [IncompleteTypeInFunctionReturnType] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.C` [IncompleteTypeInFunctionReturnType] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_return_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: class C; // CHECK:STDERR: ^ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); } @@ -447,6 +535,70 @@ fn F() { // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %C.val: %C = struct_value () [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .C = %C.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %C.decl: type = class_decl @C [concrete = constants.%C] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// 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.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc8_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %C = class_init (), %.loc8_12.2 [concrete = constants.%C.val] +// CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_14.1: ref %C = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_14.2: %C = bind_value %.loc8_14.1 +// CHECK:STDOUT: %.loc8_22.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc8_22.2: init %C = initialize_from %.loc8_14.2 to %.loc8_22.1 +// CHECK:STDOUT: %addr.loc8_22.1: %ptr.d9e = addr_of %.loc8_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_22: = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_22.2: %ptr.d9e = addr_of %.loc8_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_12: %ptr.d9e = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_import_non_copyable_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] @@ -470,21 +622,21 @@ fn F() { // 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: %Cpp.ref.loc24_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %Cpp.ref.loc8_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %.loc24_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc24_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] -// CHECK:STDOUT: %.loc8_12.2: ref %C = temporary_storage -// CHECK:STDOUT: %.loc8_12.3: init %C = class_init (), %.loc8_12.2 [concrete = constants.%C.val] -// CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 -// CHECK:STDOUT: %.loc8_14.1: ref %C = converted %.loc8_12.1, %.loc8_12.4 -// CHECK:STDOUT: %.loc8_14.2: %C = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: %.loc24_12.2: ref %C = temporary_storage +// CHECK:STDOUT: %.loc24_12.3: init %C = class_init (), %.loc24_12.2 [concrete = constants.%C.val] +// CHECK:STDOUT: %.loc24_12.4: ref %C = temporary %.loc24_12.2, %.loc24_12.3 +// CHECK:STDOUT: %.loc24_14.1: ref %C = converted %.loc24_12.1, %.loc24_12.4 +// CHECK:STDOUT: %.loc24_14.2: %C = bind_value %.loc24_14.1 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc24_14.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc24_12.2, constants.%T.as.Destroy.impl.Op.21b // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_12.2 +// CHECK:STDOUT: %bound_method: = bound_method %.loc24_12.2, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc24_12.2 // CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) // CHECK:STDOUT: // CHECK:STDOUT: } @@ -496,7 +648,12 @@ fn F() { // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -511,6 +668,11 @@ fn F() { // 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() { @@ -521,7 +683,15 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc15_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] // CHECK:STDOUT: %.loc15_14: %C = converted %.loc15_12, [concrete = ] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc15_22.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc15_22.2: init %C = initialize_from to %.loc15_22.1 [concrete = ] +// CHECK:STDOUT: %addr.loc15_22.1: %ptr.d9e = addr_of %.loc15_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc15_22.2: %ptr.d9e = addr_of %.loc15_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -532,7 +702,12 @@ fn F() { // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -547,6 +722,11 @@ fn F() { // 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() { @@ -557,7 +737,15 @@ fn F() { // CHECK:STDOUT: %Cpp.ref.loc15_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref: type = name_ref C, imports.%C.decl [concrete = constants.%C] // CHECK:STDOUT: %.loc15_14: %C = converted %.loc15_12, [concrete = ] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc15_22.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc15_22.2: init %C = initialize_from to %.loc15_22.1 [concrete = ] +// CHECK:STDOUT: %addr.loc15_22.1: %ptr.d9e = addr_of %.loc15_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc15_22.2: %ptr.d9e = addr_of %.loc15_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -569,11 +757,13 @@ fn F() { // CHECK:STDOUT: %pattern_type.69f: type = pattern_type %C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.838: type = ptr_type %C [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.9ae: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.dbb: %T.as.Destroy.impl.Op.type.9ae = struct_value () [concrete] -// CHECK:STDOUT: %ptr.838: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -592,6 +782,11 @@ fn F() { // 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() { @@ -607,7 +802,10 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %C = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %C = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_24.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc8_24.2: init %C = initialize_from %.loc8_14.2 to %.loc8_24.1 +// CHECK:STDOUT: %addr.loc8_24.1: %ptr.838 = addr_of %.loc8_24.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.69f = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.69f = var_pattern %x.patt [concrete] @@ -624,11 +822,16 @@ fn F() { // CHECK:STDOUT: %bound_method.loc10: = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1 // CHECK:STDOUT: %addr.loc10: %ptr.838 = addr_of %x.var // CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.dbb +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.dbb // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 -// CHECK:STDOUT: %addr.loc8: %ptr.838 = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) +// CHECK:STDOUT: %bound_method.loc8_24: = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_24.2: %ptr.838 = addr_of %.loc8_24.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.dbb +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3 +// CHECK:STDOUT: %addr.loc8_12: %ptr.838 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -639,11 +842,13 @@ fn F() { // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.c0c: type = ptr_type %C [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.b28: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.f48: %T.as.Destroy.impl.Op.type.b28 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.c0c: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -666,6 +871,11 @@ fn F() { // 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() { @@ -683,12 +893,20 @@ fn F() { // CHECK:STDOUT: %.loc8_15.4: ref %C = temporary %.loc8_15.2, %.loc8_15.3 // CHECK:STDOUT: %.loc8_17.1: ref %C = converted %.loc8_15.1, %.loc8_15.4 // CHECK:STDOUT: %.loc8_17.2: %C = bind_value %.loc8_17.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_17.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.f48 +// CHECK:STDOUT: %.loc8_31.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc8_31.2: init %C = initialize_from %.loc8_17.2 to %.loc8_31.1 +// CHECK:STDOUT: %addr.loc8_31.1: %ptr.c0c = addr_of %.loc8_31.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_31.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_31: = bound_method %.loc8_31.1, constants.%T.as.Destroy.impl.Op.f48 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.c0c = addr_of %.loc8_15.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc8_31: = bound_method %.loc8_31.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_31.2: %ptr.c0c = addr_of %.loc8_31.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_31: init %empty_tuple.type = call %bound_method.loc8_31(%addr.loc8_31.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_15: = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.f48 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_15: = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_15: %ptr.c0c = addr_of %.loc8_15.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_15: init %empty_tuple.type = call %bound_method.loc8_15(%addr.loc8_15) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -700,6 +918,9 @@ fn F() { // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.de2: type = ptr_type %C [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete] @@ -708,7 +929,6 @@ fn F() { // CHECK:STDOUT: %ptr.820: type = ptr_type %O [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.ac8: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.362: %T.as.Destroy.impl.Op.type.ac8 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.de2: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -724,6 +944,11 @@ fn F() { // 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() { @@ -739,7 +964,10 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %C = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %C = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_24.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc8_24.2: init %C = initialize_from %.loc8_14.2 to %.loc8_24.1 +// CHECK:STDOUT: %addr.loc8_24.1: %ptr.de2 = addr_of %.loc8_24.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.cff = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.cff = var_pattern %x.patt [concrete] @@ -755,11 +983,16 @@ fn F() { // CHECK:STDOUT: %bound_method.loc9: = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1 // CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var // CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.362 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.362 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 -// CHECK:STDOUT: %addr.loc8: %ptr.de2 = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) +// CHECK:STDOUT: %bound_method.loc8_24: = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_24.2: %ptr.de2 = addr_of %.loc8_24.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.362 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3 +// CHECK:STDOUT: %addr.loc8_12: %ptr.de2 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -773,10 +1006,12 @@ fn F() { // CHECK:STDOUT: %C.bar: %C.bar.type = struct_value () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -792,6 +1027,11 @@ fn F() { // 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() { @@ -810,12 +1050,20 @@ fn F() { // CHECK:STDOUT: %.loc9_12.4: ref %C = temporary %.loc9_12.2, %.loc9_12.3 // CHECK:STDOUT: %.loc9_14.1: ref %C = converted %.loc9_12.1, %.loc9_12.4 // CHECK:STDOUT: %.loc9_14.2: %C = bind_value %.loc9_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc9_14.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: %.loc9_22.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc9_22.2: init %C = initialize_from %.loc9_14.2 to %.loc9_22.1 +// CHECK:STDOUT: %addr.loc9_22.1: %ptr.d9e = addr_of %.loc9_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc9_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_22: = bound_method %.loc9_22.1, constants.%T.as.Destroy.impl.Op.21b // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc9_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc9_22: = bound_method %.loc9_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc9_22.2: %ptr.d9e = addr_of %.loc9_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_22: init %empty_tuple.type = call %bound_method.loc9_22(%addr.loc9_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_12: = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc9_12: = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc9_12: %ptr.d9e = addr_of %.loc9_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_12: init %empty_tuple.type = call %bound_method.loc9_12(%addr.loc9_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -826,13 +1074,15 @@ fn F() { // CHECK:STDOUT: %C: type = class_type @C [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %C.val: %C = struct_value () [concrete] // CHECK:STDOUT: %C.bar.type: type = fn_type @C.bar [concrete] // CHECK:STDOUT: %C.bar: %C.bar.type = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.1b3: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%C) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.21b: %T.as.Destroy.impl.Op.type.1b3 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.d9e: type = ptr_type %C [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -847,6 +1097,11 @@ fn F() { // 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: %C.bar.decl: %C.bar.type = fn_decl @C.bar [concrete = constants.%C.bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: @@ -862,16 +1117,24 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %C = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %C = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %C = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_22.1: ref %C = temporary_storage +// CHECK:STDOUT: %.loc8_22.2: init %C = initialize_from %.loc8_14.2 to %.loc8_22.1 +// CHECK:STDOUT: %addr.loc8_22.1: %ptr.d9e = addr_of %.loc8_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1) // CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %C.ref.loc9: type = name_ref C, imports.%C.decl [concrete = constants.%C] // CHECK:STDOUT: %bar.ref: %C.bar.type = name_ref bar, imports.%C.bar.decl [concrete = constants.%C.bar] // CHECK:STDOUT: %C.bar.call: init %empty_tuple.type = call %bar.ref() -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.21b // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.d9e = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc8_22: = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_22.2: %ptr.d9e = addr_of %.loc8_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.21b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_12: %ptr.d9e = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/full_semir.carbon b/toolchain/check/testdata/interop/cpp/function/full_semir.carbon index 6f0b8887f679..a21b94407e64 100644 --- a/toolchain/check/testdata/interop/cpp/function/full_semir.carbon +++ b/toolchain/check/testdata/interop/cpp/function/full_semir.carbon @@ -26,6 +26,7 @@ library "[[@TEST_NAME]]"; import Cpp library "short_param.h"; fn F() { + // TODO: Find a way to test the full C++ thunk AST. Cpp.foo(1 as i16); } @@ -78,11 +79,16 @@ fn F() { // CHECK:STDOUT: %pattern_type.2f8: type = pattern_type %i16 [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.251: type = ptr_type %i16 [concrete] +// CHECK:STDOUT: %pattern_type.54c: type = pattern_type %ptr.251 [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: %int_1.5b8: Core.IntLiteral = int_value 1 [concrete] // CHECK:STDOUT: %As.type.90f: type = generic_interface_type @As [concrete] // CHECK:STDOUT: %As.generic: %As.type.90f = struct_value () [concrete] // CHECK:STDOUT: %As.type.a96: type = facet_type <@As, @As(%i16)> [concrete] // CHECK:STDOUT: %As.Convert.type.be5: type = fn_type @As.Convert, @As(%i16) [concrete] +// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete] // CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.062: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%To) [symbolic] // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.527: %Core.IntLiteral.as.As.impl.Convert.type.062 = struct_value () [symbolic] @@ -95,12 +101,16 @@ fn F() { // CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.489, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] // CHECK:STDOUT: %bound_method: = bound_method %int_1.5b8, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] // CHECK:STDOUT: %int_1.f90: %i16 = int_value 1 [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23c: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%i16) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.507: %T.as.Destroy.impl.Op.type.23c = struct_value () [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.specific_fn: = specific_function %T.as.Destroy.impl.Op.507, @T.as.Destroy.impl.Op(%i16) [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { // CHECK:STDOUT: %Core: = namespace file.%Core.import, [concrete] { // CHECK:STDOUT: .Int = %Core.Int // CHECK:STDOUT: .As = %Core.As +// CHECK:STDOUT: .Destroy = %Core.Destroy // CHECK:STDOUT: import Core//prelude // CHECK:STDOUT: import Core//prelude/... // CHECK:STDOUT: } @@ -120,9 +130,21 @@ fn F() { // CHECK:STDOUT: } // CHECK:STDOUT: %a: %i16 = bind_name a, %a.param // CHECK:STDOUT: } +// CHECK:STDOUT: %foo__carbon_thunk.decl: %foo__carbon_thunk.type = fn_decl @foo__carbon_thunk [concrete = constants.%foo__carbon_thunk] { +// CHECK:STDOUT: %a.patt: %pattern_type.54c = binding_pattern a [concrete] +// CHECK:STDOUT: %a.param_patt: %pattern_type.54c = value_param_pattern %a.patt, call_param0 [concrete] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %a.param: %ptr.251 = value_param call_param0 +// CHECK:STDOUT: %.1: type = splice_block constants.%ptr.251 [concrete = constants.%ptr.251] { +// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16] +// CHECK:STDOUT: %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16] +// CHECK:STDOUT: } +// CHECK:STDOUT: %a: %ptr.251 = bind_name a, %a.param +// CHECK:STDOUT: } // CHECK:STDOUT: %Core.As: %As.type.90f = import_ref Core//prelude/parts/as, As, loaded [concrete = constants.%As.generic] // CHECK:STDOUT: %Core.import_ref.78a: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.062) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.527)] // CHECK:STDOUT: %As.impl_witness_table.eb4 = impl_witness_table (%Core.import_ref.78a), @Core.IntLiteral.as.As.impl [concrete] +// CHECK:STDOUT: %Core.Destroy: type = import_ref Core//prelude/parts/destroy, Destroy, loaded [concrete = constants.%Destroy.type] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: file { @@ -146,18 +168,28 @@ fn F() { // CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16] // CHECK:STDOUT: %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16] // CHECK:STDOUT: %impl.elem0: %.91d = impl_witness_access constants.%As.impl_witness.0ef, element0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.489] -// CHECK:STDOUT: %bound_method.loc7_13.1: = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.bound] +// CHECK:STDOUT: %bound_method.loc8_13.1: = bound_method %int_1, %impl.elem0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.bound] // CHECK:STDOUT: %specific_fn: = specific_function %impl.elem0, @Core.IntLiteral.as.As.impl.Convert(constants.%int_16) [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.specific_fn] -// CHECK:STDOUT: %bound_method.loc7_13.2: = bound_method %int_1, %specific_fn [concrete = constants.%bound_method] -// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc7_13.2(%int_1) [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %.loc7_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %.loc7_13.2: %i16 = converted %int_1, %.loc7_13.1 [concrete = constants.%int_1.f90] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc7_13.2) +// CHECK:STDOUT: %bound_method.loc8_13.2: = bound_method %int_1, %specific_fn [concrete = constants.%bound_method] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc8_13.2(%int_1) [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %.loc8_13.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %.loc8_13.2: %i16 = converted %int_1, %.loc8_13.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %.loc8_19.1: ref %i16 = temporary_storage +// CHECK:STDOUT: %.loc8_19.2: init %i16 = initialize_from %.loc8_13.2 to %.loc8_19.1 [concrete = constants.%int_1.f90] +// CHECK:STDOUT: %addr.loc8_19.1: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_19.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_19.1, constants.%T.as.Destroy.impl.Op.507 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.specific_fn: = specific_function constants.%T.as.Destroy.impl.Op.507, @T.as.Destroy.impl.Op(constants.%i16) [concrete = constants.%T.as.Destroy.impl.Op.specific_fn] +// CHECK:STDOUT: %bound_method.loc8_19: = bound_method %.loc8_19.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc8_19.2: %ptr.251 = addr_of %.loc8_19.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method.loc8_19(%addr.loc8_19.2) // CHECK:STDOUT: return // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: fn @foo(%a.param: %i16); // CHECK:STDOUT: +// CHECK:STDOUT: fn @foo__carbon_thunk(%a.param: %ptr.251); +// CHECK:STDOUT: // CHECK:STDOUT: --- import_int_param.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/testdata/interop/cpp/function/struct.carbon b/toolchain/check/testdata/interop/cpp/function/struct.carbon index 6221c89415bb..930651c620e2 100644 --- a/toolchain/check/testdata/interop/cpp/function/struct.carbon +++ b/toolchain/check/testdata/interop/cpp/function/struct.carbon @@ -2,7 +2,7 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon // // AUTOUPDATE // TIP: To test this file alone, run: @@ -20,17 +20,29 @@ struct S; auto foo(S) -> void; -// --- fail_todo_import_decl_value_param_type.carbon +// --- fail_import_decl_value_param_type.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:4:6: error: argument type 'S' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo(S) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:2:8: note: forward declaration of 'S' [CppInteropParseNote] +// CHECK:STDERR: 2 | struct S; +// CHECK:STDERR: | ^ import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+8]]:11: error: invalid use of incomplete type `Cpp.S` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+12]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({} as Cpp.S); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+8]]:11: error: invalid use of incomplete type `Cpp.S` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo({} as Cpp.S); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-10]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: struct S; // CHECK:STDERR: ^ @@ -38,26 +50,38 @@ fn F() { Cpp.foo({} as Cpp.S); } -// --- fail_todo_import_decl_value_param_type_previously_imported.carbon +// --- fail_import_decl_value_param_type_previously_imported.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:4:6: error: argument type 'S' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo(S) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:2:8: note: forward declaration of 'S' [CppInteropParseNote] +// CHECK:STDERR: 2 | struct S; +// CHECK:STDERR: | ^ import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+12]]:10: error: binding pattern has incomplete type `S` in name binding declaration [IncompleteTypeInBindingDecl] + let s: Cpp.S; + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+16]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(s); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-5]]:10: error: binding pattern has incomplete type `S` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let s: Cpp.S; // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-11]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: struct S; // CHECK:STDERR: ^ // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-13]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let s: Cpp.S; // CHECK:STDERR: ^ // CHECK:STDERR: - let s: Cpp.S; Cpp.foo(s); } @@ -72,26 +96,50 @@ struct S; auto foo1(S) -> void; auto foo2(S) -> void; -// --- fail_todo_import_double_decl_value_param_type.carbon +// --- fail_import_double_decl_value_param_type.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./double_decl_value_param_type.h:4:6: error: argument type 'S' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo1(S) -> void; +// CHECK:STDERR: | ^~~~ +// CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./double_decl_value_param_type.h:2:8: note: forward declaration of 'S' [CppInteropParseNote] +// CHECK:STDERR: 2 | struct S; +// CHECK:STDERR: | ^ import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.S` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+12]]:3: note: in `Cpp` name lookup for `foo1` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo1({} as Cpp.S); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-7]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:5:6: error: argument type 'S' is incomplete [CppInteropParseError] + // CHECK:STDERR: 5 | auto foo2(S) -> void; + // CHECK:STDERR: | ^~~~ + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-11]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:8: note: forward declaration of 'S' [CppInteropParseNote] + // CHECK:STDERR: 2 | struct S; + // CHECK:STDERR: | ^ + Cpp.foo1({} as Cpp.S); + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+20]]:3: note: in `Cpp` name lookup for `foo2` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo2({} as Cpp.S); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-5]]:12: error: invalid use of incomplete type `Cpp.S` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo1({} as Cpp.S); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-23]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./double_decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: struct S; // CHECK:STDERR: ^ // CHECK:STDERR: - Cpp.foo1({} as Cpp.S); - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.S` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.S` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo2({} as Cpp.S); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-15]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-31]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./double_decl_value_param_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: struct S; // CHECK:STDERR: ^ @@ -121,6 +169,46 @@ fn F() { //@dump-sem-ir-end } +// ============================================================================ +// Non copyable struct as parameter type +// ============================================================================ + +// --- non_copyable_param_type.h + +struct S { + S(const S&) = delete; +}; + +auto foo(S) -> void; + +// --- fail_import_non_copyable_param_type.carbon + +library "[[@TEST_NAME]]"; + +// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+12]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./non_copyable_param_type.h:6:6: error: call to deleted constructor of 'S' [CppInteropParseError] +// CHECK:STDERR: 6 | auto foo(S) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./non_copyable_param_type.h:3:3: note: 'S' has been explicitly marked deleted here [CppInteropParseNote] +// CHECK:STDERR: 3 | S(const S&) = delete; +// CHECK:STDERR: | ^ +// CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./non_copyable_param_type.h:6:11: note: passing argument to parameter here [CppInteropParseNote] +// CHECK:STDERR: 6 | auto foo(S) -> void; +// CHECK:STDERR: | ^ +import Cpp library "non_copyable_param_type.h"; + +fn F() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_import_non_copyable_param_type.carbon:[[@LINE+4]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({} as Cpp.S); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + Cpp.foo({} as Cpp.S); + //@dump-sem-ir-end +} + // ============================================================================ // Defined struct with a single data member as parameter type // ============================================================================ @@ -143,7 +231,10 @@ import Cpp library "definition_single_data_member_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:11: error: name `Core.As` implicitly referenced here, but not found [CoreNameNotFound] + // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+7]]:11: error: cannot convert expression of type `{}` to `Cpp.S` with `as` [ConversionFailure] + // CHECK:STDERR: Cpp.foo({} as Cpp.S); + // CHECK:STDERR: ^~~~~~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:11: note: type `{}` does not implement interface `Core.As(Cpp.S)` [MissingImplInMemberAccessNote] // CHECK:STDERR: Cpp.foo({} as Cpp.S); // CHECK:STDERR: ^~~~~~~~~~~ // CHECK:STDERR: @@ -175,7 +266,10 @@ import Cpp library "definition_multiple_data_members_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:11: error: name `Core.As` implicitly referenced here, but not found [CoreNameNotFound] + // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+7]]:11: error: cannot convert expression of type `{}` to `Cpp.S` with `as` [ConversionFailure] + // CHECK:STDERR: Cpp.foo({} as Cpp.S); + // CHECK:STDERR: ^~~~~~~~~~~ + // CHECK:STDERR: fail_todo_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:11: note: type `{}` does not implement interface `Core.As(Cpp.S)` [MissingImplInMemberAccessNote] // CHECK:STDERR: Cpp.foo({} as Cpp.S); // CHECK:STDERR: ^~~~~~~~~~~ // CHECK:STDERR: @@ -347,21 +441,21 @@ struct S; auto foo() -> S; -// --- fail_todo_import_decl_value_return_type.carbon +// --- fail_import_decl_value_return_type.carbon library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.S` [IncompleteTypeInFunctionReturnType] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.S` [IncompleteTypeInFunctionReturnType] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_return_type.h:2:8: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: struct S; // CHECK:STDERR: ^ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); } @@ -439,6 +533,70 @@ fn F() { // CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [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: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %S.val: %S = struct_value () [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .foo = %foo.decl +// CHECK:STDOUT: .S = %S.decl +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %S.decl: type = class_decl @S [concrete = constants.%S] {} {} +// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %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.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] +// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc8_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] +// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 +// CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4 +// CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1 +// CHECK:STDOUT: %.loc8_22.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_22.2: init %S = initialize_from %.loc8_14.2 to %.loc8_22.1 +// CHECK:STDOUT: %addr.loc8_22.1: %ptr.5c7 = addr_of %.loc8_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_22: = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_22.2: %ptr.5c7 = addr_of %.loc8_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_12: %ptr.5c7 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_import_non_copyable_param_type.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %S: type = class_type @S [concrete] +// CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] +// CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] // CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] @@ -462,21 +620,21 @@ fn F() { // 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: %Cpp.ref.loc24_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc8_12.1: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %Cpp.ref.loc8_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %.loc24_12.1: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc24_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] -// CHECK:STDOUT: %.loc8_12.2: ref %S = temporary_storage -// CHECK:STDOUT: %.loc8_12.3: init %S = class_init (), %.loc8_12.2 [concrete = constants.%S.val] -// CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 -// CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4 -// CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: %.loc24_12.2: ref %S = temporary_storage +// CHECK:STDOUT: %.loc24_12.3: init %S = class_init (), %.loc24_12.2 [concrete = constants.%S.val] +// CHECK:STDOUT: %.loc24_12.4: ref %S = temporary %.loc24_12.2, %.loc24_12.3 +// CHECK:STDOUT: %.loc24_14.1: ref %S = converted %.loc24_12.1, %.loc24_12.4 +// CHECK:STDOUT: %.loc24_14.2: %S = bind_value %.loc24_14.1 +// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc24_14.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc24_12.2, constants.%T.as.Destroy.impl.Op.ab5 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %bound_method: = bound_method %.loc24_12.2, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %.loc24_12.2 // CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) // CHECK:STDOUT: // CHECK:STDOUT: } @@ -488,7 +646,12 @@ fn F() { // CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [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: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -503,17 +666,30 @@ fn F() { // 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.loc12_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc15_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc12_12: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %Cpp.ref.loc12_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %.loc15_12: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc15_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] -// CHECK:STDOUT: %.loc12_14: %S = converted %.loc12_12, [concrete = ] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc15_14: %S = converted %.loc15_12, [concrete = ] +// CHECK:STDOUT: %.loc15_22.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc15_22.2: init %S = initialize_from to %.loc15_22.1 [concrete = ] +// CHECK:STDOUT: %addr.loc15_22.1: %ptr.5c7 = addr_of %.loc15_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc15_22.2: %ptr.5c7 = addr_of %.loc15_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -524,7 +700,12 @@ fn F() { // CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [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: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -539,17 +720,30 @@ fn F() { // 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.loc12_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc15_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc12_12: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %Cpp.ref.loc12_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %.loc15_12: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc15_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %S.ref: type = name_ref S, imports.%S.decl [concrete = constants.%S] -// CHECK:STDOUT: %.loc12_14: %S = converted %.loc12_12, [concrete = ] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc15_14: %S = converted %.loc15_12, [concrete = ] +// CHECK:STDOUT: %.loc15_22.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc15_22.2: init %S = initialize_from to %.loc15_22.1 [concrete = ] +// CHECK:STDOUT: %addr.loc15_22.1: %ptr.5c7 = addr_of %.loc15_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc15_22.2: %ptr.5c7 = addr_of %.loc15_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -561,11 +755,13 @@ fn F() { // CHECK:STDOUT: %pattern_type.cd8: type = pattern_type %S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.edf: type = ptr_type %S [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.2b5: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.9b3: %T.as.Destroy.impl.Op.type.2b5 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.edf: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -584,6 +780,11 @@ fn F() { // 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() { @@ -599,7 +800,10 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_24.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_24.2: init %S = initialize_from %.loc8_14.2 to %.loc8_24.1 +// CHECK:STDOUT: %addr.loc8_24.1: %ptr.edf = addr_of %.loc8_24.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.cd8 = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.cd8 = var_pattern %x.patt [concrete] @@ -616,11 +820,16 @@ fn F() { // CHECK:STDOUT: %bound_method.loc10: = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1 // CHECK:STDOUT: %addr.loc10: %ptr.edf = addr_of %x.var // CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.9b3 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.9b3 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 -// CHECK:STDOUT: %addr.loc8: %ptr.edf = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) +// CHECK:STDOUT: %bound_method.loc8_24: = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_24.2: %ptr.edf = addr_of %.loc8_24.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.9b3 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3 +// CHECK:STDOUT: %addr.loc8_12: %ptr.edf = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -631,11 +840,13 @@ fn F() { // CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.887: type = ptr_type %S [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.17f: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.463: %T.as.Destroy.impl.Op.type.17f = struct_value () [concrete] -// CHECK:STDOUT: %ptr.887: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -658,6 +869,11 @@ fn F() { // 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() { @@ -675,12 +891,20 @@ fn F() { // CHECK:STDOUT: %.loc8_15.4: ref %S = temporary %.loc8_15.2, %.loc8_15.3 // CHECK:STDOUT: %.loc8_17.1: ref %S = converted %.loc8_15.1, %.loc8_15.4 // CHECK:STDOUT: %.loc8_17.2: %S = bind_value %.loc8_17.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_17.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.463 +// CHECK:STDOUT: %.loc8_31.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_31.2: init %S = initialize_from %.loc8_17.2 to %.loc8_31.1 +// CHECK:STDOUT: %addr.loc8_31.1: %ptr.887 = addr_of %.loc8_31.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_31.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_31: = bound_method %.loc8_31.1, constants.%T.as.Destroy.impl.Op.463 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.887 = addr_of %.loc8_15.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc8_31: = bound_method %.loc8_31.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_31.2: %ptr.887 = addr_of %.loc8_31.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_31: init %empty_tuple.type = call %bound_method.loc8_31(%addr.loc8_31.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_15: = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.463 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_15: = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_15: %ptr.887 = addr_of %.loc8_15.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_15: init %empty_tuple.type = call %bound_method.loc8_15(%addr.loc8_15) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -692,6 +916,9 @@ fn F() { // CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.149: type = ptr_type %S [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete] @@ -700,7 +927,6 @@ fn F() { // CHECK:STDOUT: %ptr.820: type = ptr_type %O [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.23f: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.952: %T.as.Destroy.impl.Op.type.23f = struct_value () [concrete] -// CHECK:STDOUT: %ptr.149: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -716,6 +942,11 @@ fn F() { // 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() { @@ -731,7 +962,10 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_24.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_24.2: init %S = initialize_from %.loc8_14.2 to %.loc8_24.1 +// CHECK:STDOUT: %addr.loc8_24.1: %ptr.149 = addr_of %.loc8_24.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.cff = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.cff = var_pattern %x.patt [concrete] @@ -747,11 +981,16 @@ fn F() { // CHECK:STDOUT: %bound_method.loc9: = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1 // CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var // CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.952 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.952 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 -// CHECK:STDOUT: %addr.loc8: %ptr.149 = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) +// CHECK:STDOUT: %bound_method.loc8_24: = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_24.2: %ptr.149 = addr_of %.loc8_24.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.952 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3 +// CHECK:STDOUT: %addr.loc8_12: %ptr.149 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -765,10 +1004,12 @@ fn F() { // CHECK:STDOUT: %S.bar: %S.bar.type = struct_value () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [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: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -784,6 +1025,11 @@ fn F() { // 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() { @@ -802,12 +1048,20 @@ fn F() { // CHECK:STDOUT: %.loc9_12.4: ref %S = temporary %.loc9_12.2, %.loc9_12.3 // CHECK:STDOUT: %.loc9_14.1: ref %S = converted %.loc9_12.1, %.loc9_12.4 // CHECK:STDOUT: %.loc9_14.2: %S = bind_value %.loc9_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc9_14.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: %.loc9_22.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc9_22.2: init %S = initialize_from %.loc9_14.2 to %.loc9_22.1 +// CHECK:STDOUT: %addr.loc9_22.1: %ptr.5c7 = addr_of %.loc9_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc9_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_22: = bound_method %.loc9_22.1, constants.%T.as.Destroy.impl.Op.ab5 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %.loc9_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc9_22: = bound_method %.loc9_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc9_22.2: %ptr.5c7 = addr_of %.loc9_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_22: init %empty_tuple.type = call %bound_method.loc9_22(%addr.loc9_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_12: = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc9_12: = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc9_12: %ptr.5c7 = addr_of %.loc9_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_12: init %empty_tuple.type = call %bound_method.loc9_12(%addr.loc9_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -818,13 +1072,15 @@ fn F() { // CHECK:STDOUT: %S: type = class_type @S [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %S.val: %S = struct_value () [concrete] // CHECK:STDOUT: %S.bar.type: type = fn_type @S.bar [concrete] // CHECK:STDOUT: %S.bar: %S.bar.type = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.642: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%S) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.ab5: %T.as.Destroy.impl.Op.type.642 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.5c7: type = ptr_type %S [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -839,6 +1095,11 @@ fn F() { // 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: %S.bar.decl: %S.bar.type = fn_decl @S.bar [concrete = constants.%S.bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: @@ -854,16 +1115,24 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %S = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %S = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %S = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_22.1: ref %S = temporary_storage +// CHECK:STDOUT: %.loc8_22.2: init %S = initialize_from %.loc8_14.2 to %.loc8_22.1 +// CHECK:STDOUT: %addr.loc8_22.1: %ptr.5c7 = addr_of %.loc8_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1) // CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %S.ref.loc9: type = name_ref S, imports.%S.decl [concrete = constants.%S] // CHECK:STDOUT: %bar.ref: %S.bar.type = name_ref bar, imports.%S.bar.decl [concrete = constants.%S.bar] // CHECK:STDOUT: %S.bar.call: init %empty_tuple.type = call %bar.ref() -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.ab5 // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.5c7 = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc8_22: = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_22.2: %ptr.5c7 = addr_of %.loc8_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.ab5 +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_12: %ptr.5c7 = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/function/union.carbon b/toolchain/check/testdata/interop/cpp/function/union.carbon index 0e2c472bac60..fc90e7d02b6d 100644 --- a/toolchain/check/testdata/interop/cpp/function/union.carbon +++ b/toolchain/check/testdata/interop/cpp/function/union.carbon @@ -2,7 +2,7 @@ // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/convert.carbon // // AUTOUPDATE // TIP: To test this file alone, run: @@ -20,18 +20,30 @@ union U; auto foo(U) -> void; -// --- fail_todo_import_decl_value_param_type.carbon +// --- fail_import_decl_value_param_type.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:4:6: error: argument type 'U' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo(U) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:2:7: note: forward declaration of 'U' [CppInteropParseNote] +// CHECK:STDERR: 2 | union U; +// CHECK:STDERR: | ^ import Cpp library "decl_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE+8]]:11: error: invalid use of incomplete type `Cpp.U` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+12]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo({} as Cpp.U); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE+8]]:11: error: invalid use of incomplete type `Cpp.U` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo({} as Cpp.U); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type.carbon:[[@LINE-7]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_param_type.carbon:[[@LINE-11]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: union U; // CHECK:STDERR: ^ @@ -40,26 +52,38 @@ fn F() { //@dump-sem-ir-end } -// --- fail_todo_import_decl_value_param_type_previously_imported.carbon +// --- fail_import_decl_value_param_type_previously_imported.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:4:6: error: argument type 'U' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo(U) -> void; +// CHECK:STDERR: | ^~~ +// CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./decl_value_param_type.h:2:7: note: forward declaration of 'U' [CppInteropParseNote] +// CHECK:STDERR: 2 | union U; +// CHECK:STDERR: | ^ import Cpp library "decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+12]]:10: error: binding pattern has incomplete type `U` in name binding declaration [IncompleteTypeInBindingDecl] + let u: Cpp.U; + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE+16]]:3: note: in `Cpp` name lookup for `foo` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo(u); + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-5]]:10: error: binding pattern has incomplete type `U` in name binding declaration [IncompleteTypeInBindingDecl] // CHECK:STDERR: let u: Cpp.U; // CHECK:STDERR: ^~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-11]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: union U; // CHECK:STDERR: ^ // CHECK:STDERR: - // CHECK:STDERR: fail_todo_import_decl_value_param_type_previously_imported.carbon:[[@LINE+4]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] + // CHECK:STDERR: fail_import_decl_value_param_type_previously_imported.carbon:[[@LINE-13]]:15: error: expected `=`; `let` declaration must have an initializer [ExpectedInitializerAfterLet] // CHECK:STDERR: let u: Cpp.U; // CHECK:STDERR: ^ // CHECK:STDERR: - let u: Cpp.U; Cpp.foo(u); } @@ -74,26 +98,50 @@ union U; auto foo1(U) -> void; auto foo2(U) -> void; -// --- fail_todo_import_double_decl_value_param_type.carbon +// --- fail_import_double_decl_value_param_type.carbon library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+8]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./double_decl_value_param_type.h:4:6: error: argument type 'U' is incomplete [CppInteropParseError] +// CHECK:STDERR: 4 | auto foo1(U) -> void; +// CHECK:STDERR: | ^~~~ +// CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+4]]:10: in file included here [InCppInclude] +// CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: forward declaration of 'U' [CppInteropParseNote] +// CHECK:STDERR: 2 | union U; +// CHECK:STDERR: | ^ import Cpp library "double_decl_value_param_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.U` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+12]]:3: note: in `Cpp` name lookup for `foo1` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo1({} as Cpp.U); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-7]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:5:6: error: argument type 'U' is incomplete [CppInteropParseError] + // CHECK:STDERR: 5 | auto foo2(U) -> void; + // CHECK:STDERR: | ^~~~ + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-11]]:10: in file included here [InCppInclude] + // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: forward declaration of 'U' [CppInteropParseNote] + // CHECK:STDERR: 2 | union U; + // CHECK:STDERR: | ^ + Cpp.foo1({} as Cpp.U); + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+20]]:3: note: in `Cpp` name lookup for `foo2` [InCppNameLookup] + // CHECK:STDERR: Cpp.foo2({} as Cpp.U); + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-5]]:12: error: invalid use of incomplete type `Cpp.U` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo1({} as Cpp.U); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-23]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: union U; // CHECK:STDERR: ^ // CHECK:STDERR: - Cpp.foo1({} as Cpp.U); - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.U` [IncompleteTypeInConversion] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE+8]]:12: error: invalid use of incomplete type `Cpp.U` [IncompleteTypeInConversion] // CHECK:STDERR: Cpp.foo2({} as Cpp.U); // CHECK:STDERR: ^~~~~~~~~~~ - // CHECK:STDERR: fail_todo_import_double_decl_value_param_type.carbon:[[@LINE-15]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_double_decl_value_param_type.carbon:[[@LINE-31]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./double_decl_value_param_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: union U; // CHECK:STDERR: ^ @@ -145,16 +193,14 @@ import Cpp library "definition_single_data_member_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon:[[@LINE+9]]:11: error: name `Core.ImplicitAs` implicitly referenced here, but not found [CoreNameNotFound] - // CHECK:STDERR: Cpp.foo({}) as Cpp.U; - // CHECK:STDERR: ^~ - // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon: note: initializing function parameter [InCallToFunctionParam] + // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon:[[@LINE+7]]:11: error: cannot convert expression of type `{}` to `Cpp.U` with `as` [ConversionFailure] + // CHECK:STDERR: Cpp.foo({} as Cpp.U); + // CHECK:STDERR: ^~~~~~~~~~~ + // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:11: note: type `{}` does not implement interface `Core.As(Cpp.U)` [MissingImplInMemberAccessNote] + // CHECK:STDERR: Cpp.foo({} as Cpp.U); + // CHECK:STDERR: ^~~~~~~~~~~ // CHECK:STDERR: - // CHECK:STDERR: fail_import_definition_single_data_member_value_param_type.carbon:[[@LINE+4]]:3: error: name `Core.As` implicitly referenced here, but not found [CoreNameNotFound] - // CHECK:STDERR: Cpp.foo({}) as Cpp.U; - // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~ - // CHECK:STDERR: - Cpp.foo({}) as Cpp.U; + Cpp.foo({} as Cpp.U); //@dump-sem-ir-end } @@ -182,7 +228,10 @@ import Cpp library "definition_multiple_data_members_value_param_type.h"; fn F() { //@dump-sem-ir-begin - // CHECK:STDERR: fail_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:11: error: name `Core.As` implicitly referenced here, but not found [CoreNameNotFound] + // CHECK:STDERR: fail_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+7]]:11: error: cannot convert expression of type `{}` to `Cpp.U` with `as` [ConversionFailure] + // CHECK:STDERR: Cpp.foo({} as Cpp.U); + // CHECK:STDERR: ^~~~~~~~~~~ + // CHECK:STDERR: fail_import_definition_multiple_data_members_value_param_type.carbon:[[@LINE+4]]:11: note: type `{}` does not implement interface `Core.As(Cpp.U)` [MissingImplInMemberAccessNote] // CHECK:STDERR: Cpp.foo({} as Cpp.U); // CHECK:STDERR: ^~~~~~~~~~~ // CHECK:STDERR: @@ -355,21 +404,21 @@ union U; auto foo() -> U; -// --- fail_todo_import_decl_value_return_type.carbon +// --- fail_import_decl_value_return_type.carbon library "[[@TEST_NAME]]"; import Cpp library "decl_value_return_type.h"; fn F() { - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.U` [IncompleteTypeInFunctionReturnType] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE+9]]:3: error: function returns incomplete type `Cpp.U` [IncompleteTypeInFunctionReturnType] // CHECK:STDERR: Cpp.foo(); // CHECK:STDERR: ^~~~~~~~~ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon:[[@LINE-6]]:10: in file included here [InCppInclude] // CHECK:STDERR: ./decl_value_return_type.h:2:7: note: class was forward declared here [ClassForwardDeclaredHere] // CHECK:STDERR: union U; // CHECK:STDERR: ^ - // CHECK:STDERR: fail_todo_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] + // CHECK:STDERR: fail_import_decl_value_return_type.carbon: note: return type declared here [IncompleteReturnTypeHere] // CHECK:STDERR: Cpp.foo(); } @@ -440,7 +489,7 @@ fn F() { //@dump-sem-ir-end } -// CHECK:STDOUT: --- fail_todo_import_decl_value_param_type.carbon +// CHECK:STDOUT: --- fail_import_decl_value_param_type.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { // CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] @@ -466,10 +515,10 @@ fn F() { // CHECK:STDOUT: // CHECK:STDOUT: fn @F() { // CHECK:STDOUT: !entry: -// CHECK:STDOUT: %Cpp.ref.loc16_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc28_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc16: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %Cpp.ref.loc16_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %.loc28: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc28_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %U.ref: type = name_ref U, imports.%U.decl [concrete = constants.%U] // CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() // CHECK:STDOUT: @@ -482,11 +531,13 @@ fn F() { // CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %U.val: %U = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.0b7: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.2fa: %T.as.Destroy.impl.Op.type.0b7 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -501,6 +552,11 @@ fn F() { // 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() { @@ -515,12 +571,20 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %U = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %U = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %U = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.2fa +// CHECK:STDOUT: %.loc8_22.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc8_22.2: init %U = initialize_from %.loc8_14.2 to %.loc8_22.1 +// CHECK:STDOUT: %addr.loc8_22.1: %ptr.86f = addr_of %.loc8_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.2fa // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.86f = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc8_22: = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_22.2: %ptr.86f = addr_of %.loc8_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.2fa +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_12: %ptr.86f = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -531,10 +595,12 @@ fn F() { // CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [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: %empty_struct_type: type = struct_type {} [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.a63: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%empty_tuple.type) [concrete] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.ea3: %T.as.Destroy.impl.Op.type.a63 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.843: type = ptr_type %empty_tuple.type [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.0b7: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.2fa: %T.as.Destroy.impl.Op.type.0b7 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -549,25 +615,30 @@ fn F() { // 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.loc17_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc15_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc17_12.1: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %.loc17_12.2: %U = converted %.loc17_12.1, [concrete = ] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() -// CHECK:STDOUT: %Cpp.ref.loc17_18: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %.loc15_12: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc15_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %U.ref: type = name_ref U, imports.%U.decl [concrete = constants.%U] -// CHECK:STDOUT: %.loc17_13.1: ref %empty_tuple.type = temporary_storage -// CHECK:STDOUT: %.loc17_13.2: ref %empty_tuple.type = temporary %.loc17_13.1, %foo.call -// CHECK:STDOUT: %.loc17_15: %U = converted %foo.call, [concrete = ] -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc17_13.1, constants.%T.as.Destroy.impl.Op.ea3 +// CHECK:STDOUT: %.loc15_14: %U = converted %.loc15_12, [concrete = ] +// CHECK:STDOUT: %.loc15_22.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc15_22.2: init %U = initialize_from to %.loc15_22.1 [concrete = ] +// CHECK:STDOUT: %addr.loc15_22.1: %ptr.86f = addr_of %.loc15_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.2fa // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc17_13.1, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.843 = addr_of %.loc17_13.1 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method: = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc15_22.2: %ptr.86f = addr_of %.loc15_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -578,7 +649,12 @@ fn F() { // CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [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: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.type.0b7: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] +// CHECK:STDOUT: %T.as.Destroy.impl.Op.2fa: %T.as.Destroy.impl.Op.type.0b7 = struct_value () [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -593,17 +669,30 @@ fn F() { // 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.loc12_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %Cpp.ref.loc15_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %foo.ref: %foo.type = name_ref foo, imports.%foo.decl [concrete = constants.%foo] -// CHECK:STDOUT: %.loc12_12: %empty_struct_type = struct_literal () -// CHECK:STDOUT: %Cpp.ref.loc12_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %.loc15_12: %empty_struct_type = struct_literal () +// CHECK:STDOUT: %Cpp.ref.loc15_17: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %U.ref: type = name_ref U, imports.%U.decl [concrete = constants.%U] -// CHECK:STDOUT: %.loc12_14: %U = converted %.loc12_12, [concrete = ] -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref() +// CHECK:STDOUT: %.loc15_14: %U = converted %.loc15_12, [concrete = ] +// CHECK:STDOUT: %.loc15_22.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc15_22.2: init %U = initialize_from to %.loc15_22.1 [concrete = ] +// CHECK:STDOUT: %addr.loc15_22.1: %ptr.86f = addr_of %.loc15_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc15_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc15_22.1, constants.%T.as.Destroy.impl.Op.2fa +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method: = bound_method %.loc15_22.1, %T.as.Destroy.impl.Op.specific_fn +// CHECK:STDOUT: %addr.loc15_22.2: %ptr.86f = addr_of %.loc15_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr.loc15_22.2) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -615,11 +704,13 @@ fn F() { // CHECK:STDOUT: %pattern_type.eb9: type = pattern_type %U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.87e: type = ptr_type %U [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %U.val: %U = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.2e1: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.d5d: %T.as.Destroy.impl.Op.type.2e1 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.87e: type = ptr_type %U [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -638,6 +729,11 @@ fn F() { // 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() { @@ -653,7 +749,10 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %U = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %U = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %U = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_24.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc8_24.2: init %U = initialize_from %.loc8_14.2 to %.loc8_24.1 +// CHECK:STDOUT: %addr.loc8_24.1: %ptr.87e = addr_of %.loc8_24.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.eb9 = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.eb9 = var_pattern %x.patt [concrete] @@ -670,11 +769,16 @@ fn F() { // CHECK:STDOUT: %bound_method.loc10: = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1 // CHECK:STDOUT: %addr.loc10: %ptr.87e = addr_of %x.var // CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc10: init %empty_tuple.type = call %bound_method.loc10(%addr.loc10) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.d5d +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.d5d // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 -// CHECK:STDOUT: %addr.loc8: %ptr.87e = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) +// CHECK:STDOUT: %bound_method.loc8_24: = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_24.2: %ptr.87e = addr_of %.loc8_24.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.d5d +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3 +// CHECK:STDOUT: %addr.loc8_12: %ptr.87e = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -685,11 +789,13 @@ fn F() { // CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.8c1: type = ptr_type %U [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %U.val: %U = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.ee1: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.28c: %T.as.Destroy.impl.Op.type.ee1 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.8c1: type = ptr_type %U [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -712,6 +818,11 @@ fn F() { // 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() { @@ -729,12 +840,20 @@ fn F() { // CHECK:STDOUT: %.loc8_15.4: ref %U = temporary %.loc8_15.2, %.loc8_15.3 // CHECK:STDOUT: %.loc8_17.1: ref %U = converted %.loc8_15.1, %.loc8_15.4 // CHECK:STDOUT: %.loc8_17.2: %U = bind_value %.loc8_17.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_17.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.28c +// CHECK:STDOUT: %.loc8_31.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc8_31.2: init %U = initialize_from %.loc8_17.2 to %.loc8_31.1 +// CHECK:STDOUT: %addr.loc8_31.1: %ptr.8c1 = addr_of %.loc8_31.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_31.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_31: = bound_method %.loc8_31.1, constants.%T.as.Destroy.impl.Op.28c // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.8c1 = addr_of %.loc8_15.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc8_31: = bound_method %.loc8_31.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_31.2: %ptr.8c1 = addr_of %.loc8_31.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_31: init %empty_tuple.type = call %bound_method.loc8_31(%addr.loc8_31.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_15: = bound_method %.loc8_15.2, constants.%T.as.Destroy.impl.Op.28c +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_15: = bound_method %.loc8_15.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_15: %ptr.8c1 = addr_of %.loc8_15.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_15: init %empty_tuple.type = call %bound_method.loc8_15(%addr.loc8_15) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -746,6 +865,9 @@ fn F() { // CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.a6c: type = ptr_type %U [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %U.val: %U = struct_value () [concrete] // CHECK:STDOUT: %pattern_type.cff: type = pattern_type %O [concrete] @@ -754,7 +876,6 @@ fn F() { // CHECK:STDOUT: %ptr.820: type = ptr_type %O [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.8f9: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.f3b: %T.as.Destroy.impl.Op.type.8f9 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.a6c: type = ptr_type %U [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -770,6 +891,11 @@ fn F() { // 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() { @@ -785,7 +911,10 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %U = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %U = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %U = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_24.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc8_24.2: init %U = initialize_from %.loc8_14.2 to %.loc8_24.1 +// CHECK:STDOUT: %addr.loc8_24.1: %ptr.a6c = addr_of %.loc8_24.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_24.1) // CHECK:STDOUT: name_binding_decl { // CHECK:STDOUT: %x.patt: %pattern_type.cff = binding_pattern x [concrete] // CHECK:STDOUT: %x.var_patt: %pattern_type.cff = var_pattern %x.patt [concrete] @@ -801,11 +930,16 @@ fn F() { // CHECK:STDOUT: %bound_method.loc9: = bound_method %x.var, %T.as.Destroy.impl.Op.specific_fn.1 // CHECK:STDOUT: %addr.loc9: %ptr.820 = addr_of %x.var // CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9: init %empty_tuple.type = call %bound_method.loc9(%addr.loc9) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.f3b +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_24: = bound_method %.loc8_24.1, constants.%T.as.Destroy.impl.Op.f3b // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method.loc8: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 -// CHECK:STDOUT: %addr.loc8: %ptr.a6c = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8: init %empty_tuple.type = call %bound_method.loc8(%addr.loc8) +// CHECK:STDOUT: %bound_method.loc8_24: = bound_method %.loc8_24.1, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_24.2: %ptr.a6c = addr_of %.loc8_24.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_24: init %empty_tuple.type = call %bound_method.loc8_24(%addr.loc8_24.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.f3b +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.3 +// CHECK:STDOUT: %addr.loc8_12: %ptr.a6c = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -819,10 +953,12 @@ fn F() { // CHECK:STDOUT: %U.bar: %U.bar.type = struct_value () [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [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: %U.val: %U = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.0b7: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.2fa: %T.as.Destroy.impl.Op.type.0b7 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -838,6 +974,11 @@ fn F() { // 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() { @@ -856,12 +997,20 @@ fn F() { // CHECK:STDOUT: %.loc9_12.4: ref %U = temporary %.loc9_12.2, %.loc9_12.3 // CHECK:STDOUT: %.loc9_14.1: ref %U = converted %.loc9_12.1, %.loc9_12.4 // CHECK:STDOUT: %.loc9_14.2: %U = bind_value %.loc9_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc9_14.2) -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.2fa +// CHECK:STDOUT: %.loc9_22.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc9_22.2: init %U = initialize_from %.loc9_14.2 to %.loc9_22.1 +// CHECK:STDOUT: %addr.loc9_22.1: %ptr.86f = addr_of %.loc9_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc9_22.1) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_22: = bound_method %.loc9_22.1, constants.%T.as.Destroy.impl.Op.2fa // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.86f = addr_of %.loc9_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc9_22: = bound_method %.loc9_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc9_22.2: %ptr.86f = addr_of %.loc9_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_22: init %empty_tuple.type = call %bound_method.loc9_22(%addr.loc9_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc9_12: = bound_method %.loc9_12.2, constants.%T.as.Destroy.impl.Op.2fa +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc9_12: = bound_method %.loc9_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc9_12: %ptr.86f = addr_of %.loc9_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc9_12: init %empty_tuple.type = call %bound_method.loc9_12(%addr.loc9_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: @@ -872,13 +1021,15 @@ fn F() { // CHECK:STDOUT: %U: type = class_type @U [concrete] // CHECK:STDOUT: %foo.type: type = fn_type @foo [concrete] // CHECK:STDOUT: %foo: %foo.type = struct_value () [concrete] +// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [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: %empty_struct_type: type = struct_type {} [concrete] // CHECK:STDOUT: %U.val: %U = struct_value () [concrete] // CHECK:STDOUT: %U.bar.type: type = fn_type @U.bar [concrete] // CHECK:STDOUT: %U.bar: %U.bar.type = struct_value () [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.type.0b7: type = fn_type @T.as.Destroy.impl.Op, @T.as.Destroy.impl(%U) [concrete] // CHECK:STDOUT: %T.as.Destroy.impl.Op.2fa: %T.as.Destroy.impl.Op.type.0b7 = struct_value () [concrete] -// CHECK:STDOUT: %ptr.86f: type = ptr_type %U [concrete] // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: imports { @@ -893,6 +1044,11 @@ fn F() { // 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: %U.bar.decl: %U.bar.type = fn_decl @U.bar [concrete = constants.%U.bar] {} {} // CHECK:STDOUT: } // CHECK:STDOUT: @@ -908,16 +1064,24 @@ fn F() { // CHECK:STDOUT: %.loc8_12.4: ref %U = temporary %.loc8_12.2, %.loc8_12.3 // CHECK:STDOUT: %.loc8_14.1: ref %U = converted %.loc8_12.1, %.loc8_12.4 // CHECK:STDOUT: %.loc8_14.2: %U = bind_value %.loc8_14.1 -// CHECK:STDOUT: %foo.call: init %empty_tuple.type = call %foo.ref(%.loc8_14.2) +// CHECK:STDOUT: %.loc8_22.1: ref %U = temporary_storage +// CHECK:STDOUT: %.loc8_22.2: init %U = initialize_from %.loc8_14.2 to %.loc8_22.1 +// CHECK:STDOUT: %addr.loc8_22.1: %ptr.86f = addr_of %.loc8_22.1 +// CHECK:STDOUT: %foo__carbon_thunk.call: init %empty_tuple.type = call imports.%foo__carbon_thunk.decl(%addr.loc8_22.1) // CHECK:STDOUT: %Cpp.ref.loc9: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] // CHECK:STDOUT: %U.ref.loc9: type = name_ref U, imports.%U.decl [concrete = constants.%U] // CHECK:STDOUT: %bar.ref: %U.bar.type = name_ref bar, imports.%U.bar.decl [concrete = constants.%U.bar] // CHECK:STDOUT: %U.bar.call: init %empty_tuple.type = call %bar.ref() -// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.2fa +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_22: = bound_method %.loc8_22.1, constants.%T.as.Destroy.impl.Op.2fa // CHECK:STDOUT: -// CHECK:STDOUT: %bound_method: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn -// CHECK:STDOUT: %addr: %ptr.86f = addr_of %.loc8_12.2 -// CHECK:STDOUT: %T.as.Destroy.impl.Op.call: init %empty_tuple.type = call %bound_method(%addr) +// CHECK:STDOUT: %bound_method.loc8_22: = bound_method %.loc8_22.1, %T.as.Destroy.impl.Op.specific_fn.1 +// CHECK:STDOUT: %addr.loc8_22.2: %ptr.86f = addr_of %.loc8_22.1 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_22: init %empty_tuple.type = call %bound_method.loc8_22(%addr.loc8_22.2) +// CHECK:STDOUT: %T.as.Destroy.impl.Op.bound.loc8_12: = bound_method %.loc8_12.2, constants.%T.as.Destroy.impl.Op.2fa +// CHECK:STDOUT: +// CHECK:STDOUT: %bound_method.loc8_12: = bound_method %.loc8_12.2, %T.as.Destroy.impl.Op.specific_fn.2 +// CHECK:STDOUT: %addr.loc8_12: %ptr.86f = addr_of %.loc8_12.2 +// CHECK:STDOUT: %T.as.Destroy.impl.Op.call.loc8_12: init %empty_tuple.type = call %bound_method.loc8_12(%addr.loc8_12) // CHECK:STDOUT: // CHECK:STDOUT: } // CHECK:STDOUT: diff --git a/toolchain/check/testdata/interop/cpp/import.carbon b/toolchain/check/testdata/interop/cpp/import.carbon new file mode 100644 index 000000000000..90be58289dea --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/import.carbon @@ -0,0 +1,120 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/import.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/import.carbon + +// --- header.h + +auto foo_short(short x) -> void; +auto foo_int(int x) -> void; + +// --- api.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "header.h"; + +alias FooShort = Cpp.foo_short; +alias FooInt = Cpp.foo_int; + +// --- fail_todo_import_api.carbon +// CHECK:STDERR: fail_todo_import_api.carbon: error: semantics TODO: `Unsupported: Importing C++ functions that require thunks indirectly` [SemanticsTodo] +// CHECK:STDERR: + +library "[[@TEST_NAME]]"; + +import library "api"; + +fn F() { + //@dump-sem-ir-begin + FooShort(8 as i16); + FooInt(9); + //@dump-sem-ir-end +} + +// CHECK:STDOUT: --- fail_todo_import_api.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %foo_short.type: type = fn_type @foo_short [concrete] +// CHECK:STDOUT: %foo_short: %foo_short.type = struct_value () [concrete] +// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete] +// CHECK:STDOUT: %i16: type = class_type @Int, @Int(%int_16) [concrete] +// CHECK:STDOUT: %int_8.b85: Core.IntLiteral = int_value 8 [concrete] +// CHECK:STDOUT: %As.type.f58: type = facet_type <@As, @As(%i16)> [concrete] +// CHECK:STDOUT: %As.Convert.type.8b6: type = fn_type @As.Convert, @As(%i16) [concrete] +// CHECK:STDOUT: %To: Core.IntLiteral = bind_symbolic_name To, 0 [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0b2: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.6d7: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0b2 = struct_value () [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.6c8: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%To) [symbolic] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.1ee: %Core.IntLiteral.as.As.impl.Convert.type.6c8 = struct_value () [symbolic] +// CHECK:STDOUT: %As.impl_witness.ef2: = impl_witness imports.%As.impl_witness_table.a72, @Core.IntLiteral.as.As.impl(%int_16) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.type.fee: type = fn_type @Core.IntLiteral.as.As.impl.Convert, @Core.IntLiteral.as.As.impl(%int_16) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.dc5: %Core.IntLiteral.as.As.impl.Convert.type.fee = struct_value () [concrete] +// CHECK:STDOUT: %As.facet: %As.type.f58 = facet_value Core.IntLiteral, (%As.impl_witness.ef2) [concrete] +// CHECK:STDOUT: %.026: type = fn_type_with_self_type %As.Convert.type.8b6, %As.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.bound: = bound_method %int_8.b85, %Core.IntLiteral.as.As.impl.Convert.dc5 [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.As.impl.Convert.dc5, @Core.IntLiteral.as.As.impl.Convert(%int_16) [concrete] +// CHECK:STDOUT: %bound_method.b6e: = bound_method %int_8.b85, %Core.IntLiteral.as.As.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_8.892: %i16 = int_value 8 [concrete] +// CHECK:STDOUT: %foo_int.type: type = fn_type @foo_int [concrete] +// CHECK:STDOUT: %foo_int: %foo_int.type = struct_value () [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %int_9.988: Core.IntLiteral = int_value 9 [concrete] +// CHECK:STDOUT: %ImplicitAs.type.9ba: type = facet_type <@ImplicitAs, @ImplicitAs(%i32)> [concrete] +// CHECK:STDOUT: %ImplicitAs.Convert.type.6da: type = fn_type @ImplicitAs.Convert, @ImplicitAs(%i32) [concrete] +// CHECK:STDOUT: %ImplicitAs.impl_witness.e34: = impl_witness imports.%ImplicitAs.impl_witness_table.e36, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ed5: type = fn_type @Core.IntLiteral.as.ImplicitAs.impl.Convert, @Core.IntLiteral.as.ImplicitAs.impl(%int_32) [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.16d: %Core.IntLiteral.as.ImplicitAs.impl.Convert.type.ed5 = struct_value () [concrete] +// CHECK:STDOUT: %ImplicitAs.facet: %ImplicitAs.type.9ba = facet_value Core.IntLiteral, (%ImplicitAs.impl_witness.e34) [concrete] +// CHECK:STDOUT: %.d6a: type = fn_type_with_self_type %ImplicitAs.Convert.type.6da, %ImplicitAs.facet [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.bound: = bound_method %int_9.988, %Core.IntLiteral.as.ImplicitAs.impl.Convert.16d [concrete] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn: = specific_function %Core.IntLiteral.as.ImplicitAs.impl.Convert.16d, @Core.IntLiteral.as.ImplicitAs.impl.Convert(%int_32) [concrete] +// CHECK:STDOUT: %bound_method.8e3: = bound_method %int_9.988, %Core.IntLiteral.as.ImplicitAs.impl.Convert.specific_fn [concrete] +// CHECK:STDOUT: %int_9.114: %i32 = int_value 9 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Main.FooShort: %foo_short.type = import_ref Main//api, FooShort, loaded [concrete = constants.%foo_short] +// CHECK:STDOUT: %Main.FooInt: %foo_int.type = import_ref Main//api, FooInt, loaded [concrete = constants.%foo_int] +// CHECK:STDOUT: %Core.import_ref.a86c: @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert.type (%Core.IntLiteral.as.ImplicitAs.impl.Convert.type.0b2) = import_ref Core//prelude/parts/int, loc16_39, loaded [symbolic = @Core.IntLiteral.as.ImplicitAs.impl.%Core.IntLiteral.as.ImplicitAs.impl.Convert (constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.6d7)] +// CHECK:STDOUT: %ImplicitAs.impl_witness_table.e36 = impl_witness_table (%Core.import_ref.a86c), @Core.IntLiteral.as.ImplicitAs.impl [concrete] +// CHECK:STDOUT: %Core.import_ref.ea5: @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert.type (%Core.IntLiteral.as.As.impl.Convert.type.6c8) = import_ref Core//prelude/parts/int, loc25_39, loaded [symbolic = @Core.IntLiteral.as.As.impl.%Core.IntLiteral.as.As.impl.Convert (constants.%Core.IntLiteral.as.As.impl.Convert.1ee)] +// CHECK:STDOUT: %As.impl_witness_table.a72 = impl_witness_table (%Core.import_ref.ea5), @Core.IntLiteral.as.As.impl [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %FooShort.ref: %foo_short.type = name_ref FooShort, imports.%Main.FooShort [concrete = constants.%foo_short] +// CHECK:STDOUT: %int_8: Core.IntLiteral = int_value 8 [concrete = constants.%int_8.b85] +// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16] +// CHECK:STDOUT: %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16] +// CHECK:STDOUT: %impl.elem0.loc10: %.026 = impl_witness_access constants.%As.impl_witness.ef2, element0 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.dc5] +// CHECK:STDOUT: %bound_method.loc10_14.1: = bound_method %int_8, %impl.elem0.loc10 [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.bound] +// CHECK:STDOUT: %specific_fn.loc10: = specific_function %impl.elem0.loc10, @Core.IntLiteral.as.As.impl.Convert(constants.%int_16) [concrete = constants.%Core.IntLiteral.as.As.impl.Convert.specific_fn] +// CHECK:STDOUT: %bound_method.loc10_14.2: = bound_method %int_8, %specific_fn.loc10 [concrete = constants.%bound_method.b6e] +// CHECK:STDOUT: %Core.IntLiteral.as.As.impl.Convert.call: init %i16 = call %bound_method.loc10_14.2(%int_8) [concrete = constants.%int_8.892] +// CHECK:STDOUT: %.loc10_14.1: %i16 = value_of_initializer %Core.IntLiteral.as.As.impl.Convert.call [concrete = constants.%int_8.892] +// CHECK:STDOUT: %.loc10_14.2: %i16 = converted %int_8, %.loc10_14.1 [concrete = constants.%int_8.892] +// CHECK:STDOUT: %foo_short.call: init %empty_tuple.type = call %FooShort.ref(%.loc10_14.2) +// CHECK:STDOUT: %FooInt.ref: %foo_int.type = name_ref FooInt, imports.%Main.FooInt [concrete = constants.%foo_int] +// CHECK:STDOUT: %int_9: Core.IntLiteral = int_value 9 [concrete = constants.%int_9.988] +// CHECK:STDOUT: %impl.elem0.loc11: %.d6a = impl_witness_access constants.%ImplicitAs.impl_witness.e34, element0 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.16d] +// CHECK:STDOUT: %bound_method.loc11_10.1: = bound_method %int_9, %impl.elem0.loc11 [concrete = constants.%Core.IntLiteral.as.ImplicitAs.impl.Convert.bound] +// 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] +// CHECK:STDOUT: %bound_method.loc11_10.2: = bound_method %int_9, %specific_fn.loc11 [concrete = constants.%bound_method.8e3] +// CHECK:STDOUT: %Core.IntLiteral.as.ImplicitAs.impl.Convert.call: init %i32 = call %bound_method.loc11_10.2(%int_9) [concrete = constants.%int_9.114] +// CHECK:STDOUT: %.loc11_10.1: %i32 = value_of_initializer %Core.IntLiteral.as.ImplicitAs.impl.Convert.call [concrete = constants.%int_9.114] +// CHECK:STDOUT: %.loc11_10.2: %i32 = converted %int_9, %.loc11_10.1 [concrete = constants.%int_9.114] +// CHECK:STDOUT: %foo_int.call: init %empty_tuple.type = call %FooInt.ref(%.loc11_10.2) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/lower/mangler.cpp b/toolchain/lower/mangler.cpp index d35fa78fd83d..99be2a4c6fd5 100644 --- a/toolchain/lower/mangler.cpp +++ b/toolchain/lower/mangler.cpp @@ -169,6 +169,8 @@ auto Mangler::Mangle(SemIR::FunctionId function_id, case SemIR::Function::SpecialFunctionKind::Thunk: os << ":thunk"; break; + case SemIR::Function::SpecialFunctionKind::HasCppThunk: + CARBON_FATAL("C++ functions should have been handled earlier"); } // TODO: If the function is private, also include the library name as part of diff --git a/toolchain/lower/testdata/interop/cpp/thunk.carbon b/toolchain/lower/testdata/interop/cpp/thunk.carbon new file mode 100644 index 000000000000..c74f36e5429d --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/thunk.carbon @@ -0,0 +1,85 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/thunk.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/thunk.carbon + +// ============================================================================ +// Parameter requires a thunk to be generated +// ============================================================================ + +// --- thunk.h + +void foo(short x, int y, long z); + +// --- import_thunk.carbon + +library "[[@TEST_NAME]]"; + +import Cpp library "thunk.h"; + +fn MyF() { + // TODO: Make sure we actually store the value 5 into `alloca`. + // See https://github.com/carbon-language/carbon-lang/pull/5850/files#r2249030529 + Cpp.foo(5, 6, 7); +} + +// CHECK:STDOUT: ; ModuleID = 'import_thunk.carbon' +// CHECK:STDOUT: source_filename = "import_thunk.carbon" +// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @_CMyF.Main() !dbg !7 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc9_18.1.temp = alloca i16, align 2, !dbg !10 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(i64 2, ptr %.loc9_18.1.temp), !dbg !10 +// CHECK:STDOUT: call void @_Z3foosil.carbon_thunk(ptr %.loc9_18.1.temp, i32 6, i64 7), !dbg !10 +// CHECK:STDOUT: ret void, !dbg !11 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z3foosil(i16, i32, i64) +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress +// CHECK:STDOUT: define dso_local void @_Z3foosil.carbon_thunk(ptr %x, i32 %y, i64 %z) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %x.addr = alloca ptr, align 8 +// CHECK:STDOUT: %y.addr = alloca i32, align 4 +// CHECK:STDOUT: %z.addr = alloca i64, align 8 +// CHECK:STDOUT: store ptr %x, ptr %x.addr, align 8 +// CHECK:STDOUT: store i32 %y, ptr %y.addr, align 4 +// CHECK:STDOUT: store i64 %z, ptr %z.addr, align 8 +// CHECK:STDOUT: %0 = load ptr, ptr %x.addr, align 8 +// CHECK:STDOUT: %1 = load i16, ptr %0, align 2 +// CHECK:STDOUT: %2 = load i32, ptr %y.addr, align 4 +// CHECK:STDOUT: %3 = load i64, ptr %z.addr, align 8 +// CHECK:STDOUT: call void @_Z3foosil(i16 signext %1, i32 %2, i64 %3) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #1 = { alwaysinline mustprogress "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="0" "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: +// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4} +// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 0} +// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C, file: !6, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !DIFile(filename: "import_thunk.carbon", directory: "") +// CHECK:STDOUT: !7 = distinct !DISubprogram(name: "MyF", linkageName: "_CMyF.Main", scope: null, file: !6, line: 6, type: !8, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !8 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !9 = !{} +// CHECK:STDOUT: !10 = !DILocation(line: 9, column: 3, scope: !7) +// CHECK:STDOUT: !11 = !DILocation(line: 6, column: 1, scope: !7) diff --git a/toolchain/sem_ir/function.h b/toolchain/sem_ir/function.h index 2a1fa9fe7742..a0d3c7d0670f 100644 --- a/toolchain/sem_ir/function.h +++ b/toolchain/sem_ir/function.h @@ -19,7 +19,12 @@ namespace Carbon::SemIR { // Function-specific fields. struct FunctionFields { // Kinds of special functions. - enum class SpecialFunctionKind : uint8_t { None, Builtin, Thunk }; + enum class SpecialFunctionKind : uint8_t { + None, + Builtin, + Thunk, + HasCppThunk, + }; // Kinds of virtual modifiers that can apply to functions. enum class VirtualModifier : uint8_t { None, Virtual, Abstract, Impl }; @@ -64,7 +69,8 @@ struct FunctionFields { InstId self_param_id = InstId::None; // Data that is specific to the special function kind. Use - // `builtin_function_kind()` or `thunk_decl_id()` to access this. + // `builtin_function_kind()`, `thunk_decl_id()` or `cpp_thunk_decl_id()` to + // access this. AnyRawId special_function_kind_data = AnyRawId(AnyRawId::NoneIndex); // The following members are accumulated throughout the function definition. @@ -116,14 +122,23 @@ struct Function : public EntityWithParamsBase, : BuiltinFunctionKind::None; } - // Returns the declaration that this is a thunk for, or None if this function - // is not a thunk. + // Returns the declaration that this is a non C++ thunk for, or None if this + // function is not a thunk. auto thunk_decl_id() const -> InstId { return special_function_kind == SpecialFunctionKind::Thunk ? InstId(special_function_kind_data.index) : InstId::None; } + // Returns the declaration of the thunk that should be called to call this + // function, or None if this function is not a C++ function that requires + // calling a thunk. + auto cpp_thunk_decl_id() const -> InstId { + return special_function_kind == SpecialFunctionKind::HasCppThunk + ? InstId(special_function_kind_data.index) + : InstId::None; + } + // Given the ID of an instruction from `param_patterns_id` or // `implicit_param_patterns_id`, returns a `ParamPatternInfo` value with the // corresponding `Call` parameter pattern, its ID, and the entity_name_id of @@ -156,6 +171,14 @@ struct Function : public EntityWithParamsBase, special_function_kind = SpecialFunctionKind::Thunk; special_function_kind_data = AnyRawId(decl_id.index); } + + // Sets that this function is a C++ function that should be called using a C++ + // thunk. + auto SetHasCppThunk(InstId decl_id) -> void { + CARBON_CHECK(special_function_kind == SpecialFunctionKind::None); + special_function_kind = SpecialFunctionKind::HasCppThunk; + special_function_kind_data = AnyRawId(decl_id.index); + } }; using FunctionStore = ValueStore;