diff --git a/integration_tests/BUILD b/integration_tests/BUILD index f858ded72d87..03dd77d1600b 100644 --- a/integration_tests/BUILD +++ b/integration_tests/BUILD @@ -16,3 +16,8 @@ carbon_binary( name = "make_unique_test", srcs = ["make_unique_test.carbon"], ) + +carbon_binary( + name = "callback_test", + srcs = ["callback_test.carbon"], +) diff --git a/integration_tests/callback_test.carbon b/integration_tests/callback_test.carbon new file mode 100644 index 000000000000..0485dc6587ff --- /dev/null +++ b/integration_tests/callback_test.carbon @@ -0,0 +1,17 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +import Cpp library ""; + +class C { + fn F(unused self: Self, i: i32) -> i32 { + return i + 1; + } +} + +fn Run() -> i32 { + var c: C = {}; + var n: i32 = Cpp.std.invoke(Cpp.std.bind(C.F, ref c, 1)); + return if n == 2 then 0 else 1; +} diff --git a/toolchain/check/convert.cpp b/toolchain/check/convert.cpp index 71eaa6fbe8a8..4fca2e030c8a 100644 --- a/toolchain/check/convert.cpp +++ b/toolchain/check/convert.cpp @@ -503,14 +503,12 @@ static auto ConvertTupleToArray(Context& context, SemIR::TupleType tuple_type, } // Performs a conversion from a function to a C++ function pointer type. -static auto ConvertFunctionToCppPointer(Context& context, SemIR::LocId loc_id, - SemIR::FunctionType src_type, - SemIR::CppFunctionPointerType dest_type, - SemIR::InstId value_id, - ConversionTarget target) - -> SemIR::InstId { +static auto ConvertFunctionToCppPointer( + Context& context, SemIR::LocId loc_id, SemIR::FunctionType src_type, + SemIR::CppFunctionPointerType target_type, SemIR::InstId value_id, + ConversionTarget target) -> SemIR::InstId { if (!ExportFunctionToCppPointerConversion(context, value_id, src_type, - dest_type, target.diagnose)) { + target_type, target.diagnose)) { return SemIR::ErrorInst::InstId; } diff --git a/toolchain/check/cpp/export.cpp b/toolchain/check/cpp/export.cpp index 356810801c15..41fce49d76e6 100644 --- a/toolchain/check/cpp/export.cpp +++ b/toolchain/check/cpp/export.cpp @@ -24,6 +24,7 @@ #include "toolchain/check/pattern.h" #include "toolchain/check/thunk.h" #include "toolchain/check/type.h" +#include "toolchain/diagnostics/format_providers.h" #include "toolchain/sem_ir/generic.h" #include "toolchain/sem_ir/mangler.h" #include "toolchain/sem_ir/pattern.h" @@ -165,6 +166,14 @@ auto ExportNameScopeToCpp(Context& context, SemIR::LocId loc_id, } } + if (auto* record_decl = llvm::dyn_cast(decl_context)) { + // We can't use a class as a name scope until it's complete, so we need to + // ensure it's complete here. + context.clang_sema().RequireCompleteType( + GetCppLocation(context, loc_id), + context.ast_context().getCanonicalTagType(record_decl), + clang::diag::err_incomplete_member_access); + } return decl_context; } @@ -1591,27 +1600,39 @@ auto ExportFunctionToCppPointerConversion( CARBON_CHECK(!src_clang_decl->isTemplateDecl(), "can't form a pointer to a template"); - const auto* exported_fn_type = - src_clang_decl->getFunctionType() - ->getAsCanonical(); + clang::QualType src_fn_type(src_clang_decl->getFunctionType(), /*Quals=*/0); + clang::QualType src_ptr_type; + if (const auto* src_method_decl = + llvm::dyn_cast(src_clang_decl); + src_method_decl != nullptr && src_method_decl->isInstance()) { + src_ptr_type = context.ast_context().getMemberPointerType( + src_fn_type, std::nullopt, src_method_decl->getParent()); + } else { + src_ptr_type = context.ast_context().getPointerType(src_fn_type); + } + + // TODO: consider directly diagnosing things like function pointer/method + // pointer mismatch, or parent type mismatch, rather than deferring them to + // the general pointer type mismatch diagnostic below. + auto dest_function_ptr_type_info = context.clang_function_pointer_types().Get(dest_type.clang_type_id); - const auto* dest_fn_type = - dest_function_ptr_type_info.clang_type->getPointeeType() - ->getAsCanonical(); + clang::QualType dest_ptr_type(dest_function_ptr_type_info.clang_type, + /*Quals=*/0); - if (exported_fn_type != dest_fn_type) { + if (src_ptr_type.getCanonicalType() != dest_ptr_type.getCanonicalType()) { if (diagnose) { auto function = context.functions().Get(src_type.function_id); - CARBON_DIAGNOSTIC(ExportedFunctionPtrTypeMismatch, Error, - "can't convert exported function type to `{0}`", - CppType); + CARBON_DIAGNOSTIC( + ExportedFunctionPtrTypeMismatch, Error, + "can't convert exported {0:member |}function pointer to `{1}`", + Diagnostics::BoolAsSelect, CppType); CARBON_DIAGNOSTIC(ExportedFromFunction, Note, - "function exported with type `{0}`", CppType); + "function exported with pointer type `{0}`", CppType); context.emitter() - .Build(src_id, ExportedFunctionPtrTypeMismatch, dest_fn_type) - .Note(function.first_decl_id(), ExportedFromFunction, - exported_fn_type) + .Build(src_id, ExportedFunctionPtrTypeMismatch, + src_ptr_type->isMemberFunctionPointerType(), dest_ptr_type) + .Note(function.first_decl_id(), ExportedFromFunction, src_ptr_type) .Emit(); } return false; diff --git a/toolchain/check/cpp/import.cpp b/toolchain/check/cpp/import.cpp index 772fc49694d8..d1de4b4e7334 100644 --- a/toolchain/check/cpp/import.cpp +++ b/toolchain/check/cpp/import.cpp @@ -1325,7 +1325,8 @@ static auto MapTagType(Context& context, const clang::TagType& type) static auto MapFunctionPointerType(Context& context, SemIR::LocId /*loc_id*/, clang::QualType type) -> TypeExpr { - CARBON_CHECK(type->isFunctionPointerType()); + CARBON_CHECK(type->isFunctionPointerType() || + type->isMemberFunctionPointerType()); auto clang_type_id = context.clang_function_pointer_types().Lookup( type.getCanonicalType().getTypePtr()); @@ -1350,7 +1351,7 @@ static auto MapNonWrapperType(Context& context, SemIR::LocId loc_id, return MapTagType(context, *tag_type); } - if (type->isFunctionPointerType()) { + if (type->isFunctionPointerType() || type->isMemberFunctionPointerType()) { return MapFunctionPointerType(context, loc_id, type); } @@ -2105,7 +2106,8 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id, static auto ImportFunctionPointer(Context& context, const clang::Type* pointer_type) -> SemIR::InstId { - CARBON_CHECK(pointer_type->isFunctionPointerType()); + CARBON_CHECK(pointer_type->isFunctionPointerType() || + pointer_type->isMemberFunctionPointerType()); // Allocate an ID for the function pointer type and return it. pointer_type = clang::QualType(pointer_type, /*Quals=*/0) .getCanonicalType() @@ -2130,6 +2132,10 @@ auto ImportFunctionPointerInvoke( if (info.decl_id.has_value()) { return info; } + if (info.clang_type->isMemberFunctionPointerType()) { + context.TODO(loc_id, + "invoking a C++ member function pointer is unsupported"); + } Diagnostics::AnnotationScope annotate_diagnostics( &context.emitter(), [&](auto& builder) { CARBON_DIAGNOSTIC(InCppFunctionPointerThunk, Note, @@ -2183,7 +2189,7 @@ static auto PushDecl(Context& context, SemIR::ClangDeclKey decl, static auto PushType(Context& context, clang::QualType type, ImportWorklist& worklist) -> void { while (true) { - if (type->isFunctionPointerType()) { + if (type->isFunctionPointerType() || type->isMemberFunctionPointerType()) { const clang::Type* type_ptr = type.getCanonicalType().getTypePtr(); if (!IsImported(context, type_ptr)) { worklist.push_back({.key = type_ptr, .added_dependencies = false}); @@ -2418,7 +2424,8 @@ static auto ImportAfterDependencies(Context& context, SemIR::LocId loc_id, return SemIR::ErrorInst::InstId; } case CARBON_KIND(const clang::Type* type): { - if (type->isFunctionPointerType()) { + if (type->isFunctionPointerType() || + type->isMemberFunctionPointerType()) { return ImportFunctionPointer(context, type); } diff --git a/toolchain/check/cpp/type_mapping.cpp b/toolchain/check/cpp/type_mapping.cpp index e50037c517ff..143b3d04c522 100644 --- a/toolchain/check/cpp/type_mapping.cpp +++ b/toolchain/check/cpp/type_mapping.cpp @@ -293,8 +293,14 @@ static auto TryMapType(Context& context, SemIR::TypeId type_id) return clang::QualType(); } clang::QualType clang_fn_type(clang_decl->getFunctionType(), /*Quals=*/0); - clang::QualType clang_ptr_type = - context.ast_context().getPointerType(clang_fn_type); + clang::QualType clang_ptr_type; + if (const auto* method_decl = + llvm::dyn_cast(clang_decl)) { + clang_ptr_type = context.ast_context().getMemberPointerType( + clang_fn_type, std::nullopt, method_decl->getParent()); + } else { + clang_ptr_type = context.ast_context().getPointerType(clang_fn_type); + } return context.ast_context().getAttributedType( clang::attr::TypeNonNull, clang_ptr_type, clang_ptr_type); } diff --git a/toolchain/check/testdata/interop/cpp/function/import/function_ptr.carbon b/toolchain/check/testdata/interop/cpp/function/import/function_ptr.carbon index 306b15cf854c..328ec0e9765e 100644 --- a/toolchain/check/testdata/interop/cpp/function/import/function_ptr.carbon +++ b/toolchain/check/testdata/interop/cpp/function/import/function_ptr.carbon @@ -197,16 +197,29 @@ using MyCallbackType = void(*)(int); fn MyCallback(arg: i32) -> i32; fn F() { - // CHECK:STDERR: fail_convert_type_mismatch.carbon:[[@LINE+7]]:43: error: can't convert exported function type to `void (int)` [ExportedFunctionPtrTypeMismatch] + // CHECK:STDERR: fail_convert_type_mismatch.carbon:[[@LINE+7]]:43: error: can't convert exported function pointer to `void (*)(int)` [ExportedFunctionPtrTypeMismatch] // CHECK:STDERR: var unused fn_ptr: Cpp.MyCallbackType = MyCallback; // CHECK:STDERR: ^~~~~~~~~~ - // CHECK:STDERR: fail_convert_type_mismatch.carbon:[[@LINE-6]]:1: note: function exported with type `int (int)` [ExportedFromFunction] + // CHECK:STDERR: fail_convert_type_mismatch.carbon:[[@LINE-6]]:1: note: function exported with pointer type `int (*)(int)` [ExportedFromFunction] // CHECK:STDERR: fn MyCallback(arg: i32) -> i32; // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CHECK:STDERR: var unused fn_ptr: Cpp.MyCallbackType = MyCallback; } +// --- static_member_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "simple_callback.h"; + +class C { + fn MyCallback(arg: f32) -> i32; +} + +fn F() { + var unused fn_ptr: Cpp.CallbackType = C.MyCallback; +} + // CHECK:STDOUT: --- relay_fn_ptr.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants { diff --git a/toolchain/check/testdata/interop/cpp/function/import/method_ptr.carbon b/toolchain/check/testdata/interop/cpp/function/import/method_ptr.carbon new file mode 100644 index 000000000000..145b2337f2f6 --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/function/import/method_ptr.carbon @@ -0,0 +1,554 @@ +// 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/full.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/import/method_ptr.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/function/import/method_ptr.carbon + +// --- method_ptr.h + +class C { + public: + void Method(int i) const; +}; +using MethodPtrType = void(C::*)() const; + +auto GetMethodPtr() -> MethodPtrType; +void TakeMethodPtr(MethodPtrType); + +template +void TakeGenericMethodPtr(void(C::* ptr)() const); + +// --- relay_method_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "method_ptr.h"; + +fn G() { + //@dump-sem-ir-begin + Cpp.TakeMethodPtr(Cpp.GetMethodPtr()); + //@dump-sem-ir-end +} + +// --- convert_method_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp; + +class C { + fn Method(self); +} + +inline Cpp '''c++ +using MethodPtrType = void(Carbon::C::*)() const; +'''; + +fn G() { + //@dump-sem-ir-begin + var unused ptr: Cpp.MethodPtrType = C.Method; + //@dump-sem-ir-end +} + +// --- pass_method_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "method_ptr.h"; + +class C { + fn Method(self); +} + +fn F() { + //@dump-sem-ir-begin + Cpp.TakeGenericMethodPtr(C.Method); + //@dump-sem-ir-end +} + +// --- fail_todo_call_method_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "method_ptr.h"; + +fn F(c: Cpp.C) { + // CHECK:STDERR: fail_todo_call_method_ptr.carbon:[[@LINE+18]]:3: error: member name of type `` in compound member access is not an instance member or an interface member [CompoundMemberAccessDoesNotUseBase] + // CHECK:STDERR: c.(Cpp.GetMethodPtr())(42); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_call_method_ptr.carbon:[[@LINE+14]]:3: error: semantics TODO: `invoking a C++ member function pointer is unsupported` [SemanticsTodo] + // CHECK:STDERR: c.(Cpp.GetMethodPtr())(42); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: error: called object type 'void (C::*)() const' is not a function or function pointer [CppInteropParseError] + // CHECK:STDERR: fail_todo_call_method_ptr.carbon:[[@LINE+9]]:3: note: in thunk for C++ function pointer type used here [InCppFunctionPointerThunk] + // CHECK:STDERR: c.(Cpp.GetMethodPtr())(42); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + // CHECK:STDERR: fail_todo_call_method_ptr.carbon:[[@LINE+5]]:3: error: 1 argument passed to function expecting 0 arguments [CallArgCountMismatch] + // CHECK:STDERR: c.(Cpp.GetMethodPtr())(42); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_call_method_ptr.carbon: note: calling function declared here [InCallToEntity] + // CHECK:STDERR: + c.(Cpp.GetMethodPtr())(42); +} + +// --- fail_pass_function_for_method.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "method_ptr.h"; + +fn F(ref c: Cpp.C); + +fn G() { + // CHECK:STDERR: fail_pass_function_for_method.carbon:[[@LINE+7]]:39: error: can't convert exported function pointer to `void (C::*)(void) const` [ExportedFunctionPtrTypeMismatch] + // CHECK:STDERR: var unused ptr: Cpp.MethodPtrType = F; + // CHECK:STDERR: ^ + // CHECK:STDERR: fail_pass_function_for_method.carbon:[[@LINE-6]]:1: note: function exported with pointer type `void (*)(class C &)` [ExportedFromFunction] + // CHECK:STDERR: fn F(ref c: Cpp.C); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var unused ptr: Cpp.MethodPtrType = F; +} + +// --- fail_wrong_parent_type.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "method_ptr.h"; + +class C { + fn Method(self); +} + +fn F() { + // CHECK:STDERR: fail_wrong_parent_type.carbon:[[@LINE+7]]:39: error: can't convert exported member function pointer to `void (C::*)(void) const` [ExportedFunctionPtrTypeMismatch] + // CHECK:STDERR: var unused ptr: Cpp.MethodPtrType = C.Method; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_wrong_parent_type.carbon:[[@LINE-7]]:3: note: function exported with pointer type `void (Carbon::C::*)(void) const` [ExportedFromFunction] + // CHECK:STDERR: fn Method(self); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var unused ptr: Cpp.MethodPtrType = C.Method; +} + +// --- fail_type_mismatch.carbon +library "[[@TEST_NAME]]"; + +import Cpp; + +class C { + fn Method(self, i: i32); +} + +inline Cpp '''c++ +using MethodPtrType = void(Carbon::C::*)(float) const; +'''; + +fn G() { + //@dump-sem-ir-begin + // CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE+7]]:39: error: can't convert exported member function pointer to `void (Carbon::C::*)(float) const` [ExportedFunctionPtrTypeMismatch] + // CHECK:STDERR: var unused ptr: Cpp.MethodPtrType = C.Method; + // CHECK:STDERR: ^~~~~~~~ + // CHECK:STDERR: fail_type_mismatch.carbon:[[@LINE-12]]:3: note: function exported with pointer type `void (Carbon::C::*)(int) const` [ExportedFromFunction] + // CHECK:STDERR: fn Method(self, i: i32); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + var unused ptr: Cpp.MethodPtrType = C.Method; + //@dump-sem-ir-end +} + +// CHECK:STDOUT: --- relay_method_ptr.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %TakeMethodPtr.cpp_overload_set.type: type = cpp_overload_set_type @TakeMethodPtr.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeMethodPtr.cpp_overload_set.value: %TakeMethodPtr.cpp_overload_set.type = cpp_overload_set_value @TakeMethodPtr.cpp_overload_set [concrete] +// CHECK:STDOUT: %GetMethodPtr.cpp_overload_set.type: type = cpp_overload_set_type @GetMethodPtr.cpp_overload_set [concrete] +// CHECK:STDOUT: %GetMethodPtr.cpp_overload_set.value: %GetMethodPtr.cpp_overload_set.type = cpp_overload_set_value @GetMethodPtr.cpp_overload_set [concrete] +// CHECK:STDOUT: %.659: type = cpp_fn_ptr_type clang_function_pointer_type7E000000 [concrete] +// CHECK:STDOUT: %pattern_type.4b7: type = pattern_type %.659 [concrete] +// CHECK:STDOUT: %ptr.796: type = ptr_type %.659 [concrete] +// CHECK:STDOUT: %GetMethodPtr__carbon_thunk.type: type = fn_type @GetMethodPtr__carbon_thunk [concrete] +// CHECK:STDOUT: %GetMethodPtr__carbon_thunk: %GetMethodPtr__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: %TakeMethodPtr__carbon_thunk.type: type = fn_type @TakeMethodPtr__carbon_thunk [concrete] +// CHECK:STDOUT: %TakeMethodPtr__carbon_thunk: %TakeMethodPtr__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.7f5: type = fn_type @Copy.WithSelf.Op.2 [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.416: %Copy.WithSelf.Op.type.7f5 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.bab: = custom_witness (%Copy.WithSelf.Op.416), @Copy [concrete] +// CHECK:STDOUT: %Copy.facet.8df: %Copy.type = facet_value %.659, (%custom_witness.bab) [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.adb: type = fn_type @Copy.WithSelf.Op.1, @Copy.WithSelf(%Copy.facet.8df) [concrete] +// CHECK:STDOUT: %.e6b: type = fn_type_with_self_type %Copy.WithSelf.Op.type.adb, %Copy.facet.8df [concrete] +// CHECK:STDOUT: %self.param_patt.952: %pattern_type.4b7 = ref_param_pattern [concrete] +// CHECK:STDOUT: %self.patt.a35: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt.952 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.type.dfc: type = fn_type @Destroy.WithSelf.SubobjectDestroy.loc7 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.d01: %Destroy.WithSelf.SubobjectDestroy.type.dfc = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.type.ef0: type = fn_type @Destroy.WithSelf.Op.loc7 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.403: %Destroy.WithSelf.Op.type.ef0 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.fbc: type = fn_type @Destroy.WithSelf.SelfDestruct.loc7 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.db3: %Destroy.WithSelf.SelfDestruct.type.fbc = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .TakeMethodPtr = %TakeMethodPtr.cpp_overload_set.value +// CHECK:STDOUT: .GetMethodPtr = %GetMethodPtr.cpp_overload_set.value +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %TakeMethodPtr.cpp_overload_set.value: %TakeMethodPtr.cpp_overload_set.type = cpp_overload_set_value @TakeMethodPtr.cpp_overload_set [concrete = constants.%TakeMethodPtr.cpp_overload_set.value] +// CHECK:STDOUT: %GetMethodPtr.cpp_overload_set.value: %GetMethodPtr.cpp_overload_set.type = cpp_overload_set_value @GetMethodPtr.cpp_overload_set [concrete = constants.%GetMethodPtr.cpp_overload_set.value] +// CHECK:STDOUT: %GetMethodPtr__carbon_thunk.decl: %GetMethodPtr__carbon_thunk.type = fn_decl @GetMethodPtr__carbon_thunk [concrete = constants.%GetMethodPtr__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: %TakeMethodPtr__carbon_thunk.decl: %TakeMethodPtr__carbon_thunk.type = fn_decl @TakeMethodPtr__carbon_thunk [concrete = constants.%TakeMethodPtr__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generated { +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.decl: %Destroy.WithSelf.SubobjectDestroy.type.dfc = fn_decl @Destroy.WithSelf.SubobjectDestroy.loc7 [concrete = constants.%Destroy.WithSelf.SubobjectDestroy.d01] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Destroy.WithSelf.Op.decl: %Destroy.WithSelf.Op.type.ef0 = fn_decl @Destroy.WithSelf.Op.loc7 [concrete = constants.%Destroy.WithSelf.Op.403] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Cpp.ref.loc7_3: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %TakeMethodPtr.ref: %TakeMethodPtr.cpp_overload_set.type = name_ref TakeMethodPtr, imports.%TakeMethodPtr.cpp_overload_set.value [concrete = constants.%TakeMethodPtr.cpp_overload_set.value] +// CHECK:STDOUT: %Cpp.ref.loc7_21: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %GetMethodPtr.ref: %GetMethodPtr.cpp_overload_set.type = name_ref GetMethodPtr, imports.%GetMethodPtr.cpp_overload_set.value [concrete = constants.%GetMethodPtr.cpp_overload_set.value] +// CHECK:STDOUT: %.loc7_38.1: ref %.659 = temporary_storage +// CHECK:STDOUT: %addr.loc7_38: %ptr.796 = addr_of %.loc7_38.1 +// CHECK:STDOUT: %GetMethodPtr__carbon_thunk.call: init %empty_tuple.type = call imports.%GetMethodPtr__carbon_thunk.decl(%addr.loc7_38) +// CHECK:STDOUT: %.loc7_38.2: init %.659 to %.loc7_38.1 = mark_in_place_init %GetMethodPtr__carbon_thunk.call +// CHECK:STDOUT: %.loc7_38.3: ref %.659 = temporary %.loc7_38.1, %.loc7_38.2 +// CHECK:STDOUT: %.loc7_38.4: %.659 = acquire_value %.loc7_38.3 +// CHECK:STDOUT: +// CHECK:STDOUT: %impl.elem0: %.e6b = impl_witness_access constants.%custom_witness.bab, element0 [concrete = constants.%Copy.WithSelf.Op.416] +// CHECK:STDOUT: %bound_method: = bound_method %.loc7_38.4, %impl.elem0 +// CHECK:STDOUT: %Copy.WithSelf.Op.call: init %.659 = call %bound_method(%.loc7_38.4) +// CHECK:STDOUT: %.loc7_38.5: ref %.659 = temporary_storage +// CHECK:STDOUT: %.loc7_38.6: ref %.659 = temporary %.loc7_38.5, %Copy.WithSelf.Op.call +// CHECK:STDOUT: %addr.loc7_39: %ptr.796 = addr_of %.loc7_38.6 +// CHECK:STDOUT: %TakeMethodPtr__carbon_thunk.call: init %empty_tuple.type = call imports.%TakeMethodPtr__carbon_thunk.decl(%addr.loc7_39) +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.bound.loc7_38.1: = bound_method %.loc7_38.6, constants.%Destroy.WithSelf.SelfDestruct.db3 +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call.loc7_38.1: init %empty_tuple.type = call %Destroy.WithSelf.SelfDestruct.bound.loc7_38.1(%.loc7_38.6) +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.bound.loc7_38.2: = bound_method %.loc7_38.3, constants.%Destroy.WithSelf.SelfDestruct.db3 +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call.loc7_38.2: init %empty_tuple.type = call %Destroy.WithSelf.SelfDestruct.bound.loc7_38.2(%.loc7_38.3) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SubobjectDestroy.loc7(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc7(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SelfDestruct.loc7(%self.param: ref %.659) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Destroy.WithSelf.Op.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.Op.decl(%self.param) +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.SubobjectDestroy.decl(%self.param) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- convert_method_ptr.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %C.Method.type: type = fn_type @C.Method [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %C.Method: %C.Method.type = struct_value () [concrete] +// CHECK:STDOUT: %.659: type = cpp_fn_ptr_type clang_function_pointer_type41000000 [concrete] +// CHECK:STDOUT: %pattern_type.4b7: type = pattern_type %.659 [concrete] +// CHECK:STDOUT: %ptr.patt: %pattern_type.4b7 = ref_binding_pattern ptr [concrete] +// CHECK:STDOUT: %ptr.var_patt: %pattern_type.4b7 = var_pattern %ptr.patt [concrete] +// CHECK:STDOUT: %.b35: %.659 = cpp_addr_of_fn %C.Method, @C.Method [concrete] +// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.7f5: type = fn_type @Copy.WithSelf.Op.2 [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.416: %Copy.WithSelf.Op.type.7f5 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.bab: = custom_witness (%Copy.WithSelf.Op.416), @Copy [concrete] +// CHECK:STDOUT: %Copy.facet.8df: %Copy.type = facet_value %.659, (%custom_witness.bab) [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.adb: type = fn_type @Copy.WithSelf.Op.1, @Copy.WithSelf(%Copy.facet.8df) [concrete] +// CHECK:STDOUT: %.e6b: type = fn_type_with_self_type %Copy.WithSelf.Op.type.adb, %Copy.facet.8df [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.bound: = bound_method %.b35, %Copy.WithSelf.Op.416 [concrete] +// CHECK:STDOUT: %self.param_patt.952: %pattern_type.4b7 = ref_param_pattern [concrete] +// CHECK:STDOUT: %self.patt.a35: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt.952 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3: type = fn_type @Destroy.WithSelf.SubobjectDestroy.loc15 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.d01daf.3: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.type.ef016f.3: type = fn_type @Destroy.WithSelf.Op.loc15 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.403171.3: %Destroy.WithSelf.Op.type.ef016f.3 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3: type = fn_type @Destroy.WithSelf.SelfDestruct.loc15 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.db3fdb.3: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3 = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .MethodPtrType = constants.%.659 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generated { +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.decl.763c71.3: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3 = fn_decl @Destroy.WithSelf.SubobjectDestroy.loc15 [concrete = constants.%Destroy.WithSelf.SubobjectDestroy.d01daf.3] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Destroy.WithSelf.Op.decl.5f94cf.3: %Destroy.WithSelf.Op.type.ef016f.3 = fn_decl @Destroy.WithSelf.Op.loc15 [concrete = constants.%Destroy.WithSelf.Op.403171.3] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %ptr.var: ref %.659 = var_storage %ptr.var_patt +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %Method.ref: %C.Method.type = name_ref Method, @C.%C.Method.decl [concrete = constants.%C.Method] +// CHECK:STDOUT: %.loc15_3.1: %.659 = cpp_addr_of_fn %Method.ref, @C.Method [concrete = constants.%.b35] +// CHECK:STDOUT: %.loc15_3.2: %.659 = converted %Method.ref, %.loc15_3.1 [concrete = constants.%.b35] +// CHECK:STDOUT: +// CHECK:STDOUT: %impl.elem0: %.e6b = impl_witness_access constants.%custom_witness.bab, element0 [concrete = constants.%Copy.WithSelf.Op.416] +// CHECK:STDOUT: %bound_method: = bound_method %.loc15_3.2, %impl.elem0 [concrete = constants.%Copy.WithSelf.Op.bound] +// CHECK:STDOUT: %Copy.WithSelf.Op.call: init %.659 = call %bound_method(%.loc15_3.2) [concrete = constants.%.b35] +// CHECK:STDOUT: assign %ptr.var, %Copy.WithSelf.Op.call +// CHECK:STDOUT: %.loc15_22: type = splice_block %MethodPtrType.ref [concrete = constants.%.659] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %MethodPtrType.ref: type = name_ref MethodPtrType, constants.%.659 [concrete = constants.%.659] +// CHECK:STDOUT: } +// CHECK:STDOUT: %ptr: ref %.659 = wrapper_binding ptr, %ptr.var +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %ptr.patt: %pattern_type.4b7 = ref_binding_pattern ptr [concrete = constants.%ptr.patt] +// CHECK:STDOUT: %ptr.var_patt: %pattern_type.4b7 = var_pattern %ptr.patt [concrete = constants.%ptr.var_patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.bound: = bound_method %ptr.var, constants.%Destroy.WithSelf.SelfDestruct.db3fdb.3 +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call: init %empty_tuple.type = call %Destroy.WithSelf.SelfDestruct.bound(%ptr.var) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @C.Method__carbon_thunk(%self.param: ref %C) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: +// CHECK:STDOUT: %.loc15: %C = acquire_value %self.param +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SubobjectDestroy.loc15(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc15(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SelfDestruct.loc15(%self.param: ref %.659) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Destroy.WithSelf.Op.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.Op.decl.5f94cf.3(%self.param) +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.SubobjectDestroy.decl.763c71.3(%self.param) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- pass_method_ptr.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %C.Method.type: type = fn_type @C.Method [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %C.Method: %C.Method.type = struct_value () [concrete] +// CHECK:STDOUT: %TakeGenericMethodPtr.cpp_overload_set.type: type = cpp_overload_set_type @TakeGenericMethodPtr.cpp_overload_set [concrete] +// CHECK:STDOUT: %TakeGenericMethodPtr.cpp_overload_set.value: %TakeGenericMethodPtr.cpp_overload_set.type = cpp_overload_set_value @TakeGenericMethodPtr.cpp_overload_set [concrete] +// CHECK:STDOUT: %.659: type = cpp_fn_ptr_type clang_function_pointer_type61000000 [concrete] +// CHECK:STDOUT: %pattern_type.4b7: type = pattern_type %.659 [concrete] +// CHECK:STDOUT: %ptr.796: type = ptr_type %.659 [concrete] +// CHECK:STDOUT: %TakeGenericMethodPtr__carbon_thunk.type: type = fn_type @TakeGenericMethodPtr__carbon_thunk [concrete] +// CHECK:STDOUT: %TakeGenericMethodPtr__carbon_thunk: %TakeGenericMethodPtr__carbon_thunk.type = struct_value () [concrete] +// CHECK:STDOUT: %.b35: %.659 = cpp_addr_of_fn %C.Method, @C.Method [concrete] +// CHECK:STDOUT: %Copy.type: type = facet_type <@Copy> [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.7f5: type = fn_type @Copy.WithSelf.Op.2 [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.416: %Copy.WithSelf.Op.type.7f5 = struct_value () [concrete] +// CHECK:STDOUT: %custom_witness.bab: = custom_witness (%Copy.WithSelf.Op.416), @Copy [concrete] +// CHECK:STDOUT: %Copy.facet.8df: %Copy.type = facet_value %.659, (%custom_witness.bab) [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.type.adb: type = fn_type @Copy.WithSelf.Op.1, @Copy.WithSelf(%Copy.facet.8df) [concrete] +// CHECK:STDOUT: %.e6b: type = fn_type_with_self_type %Copy.WithSelf.Op.type.adb, %Copy.facet.8df [concrete] +// CHECK:STDOUT: %Copy.WithSelf.Op.bound: = bound_method %.b35, %Copy.WithSelf.Op.416 [concrete] +// CHECK:STDOUT: %.fc1: ref %.659 = temporary invalid, %.b35 [concrete] +// CHECK:STDOUT: %addr: %ptr.796 = addr_of %.fc1 [concrete] +// CHECK:STDOUT: %self.param_patt.952: %pattern_type.4b7 = ref_param_pattern [concrete] +// CHECK:STDOUT: %self.patt.a35: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt.952 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3: type = fn_type @Destroy.WithSelf.SubobjectDestroy.loc11 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.d01daf.3: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.type.ef016f.3: type = fn_type @Destroy.WithSelf.Op.loc11 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.403171.3: %Destroy.WithSelf.Op.type.ef016f.3 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3: type = fn_type @Destroy.WithSelf.SelfDestruct.loc11 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.db3fdb.3: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.bound: = bound_method %.fc1, %Destroy.WithSelf.SelfDestruct.db3fdb.3 [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .TakeGenericMethodPtr = %TakeGenericMethodPtr.cpp_overload_set.value +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: %TakeGenericMethodPtr.cpp_overload_set.value: %TakeGenericMethodPtr.cpp_overload_set.type = cpp_overload_set_value @TakeGenericMethodPtr.cpp_overload_set [concrete = constants.%TakeGenericMethodPtr.cpp_overload_set.value] +// CHECK:STDOUT: %TakeGenericMethodPtr__carbon_thunk.decl: %TakeGenericMethodPtr__carbon_thunk.type = fn_decl @TakeGenericMethodPtr__carbon_thunk [concrete = constants.%TakeGenericMethodPtr__carbon_thunk] { +// CHECK:STDOUT: +// CHECK:STDOUT: } { +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generated { +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.decl.763c71.3: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3 = fn_decl @Destroy.WithSelf.SubobjectDestroy.loc11 [concrete = constants.%Destroy.WithSelf.SubobjectDestroy.d01daf.3] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Destroy.WithSelf.Op.decl.5f94cf.3: %Destroy.WithSelf.Op.type.ef016f.3 = fn_decl @Destroy.WithSelf.Op.loc11 [concrete = constants.%Destroy.WithSelf.Op.403171.3] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// 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: %TakeGenericMethodPtr.ref: %TakeGenericMethodPtr.cpp_overload_set.type = name_ref TakeGenericMethodPtr, imports.%TakeGenericMethodPtr.cpp_overload_set.value [concrete = constants.%TakeGenericMethodPtr.cpp_overload_set.value] +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %Method.ref: %C.Method.type = name_ref Method, @C.%C.Method.decl [concrete = constants.%C.Method] +// CHECK:STDOUT: %.loc11_29.1: %.659 = cpp_addr_of_fn %Method.ref, @C.Method [concrete = constants.%.b35] +// CHECK:STDOUT: %.loc11_29.2: %.659 = converted %Method.ref, %.loc11_29.1 [concrete = constants.%.b35] +// CHECK:STDOUT: +// CHECK:STDOUT: %impl.elem0: %.e6b = impl_witness_access constants.%custom_witness.bab, element0 [concrete = constants.%Copy.WithSelf.Op.416] +// CHECK:STDOUT: %bound_method: = bound_method %.loc11_29.2, %impl.elem0 [concrete = constants.%Copy.WithSelf.Op.bound] +// CHECK:STDOUT: %Copy.WithSelf.Op.call: init %.659 = call %bound_method(%.loc11_29.2) [concrete = constants.%.b35] +// CHECK:STDOUT: %.loc11_29.3: ref %.659 = temporary_storage +// CHECK:STDOUT: %.loc11_29.4: ref %.659 = temporary %.loc11_29.3, %Copy.WithSelf.Op.call [concrete = constants.%.fc1] +// CHECK:STDOUT: %addr: %ptr.796 = addr_of %.loc11_29.4 [concrete = constants.%addr] +// CHECK:STDOUT: %TakeGenericMethodPtr__carbon_thunk.call: init %empty_tuple.type = call imports.%TakeGenericMethodPtr__carbon_thunk.decl(%addr) +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call: init %empty_tuple.type = call constants.%Destroy.WithSelf.SelfDestruct.bound(constants.%.fc1) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SubobjectDestroy.loc11(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc11(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SelfDestruct.loc11(%self.param: ref %.659) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Destroy.WithSelf.Op.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.Op.decl.5f94cf.3(%self.param) +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.SubobjectDestroy.decl.763c71.3(%self.param) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: --- fail_type_mismatch.carbon +// CHECK:STDOUT: +// CHECK:STDOUT: constants { +// CHECK:STDOUT: type: type = facet_type [concrete] +// CHECK:STDOUT: %C: type = class_type @C [concrete] +// CHECK:STDOUT: %int_32: Core.IntLiteral = int_value 32 [concrete] +// CHECK:STDOUT: %empty_tuple.type: type = tuple_type () [concrete] +// CHECK:STDOUT: %i32: type = class_type @Int, @Int(%int_32) [concrete] +// CHECK:STDOUT: %C.Method.type: type = fn_type @C.Method [concrete] +// CHECK:STDOUT: %C.Method: %C.Method.type = struct_value () [concrete] +// CHECK:STDOUT: %.659: type = cpp_fn_ptr_type clang_function_pointer_type69000000 [concrete] +// CHECK:STDOUT: %pattern_type.4b7: type = pattern_type %.659 [concrete] +// CHECK:STDOUT: %ptr.patt: %pattern_type.4b7 = ref_binding_pattern ptr [concrete] +// CHECK:STDOUT: %ptr.var_patt: %pattern_type.4b7 = var_pattern %ptr.patt [concrete] +// CHECK:STDOUT: %self.param_patt.952: %pattern_type.4b7 = ref_param_pattern [concrete] +// CHECK:STDOUT: %self.patt.a35: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt.952 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3: type = fn_type @Destroy.WithSelf.SubobjectDestroy.loc22 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.d01daf.3: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.type.ef016f.3: type = fn_type @Destroy.WithSelf.Op.loc22 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.Op.403171.3: %Destroy.WithSelf.Op.type.ef016f.3 = struct_value () [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3: type = fn_type @Destroy.WithSelf.SelfDestruct.loc22 [concrete] +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.db3fdb.3: %Destroy.WithSelf.SelfDestruct.type.fbceb5.3 = struct_value () [concrete] +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: imports { +// CHECK:STDOUT: %Cpp: = namespace file.%Cpp.import_cpp, [concrete] { +// CHECK:STDOUT: .MethodPtrType = constants.%.659 +// CHECK:STDOUT: import Cpp//... +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: generated { +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.decl.763c71.3: %Destroy.WithSelf.SubobjectDestroy.type.dfcbdb.3 = fn_decl @Destroy.WithSelf.SubobjectDestroy.loc22 [concrete = constants.%Destroy.WithSelf.SubobjectDestroy.d01daf.3] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: %Destroy.WithSelf.Op.decl.5f94cf.3: %Destroy.WithSelf.Op.type.ef016f.3 = fn_decl @Destroy.WithSelf.Op.loc22 [concrete = constants.%Destroy.WithSelf.Op.403171.3] { +// CHECK:STDOUT: %self.param_patt: %pattern_type.4b7 = ref_param_pattern [concrete = constants.%self.param_patt.952] +// CHECK:STDOUT: %self.patt: %pattern_type.4b7 = wrapper_binding_pattern self, %self.param_patt [concrete = constants.%self.patt.a35] +// CHECK:STDOUT: } { +// CHECK:STDOUT: %self.param: ref %.659 = ref_param call_param0 +// CHECK:STDOUT: %self: ref %.659 = wrapper_binding self, %self.param +// CHECK:STDOUT: } +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @G() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %ptr.var: ref %.659 = var_storage %ptr.var_patt +// CHECK:STDOUT: %C.ref: type = name_ref C, file.%C.decl [concrete = constants.%C] +// CHECK:STDOUT: %Method.ref: %C.Method.type = name_ref Method, @C.%C.Method.decl [concrete = constants.%C.Method] +// CHECK:STDOUT: assign %ptr.var, +// CHECK:STDOUT: %.loc22: type = splice_block %MethodPtrType.ref [concrete = constants.%.659] { +// CHECK:STDOUT: %Cpp.ref: = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp] +// CHECK:STDOUT: %MethodPtrType.ref: type = name_ref MethodPtrType, constants.%.659 [concrete = constants.%.659] +// CHECK:STDOUT: } +// CHECK:STDOUT: %ptr: ref %.659 = wrapper_binding ptr, %ptr.var +// CHECK:STDOUT: name_binding_decl { +// CHECK:STDOUT: %ptr.patt: %pattern_type.4b7 = ref_binding_pattern ptr [concrete = constants.%ptr.patt] +// CHECK:STDOUT: %ptr.var_patt: %pattern_type.4b7 = var_pattern %ptr.patt [concrete = constants.%ptr.var_patt] +// CHECK:STDOUT: } +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.bound: = bound_method %ptr.var, constants.%Destroy.WithSelf.SelfDestruct.db3fdb.3 +// CHECK:STDOUT: %Destroy.WithSelf.SelfDestruct.call: init %empty_tuple.type = call %Destroy.WithSelf.SelfDestruct.bound(%ptr.var) +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @C.Method__carbon_thunk(%self.param: ref %C, %_.param: ref %i32) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: +// CHECK:STDOUT: %.loc22_40.1: %C = acquire_value %self.param +// CHECK:STDOUT: %.loc22_40.2: %i32 = acquire_value %_.param +// CHECK:STDOUT: +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SubobjectDestroy.loc22(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.Op.loc22(%self.param: ref %.659) = "no_op"; +// CHECK:STDOUT: +// CHECK:STDOUT: fn @Destroy.WithSelf.SelfDestruct.loc22(%self.param: ref %.659) { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %Destroy.WithSelf.Op.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.Op.decl.5f94cf.3(%self.param) +// CHECK:STDOUT: %Destroy.WithSelf.SubobjectDestroy.call: init %empty_tuple.type = call generated.%Destroy.WithSelf.SubobjectDestroy.decl.763c71.3(%self.param) +// CHECK:STDOUT: return +// CHECK:STDOUT: } +// CHECK:STDOUT: diff --git a/toolchain/lower/testdata/interop/cpp/function/import/method_ptr.carbon b/toolchain/lower/testdata/interop/cpp/function/import/method_ptr.carbon new file mode 100644 index 000000000000..c4a0ad44c44c --- /dev/null +++ b/toolchain/lower/testdata/interop/cpp/function/import/method_ptr.carbon @@ -0,0 +1,401 @@ +// 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/full.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/import/method_ptr.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/function/import/method_ptr.carbon + +// --- method_ptr.h + +class C { + public: + void Method(int i) const; +}; +using MethodPtrType = void(C::*)() const; + +auto GetMethodPtr() -> MethodPtrType; +void TakeMethodPtr(MethodPtrType); + +template +void TakeGenericMethodPtr(void(C::* ptr)() const); + +// --- relay_method_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "method_ptr.h"; + +fn G() { + Cpp.TakeMethodPtr(Cpp.GetMethodPtr()); +} + +// --- convert_method_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp; + +class C { + fn Method(self); +} + +inline Cpp '''c++ +using MethodPtrType = void(Carbon::C::*)() const; +'''; + +fn G() { + var unused ptr: Cpp.MethodPtrType = C.Method; +} + +// --- pass_method_ptr.carbon +library "[[@TEST_NAME]]"; + +import Cpp library "method_ptr.h"; + +class C { + fn Method(self); +} + +fn F() { + Cpp.TakeGenericMethodPtr(C.Method); +} + +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'relay_method_ptr.carbon' +// CHECK:STDOUT: source_filename = "relay_method_ptr.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: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CG.Main() #0 !dbg !11 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc6_38.1.temp = alloca ptr, align 8, !dbg !12 +// CHECK:STDOUT: %.loc6_38.5.temp = alloca ptr, align 8, !dbg !12 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc6_38.1.temp), !dbg !12 +// CHECK:STDOUT: call void @_Z12GetMethodPtrv.carbon_thunk.(ptr %.loc6_38.1.temp), !dbg !12 +// CHECK:STDOUT: %.loc6_38.4 = load ptr, ptr %.loc6_38.1.temp, align 8, !dbg !12 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc6_38.5.temp), !dbg !12 +// CHECK:STDOUT: store ptr %.loc6_38.4, ptr %.loc6_38.5.temp, align 8, !dbg !12 +// CHECK:STDOUT: call void @_Z13TakeMethodPtrM1CKFvvE.carbon_thunk._(ptr %.loc6_38.5.temp), !dbg !13 +// CHECK:STDOUT: call void @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core"(ptr %.loc6_38.5.temp), !dbg !12 +// CHECK:STDOUT: call void @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core"(ptr %.loc6_38.1.temp), !dbg !12 +// CHECK:STDOUT: ret void, !dbg !14 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z12GetMethodPtrv.carbon_thunk.(ptr noundef %return) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %return.addr = alloca ptr, align 8 +// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !22 +// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !22 +// CHECK:STDOUT: %call = call { i64, i64 } @_Z12GetMethodPtrv() +// CHECK:STDOUT: store { i64, i64 } %call, ptr %0, align 8, !tbaa !23 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z13TakeMethodPtrM1CKFvvE.carbon_thunk._(ptr noundef %0) #1 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.addr = alloca ptr, align 8 +// CHECK:STDOUT: %coerce = alloca { i64, i64 }, align 8 +// CHECK:STDOUT: store ptr %0, ptr %.addr, align 8, !tbaa !22 +// CHECK:STDOUT: %1 = load ptr, ptr %.addr, align 8, !tbaa !22 +// CHECK:STDOUT: %2 = load { i64, i64 }, ptr %1, align 8, !tbaa !23 +// CHECK:STDOUT: store { i64, i64 } %2, ptr %coerce, align 8, !tbaa !23 +// CHECK:STDOUT: %3 = getelementptr inbounds nuw { i64, i64 }, ptr %coerce, i32 0, i32 0 +// CHECK:STDOUT: %4 = load i64, ptr %3, align 8 +// CHECK:STDOUT: %5 = getelementptr inbounds nuw { i64, i64 }, ptr %coerce, i32 0, i32 1 +// CHECK:STDOUT: %6 = load i64, ptr %5, align 8 +// CHECK:STDOUT: call void @_Z13TakeMethodPtrM1CKFvvE(i64 %4, i64 %6) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core"(ptr %self) #0 !dbg !15 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !17 +// 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)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: declare { i64, i64 } @_Z12GetMethodPtrv() #3 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z13TakeMethodPtrM1CKFvvE(i64, i64) #3 +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core", { 1, 0 } +// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline 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 #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #3 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!5} +// CHECK:STDOUT: !llvm.module.flags = !{!24, !25, !26, !2, !3} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!29} +// CHECK:STDOUT: +// CHECK:STDOUT: !2 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !3 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !4 = !DIFile(filename: "relay_method_ptr.carbon", directory: "") +// CHECK:STDOUT: !5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !4, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !6 = !{null} +// CHECK:STDOUT: !7 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !9 = !{null, !8} +// CHECK:STDOUT: !10 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !11 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main", scope: null, file: !4, line: 5, type: !7, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !12 = !DILocation(line: 6, column: 21, scope: !11) +// CHECK:STDOUT: !13 = !DILocation(line: 6, column: 3, scope: !11) +// CHECK:STDOUT: !14 = !DILocation(line: 5, column: 1, scope: !11) +// CHECK:STDOUT: !15 = distinct !DISubprogram(name: "SelfDestruct", linkageName: "_CSelfDestruct.659d177172b60c17:core.Destroy.Core", scope: null, file: !4, line: 6, type: !10, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !18) +// CHECK:STDOUT: !16 = !DILocalVariable(arg: 1, scope: !15, type: !8) +// CHECK:STDOUT: !17 = !DILocation(line: 6, column: 21, scope: !15) +// CHECK:STDOUT: !18 = !{!16} +// CHECK:STDOUT: !19 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !20 = !{!"omnipotent char", !19, i64 0} +// CHECK:STDOUT: !21 = !{!"any pointer", !20, i64 0} +// CHECK:STDOUT: !22 = !{!21, !21, i64 0} +// CHECK:STDOUT: !23 = !{!20, !20, i64 0} +// CHECK:STDOUT: !24 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !25 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !26 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !27 = !{!"int", !20, i64 0} +// CHECK:STDOUT: !28 = !{!"__libc_errno", !27, i64 0} +// CHECK:STDOUT: !29 = !{!28, !27, i64 0} +// CHECK:STDOUT: +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'convert_method_ptr.carbon' +// CHECK:STDOUT: source_filename = "convert_method_ptr.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: declare void @_CMethod.C.Main(ptr) +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CG.Main() #0 !dbg !32 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %ptr.var = alloca ptr, align 8, !dbg !33 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ptr.var), !dbg !33 +// CHECK:STDOUT: store ptr @_CMethod.C.Main, ptr %ptr.var, align 8, !dbg !33 +// CHECK:STDOUT: call void @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core"(ptr %ptr.var), !dbg !33 +// CHECK:STDOUT: ret void, !dbg !35 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define weak_odr void @"_C__destroy_thunk:thunk.C.Main"(ptr %self) #1 !dbg !36 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_CSelfDestruct.08d9e38b928ba575: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 @"_CSelfDestruct.cb8adced19392b99:core.Destroy.Core"(ptr %self) #0 !dbg !40 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !42 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_CSelfDestruct.08d9e38b928ba575:core.Destroy.Core"(ptr %self) #0 !dbg !44 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !46 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CMethod__carbon_thunk.C.Main(ptr %self) #0 !dbg !48 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CMethod.C.Main(ptr %self), !dbg !51 +// CHECK:STDOUT: ret void, !dbg !51 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core"(ptr %self) #0 !dbg !53 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !55 +// 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)) #2 +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline nounwind } +// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!31} +// CHECK:STDOUT: !llvm.module.flags = !{!24, !25, !26, !2, !3} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!29} +// CHECK:STDOUT: +// CHECK:STDOUT: !2 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !3 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !6 = !{null} +// CHECK:STDOUT: !7 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !9 = !{null, !8} +// CHECK:STDOUT: !10 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !19 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !20 = !{!"omnipotent char", !19, i64 0} +// CHECK:STDOUT: !24 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !25 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !26 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !27 = !{!"int", !20, i64 0} +// CHECK:STDOUT: !28 = !{!"__libc_errno", !27, i64 0} +// CHECK:STDOUT: !29 = !{!28, !27, i64 0} +// CHECK:STDOUT: !30 = !DIFile(filename: "convert_method_ptr.carbon", directory: "") +// CHECK:STDOUT: !31 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !30, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !32 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main", scope: null, file: !30, line: 13, type: !7, spFlags: DISPFlagDefinition, unit: !31) +// CHECK:STDOUT: !33 = !DILocation(line: 14, column: 3, scope: !32) +// CHECK:STDOUT: !35 = !DILocation(line: 13, column: 1, scope: !32) +// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.C.Main", scope: null, file: !30, line: 5, type: !10, spFlags: DISPFlagDefinition, unit: !31, retainedNodes: !39) +// CHECK:STDOUT: !37 = !DILocalVariable(arg: 1, scope: !36, type: !8) +// CHECK:STDOUT: !38 = !DILocation(line: 5, column: 1, scope: !36) +// CHECK:STDOUT: !39 = !{!37} +// CHECK:STDOUT: !40 = distinct !DISubprogram(name: "SelfDestruct", linkageName: "_CSelfDestruct.cb8adced19392b99:core.Destroy.Core", scope: null, file: !30, line: 5, type: !10, spFlags: DISPFlagDefinition, unit: !31, retainedNodes: !43) +// CHECK:STDOUT: !41 = !DILocalVariable(arg: 1, scope: !40, type: !8) +// CHECK:STDOUT: !42 = !DILocation(line: 5, column: 1, scope: !40) +// CHECK:STDOUT: !43 = !{!41} +// CHECK:STDOUT: !44 = distinct !DISubprogram(name: "SelfDestruct", linkageName: "_CSelfDestruct.08d9e38b928ba575:core.Destroy.Core", scope: null, file: !30, line: 5, type: !10, spFlags: DISPFlagDefinition, unit: !31, retainedNodes: !47) +// CHECK:STDOUT: !45 = !DILocalVariable(arg: 1, scope: !44, type: !8) +// CHECK:STDOUT: !46 = !DILocation(line: 5, column: 1, scope: !44) +// CHECK:STDOUT: !47 = !{!45} +// CHECK:STDOUT: !48 = distinct !DISubprogram(name: "Method__carbon_thunk", linkageName: "_CMethod__carbon_thunk.C.Main", scope: null, file: !30, line: 14, type: !10, spFlags: DISPFlagDefinition, unit: !31, retainedNodes: !52) +// CHECK:STDOUT: !49 = !DILocalVariable(arg: 1, scope: !48, type: !8) +// CHECK:STDOUT: !51 = !DILocation(line: 6, column: 3, scope: !48) +// CHECK:STDOUT: !52 = !{!49} +// CHECK:STDOUT: !53 = distinct !DISubprogram(name: "SelfDestruct", linkageName: "_CSelfDestruct.659d177172b60c17:core.Destroy.Core", scope: null, file: !30, line: 14, type: !10, spFlags: DISPFlagDefinition, unit: !31, retainedNodes: !56) +// CHECK:STDOUT: !54 = !DILocalVariable(arg: 1, scope: !53, type: !8) +// CHECK:STDOUT: !55 = !DILocation(line: 14, column: 3, scope: !53) +// CHECK:STDOUT: !56 = !{!54} +// CHECK:STDOUT: +// CHECK:STDOUT: ; --- +// CHECK:STDOUT: ; ModuleID = 'pass_method_ptr.carbon' +// CHECK:STDOUT: source_filename = "pass_method_ptr.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: @.b35 = internal constant ptr @_CMethod.C.Main +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_CMethod.C.Main(ptr) +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CF.Main() #0 !dbg !59 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc10_29.3.temp = alloca ptr, align 8, !dbg !60 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %.loc10_29.3.temp), !dbg !60 +// CHECK:STDOUT: call void @_Z20TakeGenericMethodPtrIN6Carbon1CEEvMT_KFvvE.carbon_thunk._(ptr @.b35), !dbg !61 +// CHECK:STDOUT: call void @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core"(ptr @.b35), !dbg !60 +// CHECK:STDOUT: ret void, !dbg !62 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define weak_odr void @"_C__destroy_thunk:thunk.C.Main"(ptr %self) #1 !dbg !63 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_CSelfDestruct.08d9e38b928ba575:core.Destroy.Core"(ptr %self), !dbg !65 +// CHECK:STDOUT: ret void, !dbg !65 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_CSelfDestruct.cb8adced19392b99:core.Destroy.Core"(ptr %self) #0 !dbg !67 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !69 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_CSelfDestruct.08d9e38b928ba575:core.Destroy.Core"(ptr %self) #0 !dbg !71 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !73 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CMethod__carbon_thunk.C.Main(ptr %self) #0 !dbg !75 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CMethod.C.Main(ptr %self), !dbg !77 +// CHECK:STDOUT: ret void, !dbg !77 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable +// CHECK:STDOUT: define internal void @_Z20TakeGenericMethodPtrIN6Carbon1CEEvMT_KFvvE.carbon_thunk._(ptr noundef %ptr) #2 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %ptr.addr = alloca ptr, align 8 +// CHECK:STDOUT: %coerce = alloca { i64, i64 }, align 8 +// CHECK:STDOUT: store ptr %ptr, ptr %ptr.addr, align 8, !tbaa !22 +// CHECK:STDOUT: %0 = load ptr, ptr %ptr.addr, align 8, !tbaa !22 +// CHECK:STDOUT: %1 = load { i64, i64 }, ptr %0, align 8, !tbaa !23 +// CHECK:STDOUT: store { i64, i64 } %1, ptr %coerce, align 8, !tbaa !23 +// CHECK:STDOUT: %2 = getelementptr inbounds nuw { i64, i64 }, ptr %coerce, i32 0, i32 0 +// CHECK:STDOUT: %3 = load i64, ptr %2, align 8 +// CHECK:STDOUT: %4 = getelementptr inbounds nuw { i64, i64 }, ptr %coerce, i32 0, i32 1 +// CHECK:STDOUT: %5 = load i64, ptr %4, align 8 +// CHECK:STDOUT: call void @_Z20TakeGenericMethodPtrIN6Carbon1CEEvMT_KFvvE(i64 %3, i64 %5) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_CSelfDestruct.659d177172b60c17:core.Destroy.Core"(ptr %self) #0 !dbg !79 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !81 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #3 +// CHECK:STDOUT: +// CHECK:STDOUT: declare void @_Z20TakeGenericMethodPtrIN6Carbon1CEEvMT_KFvvE(i64, i64) #4 +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { nounwind } +// CHECK:STDOUT: attributes #1 = { alwaysinline nounwind } +// CHECK:STDOUT: attributes #2 = { alwaysinline 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 #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #4 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +// CHECK:STDOUT: +// CHECK:STDOUT: !llvm.dbg.cu = !{!58} +// CHECK:STDOUT: !llvm.module.flags = !{!24, !25, !26, !2, !3} +// CHECK:STDOUT: !llvm.errno.tbaa = !{!29} +// CHECK:STDOUT: +// CHECK:STDOUT: !2 = !{i32 7, !"Dwarf Version", i32 5} +// CHECK:STDOUT: !3 = !{i32 2, !"Debug Info Version", i32 3} +// CHECK:STDOUT: !6 = !{null} +// CHECK:STDOUT: !7 = !DISubroutineType(types: !6) +// CHECK:STDOUT: !8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !9 = !{null, !8} +// CHECK:STDOUT: !10 = !DISubroutineType(types: !9) +// CHECK:STDOUT: !19 = !{!"Simple C++ TBAA"} +// CHECK:STDOUT: !20 = !{!"omnipotent char", !19, i64 0} +// CHECK:STDOUT: !21 = !{!"any pointer", !20, i64 0} +// CHECK:STDOUT: !22 = !{!21, !21, i64 0} +// CHECK:STDOUT: !23 = !{!20, !20, i64 0} +// CHECK:STDOUT: !24 = !{i32 8, !"PIC Level", i32 2} +// CHECK:STDOUT: !25 = !{i32 7, !"PIE Level", i32 2} +// CHECK:STDOUT: !26 = !{i32 7, !"uwtable", i32 2} +// CHECK:STDOUT: !27 = !{!"int", !20, i64 0} +// CHECK:STDOUT: !28 = !{!"__libc_errno", !27, i64 0} +// CHECK:STDOUT: !29 = !{!28, !27, i64 0} +// CHECK:STDOUT: !57 = !DIFile(filename: "pass_method_ptr.carbon", directory: "") +// CHECK:STDOUT: !58 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !57, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) +// CHECK:STDOUT: !59 = distinct !DISubprogram(name: "F", linkageName: "_CF.Main", scope: null, file: !57, line: 9, type: !7, spFlags: DISPFlagDefinition, unit: !58) +// CHECK:STDOUT: !60 = !DILocation(line: 10, column: 28, scope: !59) +// CHECK:STDOUT: !61 = !DILocation(line: 10, column: 3, scope: !59) +// CHECK:STDOUT: !62 = !DILocation(line: 9, column: 1, scope: !59) +// CHECK:STDOUT: !63 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.C.Main", scope: null, file: !57, line: 5, type: !10, spFlags: DISPFlagDefinition, unit: !58, retainedNodes: !66) +// CHECK:STDOUT: !64 = !DILocalVariable(arg: 1, scope: !63, type: !8) +// CHECK:STDOUT: !65 = !DILocation(line: 5, column: 1, scope: !63) +// CHECK:STDOUT: !66 = !{!64} +// CHECK:STDOUT: !67 = distinct !DISubprogram(name: "SelfDestruct", linkageName: "_CSelfDestruct.cb8adced19392b99:core.Destroy.Core", scope: null, file: !57, line: 5, type: !10, spFlags: DISPFlagDefinition, unit: !58, retainedNodes: !70) +// CHECK:STDOUT: !68 = !DILocalVariable(arg: 1, scope: !67, type: !8) +// CHECK:STDOUT: !69 = !DILocation(line: 5, column: 1, scope: !67) +// CHECK:STDOUT: !70 = !{!68} +// CHECK:STDOUT: !71 = distinct !DISubprogram(name: "SelfDestruct", linkageName: "_CSelfDestruct.08d9e38b928ba575:core.Destroy.Core", scope: null, file: !57, line: 5, type: !10, spFlags: DISPFlagDefinition, unit: !58, retainedNodes: !74) +// CHECK:STDOUT: !72 = !DILocalVariable(arg: 1, scope: !71, type: !8) +// CHECK:STDOUT: !73 = !DILocation(line: 5, column: 1, scope: !71) +// CHECK:STDOUT: !74 = !{!72} +// CHECK:STDOUT: !75 = distinct !DISubprogram(name: "Method__carbon_thunk", linkageName: "_CMethod__carbon_thunk.C.Main", scope: null, file: !57, line: 6, type: !10, spFlags: DISPFlagDefinition, unit: !58, retainedNodes: !78) +// CHECK:STDOUT: !76 = !DILocalVariable(arg: 1, scope: !75, type: !8) +// CHECK:STDOUT: !77 = !DILocation(line: 6, column: 3, scope: !75) +// CHECK:STDOUT: !78 = !{!76} +// CHECK:STDOUT: !79 = distinct !DISubprogram(name: "SelfDestruct", linkageName: "_CSelfDestruct.659d177172b60c17:core.Destroy.Core", scope: null, file: !57, line: 10, type: !10, spFlags: DISPFlagDefinition, unit: !58, retainedNodes: !82) +// CHECK:STDOUT: !80 = !DILocalVariable(arg: 1, scope: !79, type: !8) +// CHECK:STDOUT: !81 = !DILocation(line: 10, column: 28, scope: !79) +// CHECK:STDOUT: !82 = !{!80} +// CHECK:STDOUT: diff --git a/toolchain/sem_ir/typed_insts.h b/toolchain/sem_ir/typed_insts.h index d4791d676f44..250659f27eda 100644 --- a/toolchain/sem_ir/typed_insts.h +++ b/toolchain/sem_ir/typed_insts.h @@ -669,7 +669,7 @@ struct CppOverloadSetType { SpecificId specific_id; }; -// The type of a C++ function pointer. +// The type of a C++ function pointer or member function pointer. struct CppFunctionPointerType { static constexpr auto Kind = InstKind::CppFunctionPointerType.Define(