diff --git a/toolchain/check/cpp/export.cpp b/toolchain/check/cpp/export.cpp index 7d34eeaa453f..7b22bd44ef8a 100644 --- a/toolchain/check/cpp/export.cpp +++ b/toolchain/check/cpp/export.cpp @@ -5,8 +5,10 @@ #include "toolchain/check/cpp/export.h" #include +#include #include "clang/AST/ASTConsumer.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Sema.h" #include "llvm/Support/Casting.h" #include "toolchain/check/cpp/access.h" @@ -421,18 +423,22 @@ static auto BuildCppFunctionDeclForCarbonFn(Context& context, CARBON_CHECK(identifier_info, "function with non-identifier name {0}", function.name_id); + auto* tinfo = context.ast_context().getTrivialTypeSourceInfo( + cpp_function_type, clang_loc); clang::FunctionDecl* function_decl = clang::FunctionDecl::Create( context.ast_context(), context.ast_context().getTranslationUnitDecl(), /*StartLoc=*/clang_loc, /*NLoc=*/clang_loc, identifier_info, - cpp_function_type, /*TInfo=*/nullptr, clang::SC_Extern); + cpp_function_type, tinfo, clang::SC_Extern); // Build parameter decls. llvm::SmallVector param_var_decls; for (auto [i, type] : llvm::enumerate(cpp_param_types)) { + auto* param_tinfo = + context.ast_context().getTrivialTypeSourceInfo(type, clang_loc); clang::ParmVarDecl* param = clang::ParmVarDecl::Create( context.ast_context(), function_decl, /*StartLoc=*/clang_loc, - /*IdLoc=*/clang_loc, /*Id=*/nullptr, type, /*TInfo=*/nullptr, - clang::SC_None, /*DefArg=*/nullptr); + /*IdLoc=*/clang_loc, /*Id=*/nullptr, type, param_tinfo, clang::SC_None, + /*DefArg=*/nullptr); param_var_decls.push_back(param); } function_decl->setParams(param_var_decls); @@ -683,6 +689,10 @@ static auto BuildCppToCarbonThunk(Context& context, SemIR::LocId loc_id, // Build the thunk function body. clang::Sema& sema = context.clang_sema(); clang::Sema::ContextRAII context_raii(sema, thunk_function_decl); + // Ensure that the evaluation context is not `Unevaluated`, as that + // would cause code generation to fail. + clang::EnterExpressionEvaluationContext evaluated( + sema, clang::Sema::ExpressionEvaluationContext::PotentiallyEvaluated); sema.ActOnStartOfFunctionDef(nullptr, thunk_function_decl); clang::StmtResult body = BuildCppToCarbonThunkBody( sema, target, thunk_function_decl, carbon_function_decl); @@ -696,13 +706,18 @@ static auto BuildCppToCarbonThunk(Context& context, SemIR::LocId loc_id, // Create a Carbon thunk that calls `callee`. The thunk's parameters are // all references to the callee parameter type. +// +// `extra_name` will be appended to the thunk name. This is used to +// disambiguate the names of specialized function thunks. static auto BuildCarbonToCarbonThunk(Context& context, SemIR::LocId loc_id, - const FunctionInfo& target) + const FunctionInfo& target, + std::string_view extra_name = "") -> SemIR::FunctionId { // Create the thunk's name. llvm::SmallString<64> thunk_name = context.names().GetFormatted(target.function.name_id); thunk_name += "__carbon_thunk"; + thunk_name += extra_name; auto& ident = context.ast_context().Idents.get(thunk_name); auto thunk_name_id = SemIR::NameId::ForIdentifier(context.identifiers().Add(ident.getName())); @@ -738,18 +753,204 @@ static auto BuildCarbonToCarbonThunk(Context& context, SemIR::LocId loc_id, return carbon_thunk_function_id; } -auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id, - SemIR::FunctionId callee_function_id) +// Creates a `clang::FunctionDecl` that calls the Carbon function in +// `target`. The `extra_name` string is appended to the Carbon thunk's +// name. +// +// Returns nullptr if an error occurs. +auto ExportNonGenericFunctionToCpp(Context& context, SemIR::LocId loc_id, + const FunctionInfo& target, + std::string_view extra_name = "") -> clang::FunctionDecl* { - const SemIR::Function& callee = context.functions().Get(callee_function_id); + // Create a Carbon thunk that calls the callee. The thunk's parameters + // are all references so that the ABI is compatible with C++ callers. + auto carbon_thunk_function_id = + BuildCarbonToCarbonThunk(context, loc_id, target, extra_name); - if (callee.generic_id.has_value()) { - context.TODO(loc_id, - "unsupported: C++ calling a Carbon function with " - "generic parameters"); + // Create a `clang::FunctionDecl` that can be used to call the Carbon thunk. + auto* carbon_function_decl = BuildCppFunctionDeclForCarbonFn( + context, loc_id, carbon_thunk_function_id); + if (!carbon_function_decl) { return nullptr; } + // Create a C++ thunk that calls the Carbon thunk. + return BuildCppToCarbonThunk( + context, loc_id, target, + context.names().GetFormatted(target.function.name_id), + carbon_function_decl); +} + +auto ExportFunctionSpecializationToCpp( + Context& context, clang::FunctionTemplateDecl* function_template_decl, + llvm::ArrayRef template_args) -> bool { + // Map from the `clang::FunctionTemplateDecl` to the Carbon `FunctionDecl`. + auto clang_decl_id = context.clang_decls().LookupId( + SemIR::ClangDeclKey(function_template_decl)); + if (clang_decl_id == SemIR::ClangDeclId::None) { + return false; + } + SemIR::InstId inst_id = context.clang_decls().Get(clang_decl_id).inst_id; + CARBON_CHECK(inst_id.has_value()); + auto target_function_decl = + context.insts().GetAs(inst_id); + auto target_function = + context.functions().Get(target_function_decl.function_id); + + auto* decl_context = function_template_decl->getDeclContext(); + FunctionInfo target(context, target_function_decl.function_id, + target_function, decl_context); + SemIR::LocId loc_id(target.function.first_decl_id()); + + const auto& generic = context.generics().Get(target.function.generic_id); + auto bindings = context.inst_blocks().Get(generic.bindings_id); + CARBON_CHECK(bindings.size() == template_args.size()); + + // This name will be appended to the thunk name to disambiguate + // between specializations. + std::string extra_name; + + // Create a mapping from Carbon generic parameters to the + // corresponding C++ type in `template_args`. + Map symbolic_to_actual; + for (auto [binding_inst_id, clang_template_arg] : + llvm::zip(bindings, template_args)) { + auto type_expr = + ImportCppType(context, loc_id, clang_template_arg.getAsType()); + if (type_expr.type_id == SemIR::ErrorInst::TypeId) { + return false; + } + if (!type_expr.type_id.has_value()) { + context.TODO(loc_id, "failed to import C++ type"); + return false; + } + + auto binding_const_inst_id = + context.constant_values().GetConstantInstId(binding_inst_id); + symbolic_to_actual.Insert(binding_const_inst_id, type_expr.type_id); + + // TODO: this generates a pretty ugly name. + extra_name += std::string(llvm::formatv("{}", type_expr.inst_id)); + } + + // Replace symbolic explicit parameters with a concrete Carbon type. + // + // This will only handle simple cases like `x: T`, and not things like + // `x: T*`. Ultimately what we should be doing here is producing a Specific + // for the generic function. See `fail_todo_generic_pointer.carbon`. + for (auto& param : target.explicit_params) { + auto param_type_inst_id = context.types().GetTypeInstId(param.type_id); + SemIR::InstId symbolic_inst_id = SemIR::InstId::None; + if (auto symbolic_binding = + context.insts().TryGetAs( + param_type_inst_id)) { + symbolic_inst_id = param_type_inst_id; + } else if (auto facet_access_type = + context.insts().TryGetAs( + param_type_inst_id)) { + symbolic_inst_id = facet_access_type->facet_value_inst_id; + } + + if (symbolic_inst_id.has_value()) { + if (auto lookup = symbolic_to_actual.Lookup(symbolic_inst_id)) { + param.type_id = lookup.value(); + } + } + } + + // TODO: handle generic return type. + + // Build the thunks. Mark the C++ thunk as a template specialization. + auto* function_decl = + ExportNonGenericFunctionToCpp(context, loc_id, target, extra_name); + if (!function_decl) { + return false; + } + auto* template_arg_list = clang::TemplateArgumentList::CreateCopy( + context.ast_context(), template_args); + function_decl->setFunctionTemplateSpecialization( + function_template_decl, template_arg_list, + /*InsertPos=*/nullptr, clang::TSK_ExplicitSpecialization); + + return true; +} + +// Creates a `clang::FunctionTemplateDecl` for a generic Carbon function. +// +// Returns nullptr if an error occurs. +static auto ExportGenericFunctionToCpp(Context& context, SemIR::LocId loc_id, + const FunctionInfo& callee) + -> clang::FunctionTemplateDecl* { + auto clang_loc = GetCppLocation(context, loc_id); + + const auto& generic = context.generics().Get(callee.function.generic_id); + auto bindings = context.inst_blocks().Get(generic.bindings_id); + llvm::SmallVector template_param_decls; + + // Create `clang::TemplateTypeParmDecl`s for each of the function's + // symbolic parameters. + // + // TODO: handle the case where the function is within an enclosing generic, + // and only include the bindings introduced in the inner function here. See + // `fail_todo_enclosing_generic.carbon`. + for (auto binding_inst_id : bindings) { + binding_inst_id = + context.constant_values().GetConstantInstId(binding_inst_id); + auto symbolic_binding = + context.insts().GetAs(binding_inst_id); + + const auto& entity_name = + context.entity_names().Get(symbolic_binding.entity_name_id); + + auto* param_ident = GetClangIdentifierInfo(context, entity_name.name_id); + CARBON_CHECK(param_ident, "non-identifier param name {0}", + entity_name.name_id); + + if (symbolic_binding.type_id != SemIR::TypeType::TypeId && + !context.types().Is(symbolic_binding.type_id)) { + context.TODO(loc_id, "binding maps to a non-type template parameter"); + return nullptr; + } + + auto* param_decl = clang::TemplateTypeParmDecl::Create( + context.ast_context(), callee.decl_context, /*KeyLoc=*/clang_loc, + /*NameLoc=*/clang_loc, + /*D=*/0, /*P=*/0, param_ident, /*Typename=*/true, + /*ParameterPack=*/false); + template_param_decls.push_back(param_decl); + + // Store a mapping between the generic parameter's `TypeInstId` and + // the `clang::TemplateTypeParmDecl`. + auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(param_decl); + context.clang_decls().Add({.key = key, .inst_id = binding_inst_id}); + } + + auto* template_param_list = clang::TemplateParameterList::Create( + context.ast_context(), + /*TemplateLoc=*/clang_loc, + /*LAngleLoc=*/clang_loc, template_param_decls, + /*RAngleLoc=*/clang_loc, + /*RequiresClause=*/nullptr); + + auto* function_decl = + BuildCppFunctionDeclForCarbonFn(context, loc_id, callee.function_id); + if (!function_decl) { + return nullptr; + } + + auto* template_decl = clang::FunctionTemplateDecl::Create( + context.ast_context(), callee.decl_context, clang_loc, + function_decl->getDeclName(), template_param_list, function_decl); + function_decl->setDescribedFunctionTemplate(template_decl); + + return template_decl; +} + +auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id, + SemIR::FunctionId callee_function_id) + -> clang::NamedDecl* { + const SemIR::Function& callee = context.functions().Get(callee_function_id); + // Map the parent scope into the C++ AST. auto* decl_context = ExportNameScopeToCpp(context, loc_id, callee.parent_scope_id); @@ -760,22 +961,11 @@ auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id, FunctionInfo target_function_info(context, callee_function_id, callee, decl_context); - // Create a Carbon thunk that calls the callee. The thunk's parameters - // are all references so that the ABI is compatible with C++ callers. - auto carbon_thunk_function_id = - BuildCarbonToCarbonThunk(context, loc_id, target_function_info); - - // Create a `clang::FunctionDecl` that can be used to call the Carbon thunk. - auto* carbon_function_decl = BuildCppFunctionDeclForCarbonFn( - context, loc_id, carbon_thunk_function_id); - if (!carbon_function_decl) { - return nullptr; + if (callee.generic_id.has_value()) { + return ExportGenericFunctionToCpp(context, loc_id, target_function_info); } - // Create a C++ thunk that calls the Carbon thunk. - return BuildCppToCarbonThunk(context, loc_id, target_function_info, - context.names().GetFormatted(callee.name_id), - carbon_function_decl); + return ExportNonGenericFunctionToCpp(context, loc_id, target_function_info); } // Returns whether the given class has any abstract methods. diff --git a/toolchain/check/cpp/export.h b/toolchain/check/cpp/export.h index 1311d7d2c7e7..9cb940617636 100644 --- a/toolchain/check/cpp/export.h +++ b/toolchain/check/cpp/export.h @@ -52,8 +52,18 @@ auto ExportFieldToCpp(Context& context, SemIR::InstId field_inst_id, SemIR::FieldDecl field_decl) -> clang::FieldDecl*; // Get a `clang::FunctionDecl` that can be used to call a Carbon function. +// If the function is generic, a `clang::FunctionTemplateDecl` will be +// created instead. auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id, - SemIR::FunctionId function_id) -> clang::FunctionDecl*; + SemIR::FunctionId function_id) -> clang::NamedDecl*; + +// Creates a C++ function template specialization for a generic Carbon +// function. +// +// Returns true if a specialization was added, false otherwise. +auto ExportFunctionSpecializationToCpp( + Context& context, clang::FunctionTemplateDecl* function_template_decl, + llvm::ArrayRef template_args) -> bool; // Export a Carbon destructor into C++. // diff --git a/toolchain/check/cpp/generate_ast.cpp b/toolchain/check/cpp/generate_ast.cpp index 837bbcf60ffc..6188983fc43c 100644 --- a/toolchain/check/cpp/generate_ast.cpp +++ b/toolchain/check/cpp/generate_ast.cpp @@ -338,6 +338,21 @@ class CarbonExternalASTSource : public SemIR::ReadOnlyASTSource { const clang::DeclContext* decl_context, clang::DeclarationName decl_name, const clang::DeclContext* original_decl_context) -> bool override; + auto LoadExternalSpecializations( + const clang::Decl* decl, + llvm::ArrayRef template_args) -> bool override { + const auto* function_template_decl = + llvm::dyn_cast(decl); + if (!function_template_decl) { + return false; + } + + return ExportFunctionSpecializationToCpp( + *context_, + const_cast(function_template_decl), + template_args); + } + auto CompleteType(clang::TagDecl* tag_decl) -> void override; auto layoutRecordType( @@ -367,7 +382,7 @@ class CarbonExternalASTSource : public SemIR::ReadOnlyASTSource { auto GetOrExportFunctionToCpp(SemIR::InstId target_inst_id, SemIR::FunctionId function_id) - -> clang::FunctionDecl*; + -> clang::NamedDecl*; // Get a current best-effort location for the current position within C++ // processing. auto GetCurrentCppLocId() -> SemIR::LocId { @@ -460,20 +475,29 @@ auto CarbonExternalASTSource::MapInstIdToClangDeclOrType(LookupResult lookup) auto CarbonExternalASTSource::GetOrExportFunctionToCpp( SemIR::InstId target_inst_id, SemIR::FunctionId function_id) - -> clang::FunctionDecl* { + -> clang::NamedDecl* { SemIR::Function& function = context_->functions().Get(function_id); if (const auto* clang_decl = context_->clang_decls().Lookup(function.first_decl_id())) { - return cast(clang_decl->decl()); + return cast(clang_decl->decl()); } - auto* clang_function_decl = + auto* named_decl = ExportFunctionToCpp(*context_, SemIR::LocId(target_inst_id), function_id); - - if (!clang_function_decl) { + if (!named_decl) { return nullptr; } + if (auto* function_template_decl = + llvm::dyn_cast(named_decl)) { + context_->clang_decls().Add( + {.key = SemIR::ClangDeclKey::ForNonFunctionDecl(function_template_decl), + .inst_id = function.first_decl_id()}); + return function_template_decl; + } + + auto* clang_function_decl = llvm::cast(named_decl); + SemIR::ClangDeclSignature thunk_signature; thunk_signature.kind = SemIR::ClangDeclSignature::Normal; thunk_signature.num_params = diff --git a/toolchain/check/cpp/type_mapping.cpp b/toolchain/check/cpp/type_mapping.cpp index f43b27e6e63e..d847fa073653 100644 --- a/toolchain/check/cpp/type_mapping.cpp +++ b/toolchain/check/cpp/type_mapping.cpp @@ -236,6 +236,18 @@ static auto TryMapClassType(Context& context, SemIR::TypeInstId class_inst_id, return ast_context.getCanonicalTagType(tag_decl); } +// Maps a symbolic Carbon type to a C++ template parameter type. +static auto TryMapSymbolicType(Context& context, + SemIR::InstId symbolic_inst_id) { + const auto* clang_decl = context.clang_decls().Lookup(symbolic_inst_id); + if (!clang_decl) { + return clang::QualType(); + } + return context.ast_context().getTemplateTypeParmType( + /*Depth=*/0, /*Index=*/0, /*ParameterPack=*/false, + llvm::cast(clang_decl->decl())); +} + // Maps a Carbon type to a C++ type. Either returns the mapped type, a null type // as a placeholder indicating the type can't be mapped, or a `WrappedType` // representing a type that needs more work before it can be mapped. @@ -299,6 +311,13 @@ static auto TryMapType(Context& context, SemIR::TypeId type_id) clang::ArraySizeModifier::Normal, /*IndexTypeQuals=*/0); }}; } + case SemIR::SymbolicBinding::Kind: { + auto type_inst_id = context.types().GetTypeInstId(type_id); + return TryMapSymbolicType(context, type_inst_id); + } + case CARBON_KIND(SemIR::FacetAccessType facet_access_type): { + return TryMapSymbolicType(context, facet_access_type.facet_value_inst_id); + } default: { return clang::QualType(); diff --git a/toolchain/check/testdata/interop/cpp/function/export/function.carbon b/toolchain/check/testdata/interop/cpp/function/export/function.carbon index 7b0aa001479e..f1a95f049495 100644 --- a/toolchain/check/testdata/interop/cpp/function/export/function.carbon +++ b/toolchain/check/testdata/interop/cpp/function/export/function.carbon @@ -85,42 +85,29 @@ void G() { F(); } library "[[@TEST_NAME]]"; +// CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+9]]:1: in import [InImport] +// CHECK:STDERR: other.carbon:7:1: error: 1 argument passed to function expecting 2 arguments [CallArgCountMismatch] +// CHECK:STDERR: fn HasGenericArg(T:! type, a: T) { a; } +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+5]]:1: in import [InImport] -// CHECK:STDERR: other.carbon:7:1: error: semantics TODO: `unsupported: C++ calling a Carbon function with generic parameters` [SemanticsTodo] +// CHECK:STDERR: other.carbon:7:1: note: calling function declared here [InCallToEntity] // CHECK:STDERR: fn HasGenericArg(T:! type, a: T) { a; } // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: import Other; import Cpp inline ''' void G() { - // CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+8]]:18: error: no member named 'HasGenericArg' in namespace 'Carbon::Other' [CppInteropParseError] - // CHECK:STDERR: 20 | Carbon::Other::HasGenericArg(123); - // CHECK:STDERR: | ^~~~~~~~~~~~~ - // CHECK:STDERR: - // CHECK:STDERR: fail_todo_generic.carbon:[[@LINE+4]]:35: error: expected '(' for function-style cast or type construction [CppInteropParseError] - // CHECK:STDERR: 20 | Carbon::Other::HasGenericArg(123); - // CHECK:STDERR: | ~~~^ - // CHECK:STDERR: Carbon::Other::HasGenericArg(123); } '''; -// --- fail_todo_deduced.carbon +// --- deduced.carbon library "[[@TEST_NAME]]"; -// CHECK:STDERR: fail_todo_deduced.carbon:[[@LINE+5]]:1: in import [InImport] -// CHECK:STDERR: other.carbon:8:1: error: semantics TODO: `unsupported: C++ calling a Carbon function with generic parameters` [SemanticsTodo] -// CHECK:STDERR: fn HasDeducedArg[T:! type](a: T) { a; } -// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// CHECK:STDERR: import Other; import Cpp inline ''' void G() { - // CHECK:STDERR: fail_todo_deduced.carbon:[[@LINE+4]]:18: error: no member named 'HasDeducedArg' in namespace 'Carbon::Other' [CppInteropParseError] - // CHECK:STDERR: 16 | Carbon::Other::HasDeducedArg(123); - // CHECK:STDERR: | ^~~~~~~~~~~~~ - // CHECK:STDERR: Carbon::Other::HasDeducedArg(123); } '''; diff --git a/toolchain/check/testdata/interop/cpp/function/export/generic.carbon b/toolchain/check/testdata/interop/cpp/function/export/generic.carbon new file mode 100644 index 000000000000..aaa14bf87a9f --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/function/export/generic.carbon @@ -0,0 +1,550 @@ +// 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/function/export/generic.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/export/generic.carbon + +// --- generic_type_impls_interface.carbon +library "[[@TEST_NAME]]"; +import Cpp; + +//@dump-sem-ir-begin +interface I { + fn Doit(self); +} + +class A { + impl as I { + fn Doit(unused self) {} + } +} +class B { + impl as I { + fn Doit(unused self) {} + } +} + +fn F[T:! I](t: T) { + t.Doit(); +} + +inline Cpp ''' +void G() { + Carbon::A a; + Carbon::B b; + Carbon::F(a); + Carbon::F(b); +} +'''; +//@dump-sem-ir-end + +// --- fail_todo_non_type_generic.carbon +library "[[@TEST_NAME]]"; +import Cpp; + +// CHECK:STDERR: fail_todo_non_type_generic.carbon:[[@LINE+4]]:1: error: semantics TODO: `binding maps to a non-type template parameter` [SemanticsTodo] +// CHECK:STDERR: fn F[unused N:! i32]() {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn F[unused N:! i32]() {} + +inline Cpp ''' +void G() { + // CHECK:STDERR: fail_todo_non_type_generic.carbon:[[@LINE+8]]:11: error: no member named 'F' in namespace 'Carbon' [CppInteropParseError] + // CHECK:STDERR: 20 | Carbon::F<3>(); + // CHECK:STDERR: | ^ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_non_type_generic.carbon:[[@LINE+4]]:16: error: expected expression [CppInteropParseError] + // CHECK:STDERR: 20 | Carbon::F<3>(); + // CHECK:STDERR: | ^ + // CHECK:STDERR: + Carbon::F<3>(); +} +'''; + +// --- fail_todo_generic_pointer.carbon +library "[[@TEST_NAME]]"; +import Cpp; + +fn F[T:! type](unused t: T*) {} + +inline Cpp ''' +void G() { + int x = 0; + int* _Nonnull p = &x; + // CHECK:STDERR: fail_todo_generic_pointer.carbon:[[@LINE+7]]:3: error: no matching function for call to 'F' [CppInteropParseError] + // CHECK:STDERR: 17 | Carbon::F(p); + // CHECK:STDERR: | ^~~~~~~~~ + // CHECK:STDERR: fail_todo_generic_pointer.carbon:[[@LINE-9]]:30: note: candidate template ignored: deduced type 'T * _Nonnull' of 1st parameter does not match adjusted type 'int * _Nonnull' of argument [with T = int] [CppInteropParseNote] + // CHECK:STDERR: 4 | fn F[T:! type](unused t: T*) {} + // CHECK:STDERR: | ^ + // CHECK:STDERR: + Carbon::F(p); +} +'''; + +// --- fail_todo_enclosing_generic.carbon +library "[[@TEST_NAME]]"; +import Cpp; + +class A(T:! type) { + fn F[U:! type](x: T, y: U); +} +alias B = A(i32); + +inline Cpp ''' +void f() { + // TODO: this currently fails because `B` can't be imported, but the intent + // is to test a generic function within an enclosing generic scope. + // + // CHECK:STDERR: fail_todo_enclosing_generic.carbon:[[@LINE+8]]:11: error: semantics TODO: `interop with unsupported type` [SemanticsTodo] + // CHECK:STDERR: Carbon::B b; + // CHECK:STDERR: ^ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_enclosing_generic.carbon:[[@LINE+4]]:11: error: no type named 'B' in namespace 'Carbon' [CppInteropParseError] + // CHECK:STDERR: 22 | Carbon::B b; + // CHECK:STDERR: | ~~~~~~~~^ + // CHECK:STDERR: + Carbon::B b; + b.F(1, 2); +} +'''; + +// --- fail_generic_unsupported_type.carbon +library "[[@TEST_NAME]]"; +import Cpp; + +// CHECK:STDERR: fail_generic_unsupported_type.carbon:[[@LINE+4]]:1: error: semantics TODO: `failed to import C++ type` [SemanticsTodo] +// CHECK:STDERR: fn F[T:! type](unused t: T) {} +// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// CHECK:STDERR: +fn F[T:! type](unused t: T) {} + +inline Cpp ''' +void G() { + volatile int x; + // CHECK:STDERR: fail_generic_unsupported_type.carbon:[[@LINE+7]]:3: error: no matching function for call to 'F' [CppInteropParseError] + // CHECK:STDERR: 20 | Carbon::F(x); + // CHECK:STDERR: | ^~~~~~~~~ + // CHECK:STDERR: fail_generic_unsupported_type.carbon:[[@LINE-8]]:29: note: candidate template ignored: substitution failure [with T = volatile int] [CppInteropParseNote] + // CHECK:STDERR: 8 | fn F[T:! type](unused t: T) {} + // CHECK:STDERR: | ^ + // CHECK:STDERR: + Carbon::F(x); +} +'''; + +// CHECK:STDOUT: --- generic_type_impls_interface.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: %I.type: type = facet_type <@I> [concrete] +// CHECK:STDOUT: %Self.37e: %I.type = symbolic_binding Self, 0 [symbolic] +// CHECK:STDOUT: %Self.as_type.c84: type = facet_access_type %Self.37e [symbolic] +// CHECK:STDOUT: %pattern_type.c60: type = pattern_type %Self.as_type.c84 [symbolic] +// CHECK:STDOUT: %self.param_patt.a33: %pattern_type.c60 = value_param_pattern [symbolic] +// CHECK:STDOUT: %self.patt.696: %pattern_type.c60 = at_binding_pattern self, %self.param_patt.a33 [symbolic] +// CHECK:STDOUT: %I.WithSelf.Doit.type.26f: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%Self.37e) [symbolic] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %I.WithSelf.Doit.11f: %I.WithSelf.Doit.type.26f = struct_value () [symbolic] +// CHECK:STDOUT: %I.assoc_type: type = assoc_entity_type @I [concrete] +// CHECK:STDOUT: %assoc0.628: %I.assoc_type = assoc_entity element0, @I.WithSelf.%I.WithSelf.Doit.decl [concrete] +// CHECK:STDOUT: %A: type = class_type @A [concrete] +// CHECK:STDOUT: %I.impl_witness.6ad: = impl_witness @A.as.I.impl.%I.impl_witness_table [concrete] +// CHECK:STDOUT: %pattern_type.9ef: type = pattern_type %A [concrete] +// CHECK:STDOUT: %self.param_patt.04e: %pattern_type.9ef = value_param_pattern [concrete] +// CHECK:STDOUT: %self.patt.312: %pattern_type.9ef = at_binding_pattern self, %self.param_patt.04e [concrete] +// CHECK:STDOUT: %A.as.I.impl.Doit.type: type = fn_type @A.as.I.impl.Doit [concrete] +// CHECK:STDOUT: %A.as.I.impl.Doit: %A.as.I.impl.Doit.type = struct_value () [concrete] +// CHECK:STDOUT: %I.facet.64b: %I.type = facet_value %A, (%I.impl_witness.6ad) [concrete] +// CHECK:STDOUT: %I.WithSelf.Doit.type.5b3: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%I.facet.64b) [concrete] +// CHECK:STDOUT: %I.WithSelf.Doit.dab: %I.WithSelf.Doit.type.5b3 = struct_value () [concrete] +// CHECK:STDOUT: %empty_struct_type: type = struct_type {} [concrete] +// CHECK:STDOUT: %complete_type: = complete_type_witness %empty_struct_type [concrete] +// CHECK:STDOUT: %B: type = class_type @B [concrete] +// CHECK:STDOUT: %I.impl_witness.5b8: = impl_witness @B.as.I.impl.%I.impl_witness_table [concrete] +// CHECK:STDOUT: %pattern_type.e39: type = pattern_type %B [concrete] +// CHECK:STDOUT: %self.param_patt.f1f: %pattern_type.e39 = value_param_pattern [concrete] +// CHECK:STDOUT: %self.patt.4eb: %pattern_type.e39 = at_binding_pattern self, %self.param_patt.f1f [concrete] +// CHECK:STDOUT: %B.as.I.impl.Doit.type: type = fn_type @B.as.I.impl.Doit [concrete] +// CHECK:STDOUT: %B.as.I.impl.Doit: %B.as.I.impl.Doit.type = struct_value () [concrete] +// CHECK:STDOUT: %I.facet.9f8: %I.type = facet_value %B, (%I.impl_witness.5b8) [concrete] +// CHECK:STDOUT: %I.WithSelf.Doit.type.2ce: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%I.facet.9f8) [concrete] +// CHECK:STDOUT: %I.WithSelf.Doit.450: %I.WithSelf.Doit.type.2ce = struct_value () [concrete] +// CHECK:STDOUT: %type: type = facet_type [concrete] +// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self] +// CHECK:STDOUT: %pattern_type.6cb: type = pattern_type %I.type [concrete] +// CHECK:STDOUT: %T.patt: %pattern_type.6cb = symbolic_binding_pattern T, 0 [symbolic] +// CHECK:STDOUT: %T: %I.type = symbolic_binding T, 0 [symbolic] +// CHECK:STDOUT: %T.as_type: type = facet_access_type %T [symbolic] +// CHECK:STDOUT: %pattern_type.b3a: type = pattern_type %T.as_type [symbolic] +// CHECK:STDOUT: %t.param_patt.5db: %pattern_type.b3a = value_param_pattern [symbolic] +// CHECK:STDOUT: %t.patt.030: %pattern_type.b3a = at_binding_pattern t, %t.param_patt.5db [symbolic] +// CHECK:STDOUT: %F.type: type = fn_type @F [concrete] +// CHECK:STDOUT: %F: %F.type = struct_value () [concrete] +// CHECK:STDOUT: %require_complete: = require_complete_type %T.as_type [symbolic] +// CHECK:STDOUT: %I.WithSelf.Doit.type.860: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%T) [symbolic] +// CHECK:STDOUT: %I.WithSelf.Doit.45d: %I.WithSelf.Doit.type.860 = struct_value () [symbolic] +// CHECK:STDOUT: %I.lookup_impl_witness: = lookup_impl_witness %T, @I [symbolic] +// CHECK:STDOUT: %.8a9: type = fn_type_with_self_type %I.WithSelf.Doit.type.860, %T [symbolic] +// CHECK:STDOUT: %impl.elem0: %.8a9 = impl_witness_access %I.lookup_impl_witness, element0 [symbolic] +// CHECK:STDOUT: %self.param_patt.58e: %pattern_type.b3a = value_param_pattern [symbolic] +// CHECK:STDOUT: %self.patt.300: %pattern_type.b3a = at_binding_pattern self, %self.param_patt.58e [symbolic] +// CHECK:STDOUT: %specific_impl_fn: = specific_impl_function %impl.elem0, @I.WithSelf.Doit(%T) [symbolic] +// CHECK:STDOUT: %Destroy.type: type = facet_type <@Destroy> [concrete] +// CHECK:STDOUT: %Destroy.Op.type.1d8f74.2: type = fn_type @Destroy.Op.loc9_9.2 [concrete] +// CHECK:STDOUT: %Destroy.Op.1a2547.2: %Destroy.Op.type.1d8f74.2 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.df9cc1.2: = custom_witness (%Destroy.Op.1a2547.2), @Destroy [concrete] +// CHECK:STDOUT: %Destroy.facet.6e5: %Destroy.type = facet_value %A, (%custom_witness.df9cc1.2) [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.type.09e: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Destroy.facet.6e5) [concrete] +// CHECK:STDOUT: %.dca: type = fn_type_with_self_type %Destroy.WithSelf.Op.type.09e, %Destroy.facet.6e5 [concrete] +// CHECK:STDOUT: %Destroy.Op.type.1d8f74.3: type = fn_type @Destroy.Op.loc14 [concrete] +// CHECK:STDOUT: %Destroy.Op.1a2547.3: %Destroy.Op.type.1d8f74.3 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.df9cc1.3: = custom_witness (%Destroy.Op.1a2547.3), @Destroy [concrete] +// CHECK:STDOUT: %Destroy.facet.f70: %Destroy.type = facet_value %B, (%custom_witness.df9cc1.3) [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.type.cda: type = fn_type @Destroy.WithSelf.Op, @Destroy.WithSelf(%Destroy.facet.f70) [concrete] +// CHECK:STDOUT: %.3d9: type = fn_type_with_self_type %Destroy.WithSelf.Op.type.cda, %Destroy.facet.f70 [concrete] +// CHECK:STDOUT: %t.param_patt.169: %pattern_type.9ef = value_param_pattern [concrete] +// CHECK:STDOUT: %t.patt.ee8: %pattern_type.9ef = at_binding_pattern t, %t.param_patt.169 [concrete] +// CHECK:STDOUT: %F.specific_fn.f33: = specific_function %F, @F(%I.facet.64b) [concrete] +// CHECK:STDOUT: %t.param_patt.267: %pattern_type.e39 = value_param_pattern [concrete] +// CHECK:STDOUT: %t.patt.062: %pattern_type.e39 = at_binding_pattern t, %t.param_patt.267 [concrete] +// CHECK:STDOUT: %F.specific_fn.db2: = specific_function %F, @F(%I.facet.9f8) [concrete] +// CHECK:STDOUT: %.660: type = fn_type_with_self_type %I.WithSelf.Doit.type.5b3, %I.facet.64b [concrete] +// CHECK:STDOUT: %.545: type = fn_type_with_self_type %I.WithSelf.Doit.type.2ce, %I.facet.9f8 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: file { +// CHECK:STDOUT: %I.decl: type = interface_decl @I [concrete = constants.%I.type] {} {} +// CHECK:STDOUT: %A.decl: type = class_decl @A [concrete = constants.%A] {} {} +// CHECK:STDOUT: %B.decl: type = class_decl @B [concrete = constants.%B] {} {} +// CHECK:STDOUT: %F.decl: %F.type = fn_decl @F [concrete = constants.%F] { +// CHECK:STDOUT: %T.patt.loc20_7.1: %pattern_type.6cb = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc20_7.2 (constants.%T.patt)] +// CHECK:STDOUT: %t.param_patt.loc20_14.1: @F.%pattern_type (%pattern_type.b3a) = value_param_pattern [symbolic = %t.param_patt.loc20_14.2 (constants.%t.param_patt.5db)] +// CHECK:STDOUT: %t.patt.loc20_14.1: @F.%pattern_type (%pattern_type.b3a) = at_binding_pattern t, %t.param_patt.loc20_14.1 [symbolic = %t.patt.loc20_14.2 (constants.%t.patt.030)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %.loc20_10: type = splice_block %I.ref [concrete = constants.%I.type] { +// CHECK:STDOUT: %.Self: %type = symbolic_binding .Self [symbolic_self = constants.%.Self] +// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %T.loc20_7.2: %I.type = symbolic_binding T, 0 [symbolic = %T.loc20_7.1 (constants.%T)] +// CHECK:STDOUT: %t.param: @F.%T.as_type.loc20_16.1 (%T.as_type) = value_param call_param0 +// CHECK:STDOUT: %.loc20_16.1: type = splice_block %.loc20_16.2 [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)] { +// CHECK:STDOUT: %T.ref: %I.type = name_ref T, %T.loc20_7.2 [symbolic = %T.loc20_7.1 (constants.%T)] +// CHECK:STDOUT: %T.as_type.loc20_16.2: type = facet_access_type %T.ref [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)] +// CHECK:STDOUT: %.loc20_16.2: type = converted %T.ref, %T.as_type.loc20_16.2 [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %t: @F.%T.as_type.loc20_16.1 (%T.as_type) = wrapper_binding t, %t.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: inline_cpp "void G() {\n Carbon::A a;\n Carbon::B b;\n Carbon::F(a);\n Carbon::F(b);\n}\n" +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: interface @I { +// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = constants.%Self.37e] +// CHECK:STDOUT: %I.WithSelf.decl = interface_with_self_decl @I [concrete] +// CHECK:STDOUT: +// CHECK:STDOUT: !with Self: +// CHECK:STDOUT: %I.WithSelf.Doit.decl: @I.WithSelf.%I.WithSelf.Doit.type (%I.WithSelf.Doit.type.26f) = fn_decl @I.WithSelf.Doit [symbolic = @I.WithSelf.%I.WithSelf.Doit (constants.%I.WithSelf.Doit.11f)] { +// CHECK:STDOUT: %self.param_patt.loc6_11.1: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = value_param_pattern [symbolic = %self.param_patt.loc6_11.2 (constants.%self.param_patt.a33)] +// CHECK:STDOUT: %self.patt.loc6_11.1: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = at_binding_pattern self, %self.param_patt.loc6_11.1 [symbolic = %self.patt.loc6_11.2 (constants.%self.patt.696)] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: @I.WithSelf.Doit.%Self.as_type.loc6_11.1 (%Self.as_type.c84) = value_param call_param0 +// CHECK:STDOUT: %.loc6_11.1: type = splice_block %.loc6_11.2 [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)] { +// CHECK:STDOUT: %Self.ref: %I.type = name_ref Self, @I.%Self [symbolic = %Self (constants.%Self.37e)] +// CHECK:STDOUT: %Self.as_type.loc6_11.2: type = facet_access_type %Self.ref [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)] +// CHECK:STDOUT: %.loc6_11.2: type = converted %Self.ref, %Self.as_type.loc6_11.2 [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)] +// CHECK:STDOUT: } +// CHECK:STDOUT: %self: @I.WithSelf.Doit.%Self.as_type.loc6_11.1 (%Self.as_type.c84) = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %assoc0: %I.assoc_type = assoc_entity element0, %I.WithSelf.Doit.decl [concrete = constants.%assoc0.628] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = %Self +// CHECK:STDOUT: .Doit = @I.WithSelf.%assoc0 +// CHECK:STDOUT: witness = (@I.WithSelf.%I.WithSelf.Doit.decl) +// CHECK:STDOUT: +// CHECK:STDOUT: !requires: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @A.as.I.impl: %Self.ref as %I.ref { +// CHECK:STDOUT: %A.as.I.impl.Doit.decl: %A.as.I.impl.Doit.type = fn_decl @A.as.I.impl.Doit [concrete = constants.%A.as.I.impl.Doit] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.9ef = value_param_pattern [concrete = constants.%self.param_patt.04e] +// CHECK:STDOUT: %self.patt: %pattern_type.9ef = at_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.312] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %A = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%A [concrete = constants.%A] +// CHECK:STDOUT: %self: %A = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (%A.as.I.impl.Doit.decl), @A.as.I.impl [concrete] +// CHECK:STDOUT: %I.impl_witness: = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness.6ad] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Doit = %A.as.I.impl.Doit.decl +// CHECK:STDOUT: extend %I.ref +// CHECK:STDOUT: witness = %I.impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: impl @B.as.I.impl: %Self.ref as %I.ref { +// CHECK:STDOUT: %B.as.I.impl.Doit.decl: %B.as.I.impl.Doit.type = fn_decl @B.as.I.impl.Doit [concrete = constants.%B.as.I.impl.Doit] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.e39 = value_param_pattern [concrete = constants.%self.param_patt.f1f] +// CHECK:STDOUT: %self.patt: %pattern_type.e39 = at_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.4eb] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: %B = value_param call_param0 +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B [concrete = constants.%B] +// CHECK:STDOUT: %self: %B = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %I.impl_witness_table = impl_witness_table (%B.as.I.impl.Doit.decl), @B.as.I.impl [concrete] +// CHECK:STDOUT: %I.impl_witness: = impl_witness %I.impl_witness_table [concrete = constants.%I.impl_witness.5b8] +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Doit = %B.as.I.impl.Doit.decl +// CHECK:STDOUT: extend %I.ref +// CHECK:STDOUT: witness = %I.impl_witness +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @A { +// CHECK:STDOUT: impl_decl @A.as.I.impl [concrete] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%A [concrete = constants.%A] +// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%A +// CHECK:STDOUT: .I = +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: class @B { +// CHECK:STDOUT: impl_decl @B.as.I.impl [concrete] {} { +// CHECK:STDOUT: %Self.ref: type = name_ref Self, constants.%B [concrete = constants.%B] +// CHECK:STDOUT: %I.ref: type = name_ref I, file.%I.decl [concrete = constants.%I.type] +// CHECK:STDOUT: } +// CHECK:STDOUT: %complete_type: = complete_type_witness constants.%empty_struct_type [concrete = constants.%complete_type] +// CHECK:STDOUT: complete_type_witness = %complete_type +// CHECK:STDOUT: +// CHECK:STDOUT: !members: +// CHECK:STDOUT: .Self = constants.%B +// CHECK:STDOUT: .I = +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @I.WithSelf.Doit(@I.%Self: %I.type) { +// CHECK:STDOUT: %Self: %I.type = symbolic_binding Self, 0 [symbolic = %Self (constants.%Self.37e)] +// CHECK:STDOUT: %Self.as_type.loc6_11.1: type = facet_access_type %Self [symbolic = %Self.as_type.loc6_11.1 (constants.%Self.as_type.c84)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %Self.as_type.loc6_11.1 [symbolic = %pattern_type (constants.%pattern_type.c60)] +// CHECK:STDOUT: %self.param_patt.loc6_11.2: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = value_param_pattern [symbolic = %self.param_patt.loc6_11.2 (constants.%self.param_patt.a33)] +// CHECK:STDOUT: %self.patt.loc6_11.2: @I.WithSelf.Doit.%pattern_type (%pattern_type.c60) = at_binding_pattern self, %self.param_patt.loc6_11.2 [symbolic = %self.patt.loc6_11.2 (constants.%self.patt.696)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%self.param: @I.WithSelf.Doit.%Self.as_type.loc6_11.1 (%Self.as_type.c84)); +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A.as.I.impl.Doit(%self.param: %A) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @B.as.I.impl.Doit(%self.param: %B) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generic fn @F(%T.loc20_7.2: %I.type) { +// CHECK:STDOUT: %T.patt.loc20_7.2: %pattern_type.6cb = symbolic_binding_pattern T, 0 [symbolic = %T.patt.loc20_7.2 (constants.%T.patt)] +// CHECK:STDOUT: %T.loc20_7.1: %I.type = symbolic_binding T, 0 [symbolic = %T.loc20_7.1 (constants.%T)] +// CHECK:STDOUT: %T.as_type.loc20_16.1: type = facet_access_type %T.loc20_7.1 [symbolic = %T.as_type.loc20_16.1 (constants.%T.as_type)] +// CHECK:STDOUT: %pattern_type: type = pattern_type %T.as_type.loc20_16.1 [symbolic = %pattern_type (constants.%pattern_type.b3a)] +// CHECK:STDOUT: %t.param_patt.loc20_14.2: @F.%pattern_type (%pattern_type.b3a) = value_param_pattern [symbolic = %t.param_patt.loc20_14.2 (constants.%t.param_patt.5db)] +// CHECK:STDOUT: %t.patt.loc20_14.2: @F.%pattern_type (%pattern_type.b3a) = at_binding_pattern t, %t.param_patt.loc20_14.2 [symbolic = %t.patt.loc20_14.2 (constants.%t.patt.030)] +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete: = require_complete_type %T.as_type.loc20_16.1 [symbolic = %require_complete (constants.%require_complete)] +// CHECK:STDOUT: %I.WithSelf.Doit.type: type = fn_type @I.WithSelf.Doit, @I.WithSelf(%T.loc20_7.1) [symbolic = %I.WithSelf.Doit.type (constants.%I.WithSelf.Doit.type.860)] +// CHECK:STDOUT: %.loc21_4: type = fn_type_with_self_type %I.WithSelf.Doit.type, %T.loc20_7.1 [symbolic = %.loc21_4 (constants.%.8a9)] +// CHECK:STDOUT: %I.lookup_impl_witness: = lookup_impl_witness %T.loc20_7.1, @I [symbolic = %I.lookup_impl_witness (constants.%I.lookup_impl_witness)] +// CHECK:STDOUT: %impl.elem0.loc21_4.2: @F.%.loc21_4 (%.8a9) = impl_witness_access %I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc21_4.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %specific_impl_fn.loc21_4.2: = specific_impl_function %impl.elem0.loc21_4.2, @I.WithSelf.Doit(%T.loc20_7.1) [symbolic = %specific_impl_fn.loc21_4.2 (constants.%specific_impl_fn)] +// CHECK:STDOUT: +// CHECK:STDOUT: fn(%t.param: @F.%T.as_type.loc20_16.1 (%T.as_type)) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %t.ref: @F.%T.as_type.loc20_16.1 (%T.as_type) = name_ref t, %t +// CHECK:STDOUT: %Doit.ref: %I.assoc_type = name_ref Doit, @I.WithSelf.%assoc0 [concrete = constants.%assoc0.628] +// CHECK:STDOUT: %impl.elem0.loc21_4.1: @F.%.loc21_4 (%.8a9) = impl_witness_access constants.%I.lookup_impl_witness, element0 [symbolic = %impl.elem0.loc21_4.2 (constants.%impl.elem0)] +// CHECK:STDOUT: %bound_method.loc21_4: = bound_method %t.ref, %impl.elem0.loc21_4.1 +// CHECK:STDOUT: %.loc21_10.1: %I.type = converted constants.%T.as_type, constants.%T [symbolic = %T.loc20_7.1 (constants.%T)] +// CHECK:STDOUT: %.loc21_10.2: %I.type = converted constants.%T.as_type, constants.%T [symbolic = %T.loc20_7.1 (constants.%T)] +// CHECK:STDOUT: %specific_impl_fn.loc21_4.1: = specific_impl_function %impl.elem0.loc21_4.1, @I.WithSelf.Doit(constants.%T) [symbolic = %specific_impl_fn.loc21_4.2 (constants.%specific_impl_fn)] +// CHECK:STDOUT: %bound_method.loc21_10: = bound_method %t.ref, %specific_impl_fn.loc21_4.1 +// CHECK:STDOUT: %I.WithSelf.Doit.call: init %empty_tuple.type = call %bound_method.loc21_10(%t.ref) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @A.__destroy_thunk(%self.param: ref %A) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %impl.elem0: %.dca = impl_witness_access constants.%custom_witness.df9cc1.2, element0 [concrete = constants.%Destroy.Op.1a2547.2] +// CHECK:STDOUT: %bound_method: = bound_method %self.param, %impl.elem0 +// CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %bound_method(%self.param) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.Op.loc9_9.1(%self.param: ref %empty_struct_type) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.Op.loc9_9.2(%self.param: ref %A) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @B.__destroy_thunk(%self.param: ref %B) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %impl.elem0: %.3d9 = impl_witness_access constants.%custom_witness.df9cc1.3, element0 [concrete = constants.%Destroy.Op.1a2547.3] +// CHECK:STDOUT: %bound_method: = bound_method %self.param, %impl.elem0 +// CHECK:STDOUT: %Destroy.Op.call: init %empty_tuple.type = call %bound_method(%self.param) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.Op.loc14(%self.param: ref %B) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F__carbon_thunkinst64000035(%_.param: ref %A) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F__carbon_thunkinst64000035.ref: %F.type = name_ref F__carbon_thunkinst64000035, file.%F.decl [concrete = constants.%F] +// CHECK:STDOUT: %I.facet.loc20_19.1: %I.type = facet_value constants.%A, (constants.%I.impl_witness.6ad) [concrete = constants.%I.facet.64b] +// CHECK:STDOUT: %.loc20_19.1: %I.type = converted constants.%A, %I.facet.loc20_19.1 [concrete = constants.%I.facet.64b] +// CHECK:STDOUT: %I.facet.loc20_19.2: %I.type = facet_value constants.%A, (constants.%I.impl_witness.6ad) [concrete = constants.%I.facet.64b] +// CHECK:STDOUT: %.loc20_19.2: %I.type = converted constants.%A, %I.facet.loc20_19.2 [concrete = constants.%I.facet.64b] +// CHECK:STDOUT: %F.specific_fn: = specific_function %F__carbon_thunkinst64000035.ref, @F(constants.%I.facet.64b) [concrete = constants.%F.specific_fn.f33] +// CHECK:STDOUT: %.loc20_19.3: %A = acquire_value %_.param +// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.specific_fn(%.loc20_19.3) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F__carbon_thunkinst64000050(%_.param: ref %B) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %F__carbon_thunkinst64000050.ref: %F.type = name_ref F__carbon_thunkinst64000050, file.%F.decl [concrete = constants.%F] +// CHECK:STDOUT: %I.facet.loc20_19.1: %I.type = facet_value constants.%B, (constants.%I.impl_witness.5b8) [concrete = constants.%I.facet.9f8] +// CHECK:STDOUT: %.loc20_19.1: %I.type = converted constants.%B, %I.facet.loc20_19.1 [concrete = constants.%I.facet.9f8] +// CHECK:STDOUT: %I.facet.loc20_19.2: %I.type = facet_value constants.%B, (constants.%I.impl_witness.5b8) [concrete = constants.%I.facet.9f8] +// CHECK:STDOUT: %.loc20_19.2: %I.type = converted constants.%B, %I.facet.loc20_19.2 [concrete = constants.%I.facet.9f8] +// CHECK:STDOUT: %F.specific_fn: = specific_function %F__carbon_thunkinst64000050.ref, @F(constants.%I.facet.9f8) [concrete = constants.%F.specific_fn.db2] +// CHECK:STDOUT: %.loc20_19.3: %B = acquire_value %_.param +// CHECK:STDOUT: %F.call: init %empty_tuple.type = call %F.specific_fn(%.loc20_19.3) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf(constants.%Self.37e) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%Self.37e +// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.26f +// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.11f +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%Self.37e) { +// CHECK:STDOUT: %Self => constants.%Self.37e +// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%Self.as_type.c84 +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.c60 +// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.a33 +// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.696 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf(constants.%I.facet.64b) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%I.facet.64b +// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.5b3 +// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.dab +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%I.facet.64b) { +// CHECK:STDOUT: %Self => constants.%I.facet.64b +// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%A +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.9ef +// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.04e +// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.312 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf(constants.%I.facet.9f8) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%I.facet.9f8 +// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.2ce +// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.450 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%I.facet.9f8) { +// CHECK:STDOUT: %Self => constants.%I.facet.9f8 +// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%B +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.e39 +// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.f1f +// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.4eb +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%T) { +// CHECK:STDOUT: %T.patt.loc20_7.2 => constants.%T.patt +// CHECK:STDOUT: %T.loc20_7.1 => constants.%T +// CHECK:STDOUT: %T.as_type.loc20_16.1 => constants.%T.as_type +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.b3a +// CHECK:STDOUT: %t.param_patt.loc20_14.2 => constants.%t.param_patt.5db +// CHECK:STDOUT: %t.patt.loc20_14.2 => constants.%t.patt.030 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf(constants.%T) { +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %Self => constants.%T +// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.860 +// CHECK:STDOUT: %I.WithSelf.Doit => constants.%I.WithSelf.Doit.45d +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @I.WithSelf.Doit(constants.%T) { +// CHECK:STDOUT: %Self => constants.%T +// CHECK:STDOUT: %Self.as_type.loc6_11.1 => constants.%T.as_type +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.b3a +// CHECK:STDOUT: %self.param_patt.loc6_11.2 => constants.%self.param_patt.58e +// CHECK:STDOUT: %self.patt.loc6_11.2 => constants.%self.patt.300 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%I.facet.64b) { +// CHECK:STDOUT: %T.patt.loc20_7.2 => constants.%T.patt +// CHECK:STDOUT: %T.loc20_7.1 => constants.%I.facet.64b +// CHECK:STDOUT: %T.as_type.loc20_16.1 => constants.%A +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.9ef +// CHECK:STDOUT: %t.param_patt.loc20_14.2 => constants.%t.param_patt.169 +// CHECK:STDOUT: %t.patt.loc20_14.2 => constants.%t.patt.ee8 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type +// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.5b3 +// CHECK:STDOUT: %.loc21_4 => constants.%.660 +// CHECK:STDOUT: %I.lookup_impl_witness => constants.%I.impl_witness.6ad +// CHECK:STDOUT: %impl.elem0.loc21_4.2 => constants.%A.as.I.impl.Doit +// CHECK:STDOUT: %specific_impl_fn.loc21_4.2 => constants.%A.as.I.impl.Doit +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: specific @F(constants.%I.facet.9f8) { +// CHECK:STDOUT: %T.patt.loc20_7.2 => constants.%T.patt +// CHECK:STDOUT: %T.loc20_7.1 => constants.%I.facet.9f8 +// CHECK:STDOUT: %T.as_type.loc20_16.1 => constants.%B +// CHECK:STDOUT: %pattern_type => constants.%pattern_type.e39 +// CHECK:STDOUT: %t.param_patt.loc20_14.2 => constants.%t.param_patt.267 +// CHECK:STDOUT: %t.patt.loc20_14.2 => constants.%t.patt.062 +// CHECK:STDOUT: +// CHECK:STDOUT: !definition: +// CHECK:STDOUT: %require_complete => constants.%complete_type +// CHECK:STDOUT: %I.WithSelf.Doit.type => constants.%I.WithSelf.Doit.type.2ce +// CHECK:STDOUT: %.loc21_4 => constants.%.545 +// CHECK:STDOUT: %I.lookup_impl_witness => constants.%I.impl_witness.5b8 +// CHECK:STDOUT: %impl.elem0.loc21_4.2 => constants.%B.as.I.impl.Doit +// CHECK:STDOUT: %specific_impl_fn.loc21_4.2 => constants.%B.as.I.impl.Doit +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/lower/testdata/interop/cpp/function/export/generic.carbon b/toolchain/lower/testdata/interop/cpp/function/export/generic.carbon new file mode 100644 index 000000000000..436e7b617a4c --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/function/export/generic.carbon @@ -0,0 +1,329 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/destroy.carbon +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/function/export/generic.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/function/export/generic.carbon + +// --- generic_type_impls_interface.carbon +library "[[@TEST_NAME]]"; +import Cpp; + +interface I { + fn Doit(self); +} + +class A { + impl as I { + fn Doit(unused self) {} + } +} +class B { + impl as I { + fn Doit(unused self) {} + } +} + +fn F[T:! I](t: T) { + t.Doit(); +} + +inline Cpp ''' +void G() { + Carbon::A a; + Carbon::B b; + Carbon::F(a); + Carbon::F(b); +} +'''; + +fn Run() { + Cpp.G(); +} + +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'generic_type_impls_interface.carbon' +// CHECK:STDOUT: source_filename = "generic_type_impls_interface.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: %"class.Carbon::A" = type {} +// CHECK:STDOUT: %"class.Carbon::B" = type {} +// CHECK:STDOUT: +// CHECK:STDOUT: $_ZN6Carbon1AD2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_ZN6Carbon1BD2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable +// CHECK:STDOUT: define dso_local void @_Z1Gv() #0 personality ptr @__gxx_personality_v0 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %a = alloca %"class.Carbon::A", align 1 +// CHECK:STDOUT: %b = alloca %"class.Carbon::B", align 1 +// CHECK:STDOUT: %agg.tmp = alloca %"class.Carbon::A", align 1 +// CHECK:STDOUT: %exn.slot = alloca ptr, align 8 +// CHECK:STDOUT: %ehselector.slot = alloca i32, align 4 +// CHECK:STDOUT: %agg.tmp1 = alloca %"class.Carbon::B", align 1 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a) #4 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b) #4 +// CHECK:STDOUT: invoke void @_ZN6CarbonL1FENS_1AE() +// CHECK:STDOUT: to label %invoke.cont unwind label %lpad +// CHECK:STDOUT: +// CHECK:STDOUT: invoke.cont: ; preds = %entry +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %agg.tmp) #4 +// CHECK:STDOUT: invoke void @_ZN6CarbonL1FENS_1BE() +// CHECK:STDOUT: to label %invoke.cont3 unwind label %lpad2 +// CHECK:STDOUT: +// CHECK:STDOUT: invoke.cont3: ; preds = %invoke.cont +// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %agg.tmp1) #4 +// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %b) #4 +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %b) #4 +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %a) #4 +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %a) #4 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: +// CHECK:STDOUT: lpad: ; preds = %entry +// CHECK:STDOUT: %0 = landingpad { ptr, i32 } +// CHECK:STDOUT: cleanup +// CHECK:STDOUT: %1 = extractvalue { ptr, i32 } %0, 0 +// CHECK:STDOUT: store ptr %1, ptr %exn.slot, align 8 +// CHECK:STDOUT: %2 = extractvalue { ptr, i32 } %0, 1 +// CHECK:STDOUT: store i32 %2, ptr %ehselector.slot, align 4 +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %agg.tmp) #4 +// CHECK:STDOUT: br label %ehcleanup +// CHECK:STDOUT: +// CHECK:STDOUT: lpad2: ; preds = %invoke.cont +// CHECK:STDOUT: %3 = landingpad { ptr, i32 } +// CHECK:STDOUT: cleanup +// CHECK:STDOUT: %4 = extractvalue { ptr, i32 } %3, 0 +// CHECK:STDOUT: store ptr %4, ptr %exn.slot, align 8 +// CHECK:STDOUT: %5 = extractvalue { ptr, i32 } %3, 1 +// CHECK:STDOUT: store i32 %5, ptr %ehselector.slot, align 4 +// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %agg.tmp1) #4 +// CHECK:STDOUT: br label %ehcleanup +// CHECK:STDOUT: +// CHECK:STDOUT: ehcleanup: ; preds = %lpad2, %lpad +// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %b) #4 +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %b) #4 +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %a) #4 +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %a) #4 +// CHECK:STDOUT: br label %eh.resume +// CHECK:STDOUT: +// CHECK:STDOUT: eh.resume: ; preds = %ehcleanup +// CHECK:STDOUT: %exn = load ptr, ptr %exn.slot, align 8 +// CHECK:STDOUT: %sel = load i32, ptr %ehselector.slot, align 4 +// CHECK:STDOUT: %lpad.val = insertvalue { ptr, i32 } poison, ptr %exn, 0 +// CHECK:STDOUT: %lpad.val7 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1 +// CHECK:STDOUT: resume { ptr, i32 } %lpad.val7 +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr %a, { 0, 2, 1, 3, 4 } +// CHECK:STDOUT: uselistorder ptr %b, { 0, 2, 1, 3, 4 } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_ZN6CarbonL1FENS_1AE() #2 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %0 = alloca %"class.Carbon::A", align 1 +// CHECK:STDOUT: call void @_CF__carbon_thunkinst70000035.Main(ptr noundef nonnull align 1 %0) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: declare i32 @__gxx_personality_v0(...) +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 %this) unnamed_addr #3 comdat align 2 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %this.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !11 +// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.A.Main"(ptr noundef nonnull align 1 %this1) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable +// CHECK:STDOUT: define internal void @_ZN6CarbonL1FENS_1BE() #2 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %0 = alloca %"class.Carbon::B", align 1 +// CHECK:STDOUT: call void @_CF__carbon_thunkinst70000050.Main(ptr noundef nonnull align 1 %0) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 1 %this) unnamed_addr #3 comdat align 2 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %this.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !14 +// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.B.Main"(ptr noundef nonnull align 1 %this1) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.end.p0(ptr captures(none)) #1 +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @"_CDoit.A.Main:I.Main"(ptr %self) #4 !dbg !16 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !22 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @"_CDoit.B.Main:I.Main"(ptr %self) #4 !dbg !23 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !26 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.A.Main"(ptr %self) #5 !dbg !27 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_COp.68011419f123494e:core.Destroy.Core"(ptr %self), !dbg !30 +// CHECK:STDOUT: ret void, !dbg !30 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.68011419f123494e:core.Destroy.Core"(ptr %self) #4 !dbg !31 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !34 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.B.Main"(ptr %self) #5 !dbg !35 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_COp.6c3865e9cbd9f6de:core.Destroy.Core"(ptr %self), !dbg !38 +// CHECK:STDOUT: ret void, !dbg !38 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.6c3865e9cbd9f6de:core.Destroy.Core"(ptr %self) #4 !dbg !39 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !42 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CF__carbon_thunkinst70000035.Main(ptr %_) #4 !dbg !43 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CF.Main.3e1f7ed08cd9ee58(ptr %_), !dbg !46 +// CHECK:STDOUT: ret void, !dbg !46 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CF__carbon_thunkinst70000050.Main(ptr %_) #4 !dbg !47 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CF.Main.bd1b6d59f703c190(ptr %_), !dbg !50 +// CHECK:STDOUT: ret void, !dbg !50 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @main() #4 !dbg !51 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z1Gv(), !dbg !55 +// CHECK:STDOUT: ret i32 0, !dbg !56 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define linkonce_odr void @_CF.Main.3e1f7ed08cd9ee58(ptr %t) #4 !dbg !57 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_CDoit.A.Main:I.Main"(ptr %t), !dbg !60 +// CHECK:STDOUT: ret void, !dbg !61 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define linkonce_odr void @_CF.Main.bd1b6d59f703c190(ptr %t) #4 !dbg !62 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_CDoit.B.Main:I.Main"(ptr %t), !dbg !65 +// CHECK:STDOUT: ret void, !dbg !66 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 1, 0 } +// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon1AD2Ev, { 0, 2, 1, 3 } +// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon1BD2Ev, { 0, 2, 1, 3 } +// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.end.p0, { 3, 1, 2, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #2 = { alwaysinline mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #3 = { inlinehint mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: attributes #4 = { nounwind } +// CHECK:STDOUT: attributes #5 = { alwaysinline nounwind } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!0} +// CHECK:STDOUT: !llvm.module.flags = !{!2, !3, !4, !5, !6} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!7} +// CHECK:STDOUT: +// CHECK:STDOUT: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !1 = !DIFile(filename: "generic_type_impls_interface.carbon", directory: "") +// CHECK:STDOUT: !2 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !3 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !4 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !5 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !6 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !7 = !{!8, !8, i64 0} +// CHECK:STDOUT: !8 = !{!"int", !9, i64 0} +// CHECK:STDOUT: !9 = !{!"omnipotent char", !10, i64 0} +// CHECK:STDOUT: !10 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !11 = !{!12, !12, i64 0} +// CHECK:STDOUT: !12 = !{!"p1 _ZTSN6Carbon1AE", !13, i64 0} +// CHECK:STDOUT: !13 = !{!"any pointer", !9, i64 0} +// CHECK:STDOUT: !14 = !{!15, !15, i64 0} +// CHECK:STDOUT: !15 = !{!"p1 _ZTSN6Carbon1BE", !13, i64 0} +// CHECK:STDOUT: !16 = distinct !DISubprogram(name: "Doit", linkageName: "_CDoit.A.Main:I.Main", scope: null, file: !1, line: 10, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !20) +// CHECK:STDOUT: !17 = !DISubroutineType(types: !18) +// CHECK:STDOUT: !18 = !{null, !19} +// CHECK:STDOUT: !19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !20 = !{!21} +// CHECK:STDOUT: !21 = !DILocalVariable(arg: 1, scope: !16, type: !19) +// CHECK:STDOUT: !22 = !DILocation(line: 10, column: 5, scope: !16) +// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "Doit", linkageName: "_CDoit.B.Main:I.Main", scope: null, file: !1, line: 15, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !24) +// CHECK:STDOUT: !24 = !{!25} +// CHECK:STDOUT: !25 = !DILocalVariable(arg: 1, scope: !23, type: !19) +// CHECK:STDOUT: !26 = !DILocation(line: 15, column: 5, scope: !23) +// CHECK:STDOUT: !27 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.A.Main", scope: null, file: !1, line: 8, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !28) +// CHECK:STDOUT: !28 = !{!29} +// CHECK:STDOUT: !29 = !DILocalVariable(arg: 1, scope: !27, type: !19) +// CHECK:STDOUT: !30 = !DILocation(line: 8, column: 1, scope: !27) +// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "Op", linkageName: "_COp.68011419f123494e:core.Destroy.Core", scope: null, file: !1, line: 8, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !32) +// CHECK:STDOUT: !32 = !{!33} +// CHECK:STDOUT: !33 = !DILocalVariable(arg: 1, scope: !31, type: !19) +// CHECK:STDOUT: !34 = !DILocation(line: 8, column: 1, scope: !31) +// CHECK:STDOUT: !35 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.B.Main", scope: null, file: !1, line: 13, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !36) +// CHECK:STDOUT: !36 = !{!37} +// CHECK:STDOUT: !37 = !DILocalVariable(arg: 1, scope: !35, type: !19) +// CHECK:STDOUT: !38 = !DILocation(line: 13, column: 1, scope: !35) +// CHECK:STDOUT: !39 = distinct !DISubprogram(name: "Op", linkageName: "_COp.6c3865e9cbd9f6de:core.Destroy.Core", scope: null, file: !1, line: 13, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !40) +// CHECK:STDOUT: !40 = !{!41} +// CHECK:STDOUT: !41 = !DILocalVariable(arg: 1, scope: !39, type: !19) +// CHECK:STDOUT: !42 = !DILocation(line: 13, column: 1, scope: !39) +// CHECK:STDOUT: !43 = distinct !DISubprogram(name: "F__carbon_thunkinst70000035", linkageName: "_CF__carbon_thunkinst70000035.Main", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !44) +// CHECK:STDOUT: !44 = !{!45} +// CHECK:STDOUT: !45 = !DILocalVariable(arg: 1, scope: !43, type: !19) +// CHECK:STDOUT: !46 = !DILocation(line: 19, column: 1, scope: !43) +// CHECK:STDOUT: !47 = distinct !DISubprogram(name: "F__carbon_thunkinst70000050", linkageName: "_CF__carbon_thunkinst70000050.Main", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !48) +// CHECK:STDOUT: !48 = !{!49} +// CHECK:STDOUT: !49 = !DILocalVariable(arg: 1, scope: !47, type: !19) +// CHECK:STDOUT: !50 = !DILocation(line: 19, column: 1, scope: !47) +// CHECK:STDOUT: !51 = distinct !DISubprogram(name: "Run", linkageName: "main", scope: null, file: !1, line: 32, type: !52, spFlags: DISPFlagDefinition, unit: !0) +// CHECK:STDOUT: !52 = !DISubroutineType(types: !53) +// CHECK:STDOUT: !53 = !{!54} +// CHECK:STDOUT: !54 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !55 = !DILocation(line: 33, column: 3, scope: !51) +// CHECK:STDOUT: !56 = !DILocation(line: 32, column: 1, scope: !51) +// CHECK:STDOUT: !57 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main.3e1f7ed08cd9ee58", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !58) +// CHECK:STDOUT: !58 = !{!59} +// CHECK:STDOUT: !59 = !DILocalVariable(arg: 1, scope: !57, type: !19) +// CHECK:STDOUT: !60 = !DILocation(line: 20, column: 3, scope: !57) +// CHECK:STDOUT: !61 = !DILocation(line: 19, column: 1, scope: !57) +// CHECK:STDOUT: !62 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main.bd1b6d59f703c190", scope: null, file: !1, line: 19, type: !17, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !63) +// CHECK:STDOUT: !63 = !{!64} +// CHECK:STDOUT: !64 = !DILocalVariable(arg: 1, scope: !62, type: !19) +// CHECK:STDOUT: !65 = !DILocation(line: 20, column: 3, scope: !62) +// CHECK:STDOUT: !66 = !DILocation(line: 19, column: 1, scope: !62) +// CHECK:STDOUT: