From 1bc329af144f602e655e0430d1ec973aedb7d7a6 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Mon, 4 May 2026 16:28:58 -0400 Subject: [PATCH] Support calling Carbon destructors from C++ (#7143) A destructor is added to the C++ class definition in `CarbonExternalASTSource::CompleteType`. The destructor calls a Carbon function that calls the `Destroy` operator. --- toolchain/check/cpp/export.cpp | 72 +++- toolchain/check/cpp/export.h | 7 + toolchain/check/cpp/generate_ast.cpp | 2 + toolchain/check/thunk.cpp | 35 ++ toolchain/check/thunk.h | 4 + .../testdata/interop/cpp/reverse/class.carbon | 308 ++++++++++++++---- .../interop/cpp/reverse/method.carbon | 202 +++++++++--- 7 files changed, 498 insertions(+), 132 deletions(-) diff --git a/toolchain/check/cpp/export.cpp b/toolchain/check/cpp/export.cpp index e0fdec4e3a66..87dc23085f66 100644 --- a/toolchain/check/cpp/export.cpp +++ b/toolchain/check/cpp/export.cpp @@ -555,6 +555,20 @@ static auto BuildCppToCarbonThunkDecl( return thunk_function_decl; } +// Get an expr for accessing `this` in a method. +static auto GetThisArg(clang::Sema& sema, clang::SourceLocation clang_loc, + clang::CXXRecordDecl* record_decl) -> clang::Expr* { + clang::QualType class_type = + sema.getASTContext().getCanonicalTagType(record_decl); + auto class_ptr_type = sema.getASTContext().getPointerType(class_type); + auto* this_expr = sema.BuildCXXThisExpr(clang_loc, class_ptr_type, + /*IsImplicit=*/true); + return clang::UnaryOperator::Create( + sema.getASTContext(), this_expr, clang::UO_Deref, class_type, + clang::ExprValueKind::VK_LValue, clang::ExprObjectKind::OK_Ordinary, + clang_loc, /*CanOverflow=*/false, clang::FPOptionsOverride()); +} + // Create the body of a C++ thunk that calls a Carbon thunk. The // arguments are passed by reference to the callee. static auto BuildCppToCarbonThunkBody(clang::Sema& sema, @@ -599,16 +613,7 @@ static auto BuildCppToCarbonThunkBody(clang::Sema& sema, // For methods, pass the `this` pointer as the first argument to the callee. if (target.self_param) { auto* parent_class = cast(target.decl_context); - clang::QualType class_type = - sema.getASTContext().getCanonicalTagType(parent_class); - auto class_ptr_type = sema.getASTContext().getPointerType(class_type); - auto* this_expr = sema.BuildCXXThisExpr(clang_loc, class_ptr_type, - /*IsImplicit=*/true); - this_expr = clang::UnaryOperator::Create( - sema.getASTContext(), this_expr, clang::UO_Deref, class_type, - clang::ExprValueKind::VK_LValue, clang::ExprObjectKind::OK_Ordinary, - clang_loc, /*CanOverflow=*/false, clang::FPOptionsOverride()); - call_args.push_back(this_expr); + call_args.push_back(GetThisArg(sema, clang_loc, parent_class)); } for (auto* param : function_decl->parameters()) { clang::Expr* call_arg = @@ -765,4 +770,51 @@ auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id, carbon_function_decl); } +auto ExportDestructorToCpp(Context& context, const SemIR::Class& class_info, + clang::CXXRecordDecl* record_decl) + -> clang::CXXDestructorDecl* { + SemIR::LocId loc_id(class_info.first_decl_id()); + auto clang_loc = record_decl->getLocation(); + + // Create C++ destructor decl. + auto class_type = context.ast_context().getCanonicalTagType(record_decl); + auto name = + context.ast_context().DeclarationNames.getCXXDestructorName(class_type); + clang::DeclarationNameInfo name_info(name, clang_loc); + clang::QualType type = context.ast_context().getFunctionType( + context.ast_context().VoidTy, llvm::ArrayRef(), + clang::FunctionProtoType::ExtProtoInfo()); + auto* cpp_destructor_decl = clang::CXXDestructorDecl::Create( + context.ast_context(), record_decl, + /*StartLoc=*/clang_loc, name_info, type, /*TInfo=*/nullptr, + /*UsesFPIntrin=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true, + clang::ConstexprSpecKind::Unspecified); + cpp_destructor_decl->setAccess(clang::AS_public); + + // Create Carbon thunk that destroys the object, and get a C++ + // function decl for calling it. + auto thunk_function_id = BuildDestroyThunk(context, loc_id, class_info); + auto* cpp_function_decl = + BuildCppFunctionDeclForCarbonFn(context, loc_id, thunk_function_id); + + clang::Sema& sema = context.clang_sema(); + + // Build the destructor body. + clang::Sema::ContextRAII context_raii(sema, cpp_destructor_decl); + sema.ActOnStartOfFunctionDef(nullptr, cpp_destructor_decl); + + // Create a clang call expr to call the Carbon thunk. + clang::ExprResult callee = + sema.BuildDeclRefExpr(cpp_function_decl, cpp_function_decl->getType(), + clang::VK_PRValue, clang_loc); + llvm::SmallVector call_args; + call_args.push_back(GetThisArg(sema, clang_loc, record_decl)); + clang::ExprResult call = sema.BuildCallExpr(nullptr, callee.get(), clang_loc, + call_args, clang_loc); + + sema.ActOnFinishFunctionBody(cpp_destructor_decl, call.get()); + + return cpp_destructor_decl; +} + } // namespace Carbon::Check diff --git a/toolchain/check/cpp/export.h b/toolchain/check/cpp/export.h index ae690661c802..cb29a4745960 100644 --- a/toolchain/check/cpp/export.h +++ b/toolchain/check/cpp/export.h @@ -58,6 +58,13 @@ auto CalculateCppFieldOffsets( auto ExportFunctionToCpp(Context& context, SemIR::LocId loc_id, SemIR::FunctionId function_id) -> clang::FunctionDecl*; +// Export a Carbon destructor into C++. +// +// The destructor calls the `Destroy` operator. +auto ExportDestructorToCpp(Context& context, const SemIR::Class& class_info, + clang::CXXRecordDecl* record_decl) + -> clang::CXXDestructorDecl*; + } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_CPP_EXPORT_H_ diff --git a/toolchain/check/cpp/generate_ast.cpp b/toolchain/check/cpp/generate_ast.cpp index 43b2c29ba475..12c17734f692 100644 --- a/toolchain/check/cpp/generate_ast.cpp +++ b/toolchain/check/cpp/generate_ast.cpp @@ -641,6 +641,8 @@ auto CarbonExternalASTSource::CompleteType(clang::TagDecl* tag_decl) -> void { ExportAllFieldsToCpp(*context_, class_info); + class_decl->addDecl(ExportDestructorToCpp(*context_, class_info, class_decl)); + // TODO: Import any special member functions that affect class properties. class_decl->completeDefinition(); } diff --git a/toolchain/check/thunk.cpp b/toolchain/check/thunk.cpp index 46dcce5dd610..2eaf74e0fdef 100644 --- a/toolchain/check/thunk.cpp +++ b/toolchain/check/thunk.cpp @@ -17,6 +17,7 @@ #include "toolchain/check/inst.h" #include "toolchain/check/member_access.h" #include "toolchain/check/name_ref.h" +#include "toolchain/check/operator.h" #include "toolchain/check/pattern.h" #include "toolchain/check/pattern_match.h" #include "toolchain/check/pointer_dereference.h" @@ -515,4 +516,38 @@ auto BuildThunk(Context& context, SemIR::FunctionId signature_id, return thunk_id; } +auto BuildDestroyThunk(Context& context, SemIR::LocId loc_id, + const SemIR::Class& class_info) -> SemIR::FunctionId { + // Create a new function declaration. + auto thunk_name_id = SemIR::NameId::ForIdentifier( + context.identifiers().Add("__destroy_thunk")); + auto [thunk_inst_id, thunk_function_id] = + MakeGeneratedFunctionDecl(context, loc_id, + {.parent_scope_id = class_info.scope_id, + .name_id = thunk_name_id, + .self_type_id = class_info.self_type_id}); + + auto& thunk_function = context.functions().Get(thunk_function_id); + thunk_function.SetThunk(SemIR::InstId::None); + + context.scope_stack().PushForDeclName(); + StartFunctionDefinition(context, thunk_inst_id, thunk_function_id); + + // Get `self` arg. + auto params = context.inst_blocks().Get(thunk_function.call_params_id); + auto self_inst_id = params[0]; + + // Build the function body. This calls the `Destroy` operator on `self`. + auto destroy_inst_id = BuildUnaryOperator( + context, loc_id, {.interface_name = CoreIdentifier::Destroy}, + self_inst_id); + DiscardExpr(context, destroy_inst_id); + BuildReturnWithNoExpr(context, loc_id); + + FinishFunctionDefinition(context, thunk_function_id); + context.scope_stack().Pop(); + + return thunk_function_id; +} + } // namespace Carbon::Check diff --git a/toolchain/check/thunk.h b/toolchain/check/thunk.h index e1589987b545..9805e901dc70 100644 --- a/toolchain/check/thunk.h +++ b/toolchain/check/thunk.h @@ -46,6 +46,10 @@ auto BuildThunkDefinitionForExport(Context& context, SemIR::InstId thunk_id, SemIR::InstId callee_id) -> void; +// Build a function that destroys an object of the given class. +auto BuildDestroyThunk(Context& context, SemIR::LocId loc_id, + const SemIR::Class& class_info) -> SemIR::FunctionId; + } // namespace Carbon::Check #endif // CARBON_TOOLCHAIN_CHECK_THUNK_H_ diff --git a/toolchain/lower/testdata/interop/cpp/reverse/class.carbon b/toolchain/lower/testdata/interop/cpp/reverse/class.carbon index 719a20274299..790523600207 100644 --- a/toolchain/lower/testdata/interop/cpp/reverse/class.carbon +++ b/toolchain/lower/testdata/interop/cpp/reverse/class.carbon @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// EXTRA-ARGS: --clang-arg=-fno-exceptions // // AUTOUPDATE // TIP: To test this file alone, run: @@ -156,13 +157,20 @@ fn G() { // CHECK:STDOUT: %"class.Carbon::B" = type { %"class.Carbon::A", i32 } // CHECK:STDOUT: %"class.Carbon::C" = type { %"class.Carbon::A", i32 } // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable +// CHECK:STDOUT: $_ZN6Carbon1AD2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_ZN6Carbon1BD2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: $_ZN6Carbon1CD2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local void @_Z1fv() #0 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %a = alloca %"class.Carbon::A", align 8 -// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a) #3 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %a) #5 // CHECK:STDOUT: call void @_ZN6CarbonL5CallAEPNS_1AE(ptr noundef %a) -// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %a) #3 +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %a) +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %a) #5 // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -178,16 +186,27 @@ fn G() { // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %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 8 dereferenceable(12) %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: mustprogress uwtable +// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local void @_Z1gv() #0 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %b = alloca %"class.Carbon::B", align 8 -// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b) #3 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %b) #5 // CHECK:STDOUT: call void @_ZN6CarbonL5CallBEPNS_1BE(ptr noundef %b) -// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %b) #3 +// CHECK:STDOUT: call void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %b) +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %b) #5 // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -200,14 +219,27 @@ fn G() { // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1BD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %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 8 dereferenceable(16) %this1) +// CHECK:STDOUT: %a = getelementptr inbounds nuw %"class.Carbon::B", ptr %this1, i32 0, i32 0 +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %a) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local void @_Z1hv() #0 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %c = alloca %"class.Carbon::C", align 8 -// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c) #3 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c) #5 // CHECK:STDOUT: call void @_ZN6CarbonL5CallCEPNS_1CE(ptr noundef %c) // CHECK:STDOUT: call void @_ZN6CarbonL5CallAEPNS_1AE(ptr noundef %c) -// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %c) #3 +// CHECK:STDOUT: call void @_ZN6Carbon1CD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %c) +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %c) #5 // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -220,40 +252,119 @@ fn G() { // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1CD2Ev(ptr noundef nonnull align 8 dead_on_return(16) dereferenceable(16) %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 !16 +// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.C.Main"(ptr noundef nonnull align 8 dereferenceable(16) %this1) +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %this1) +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } +// CHECK:STDOUT: // CHECK:STDOUT: declare void @_CCallA.Main(ptr) // CHECK:STDOUT: // CHECK:STDOUT: declare void @_CCallB.Main(ptr) // CHECK:STDOUT: // CHECK:STDOUT: declare void @_CCallC.Main(ptr) // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CCallA__carbon_thunk.Main(ptr %_) #3 !dbg !18 { +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.A.Main"(ptr %self) #4 !dbg !18 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %.loc21 = load ptr, ptr %_, align 8, !dbg !24 -// CHECK:STDOUT: call void @_CCallA.Main(ptr %.loc21), !dbg !24 +// CHECK:STDOUT: call void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self), !dbg !24 // CHECK:STDOUT: ret void, !dbg !24 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CCallB__carbon_thunk.Main(ptr %_) #3 !dbg !25 { +// CHECK:STDOUT: define weak_odr void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %self) #5 !dbg !25 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %.loc22 = load ptr, ptr %_, align 8, !dbg !28 -// CHECK:STDOUT: call void @_CCallB.Main(ptr %.loc22), !dbg !28 -// CHECK:STDOUT: ret void, !dbg !28 +// CHECK:STDOUT: ret void, !dbg !31 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CCallC__carbon_thunk.Main(ptr %_) #3 !dbg !29 { +// CHECK:STDOUT: define weak_odr void @"_COp.ce21b459230035a4:core.Destroy.Core"(ptr %self) #5 !dbg !32 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %.loc23 = load ptr, ptr %_, align 8, !dbg !32 -// CHECK:STDOUT: call void @_CCallC.Main(ptr %.loc23), !dbg !32 -// CHECK:STDOUT: ret void, !dbg !32 +// CHECK:STDOUT: ret void, !dbg !35 // CHECK:STDOUT: } // 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: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self) #5 !dbg !36 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !39 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CCallA__carbon_thunk.Main(ptr %_) #5 !dbg !40 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc21 = load ptr, ptr %_, align 8, !dbg !43 +// CHECK:STDOUT: call void @_CCallA.Main(ptr %.loc21), !dbg !43 +// CHECK:STDOUT: ret void, !dbg !43 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.B.Main"(ptr %self) #4 !dbg !44 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_COp.301c2cde953858ec:core.Destroy.Core"(ptr %self), !dbg !47 +// CHECK:STDOUT: ret void, !dbg !47 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.1a8ac7d7e1ca560e:core.Destroy.Core"(ptr %self) #5 !dbg !48 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !51 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.301c2cde953858ec:core.Destroy.Core"(ptr %self) #5 !dbg !52 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !55 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CCallB__carbon_thunk.Main(ptr %_) #5 !dbg !56 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc22 = load ptr, ptr %_, align 8, !dbg !59 +// CHECK:STDOUT: call void @_CCallB.Main(ptr %.loc22), !dbg !59 +// CHECK:STDOUT: ret void, !dbg !59 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.C.Main"(ptr %self) #4 !dbg !60 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @"_COp.71e25083d63c4d6c:core.Destroy.Core"(ptr %self), !dbg !63 +// CHECK:STDOUT: ret void, !dbg !63 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.e9c7e36fd2e174ea:core.Destroy.Core"(ptr %self) #5 !dbg !64 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !67 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.71e25083d63c4d6c:core.Destroy.Core"(ptr %self) #5 !dbg !68 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !71 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CCallC__carbon_thunk.Main(ptr %_) #5 !dbg !72 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc23 = load ptr, ptr %_, align 8, !dbg !75 +// CHECK:STDOUT: call void @_CCallC.Main(ptr %.loc23), !dbg !75 +// CHECK:STDOUT: ret void, !dbg !75 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; uselistorder directives +// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon1AD2Ev, { 2, 1, 0 } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } // CHECK:STDOUT: attributes #1 = { 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 = { nounwind } +// 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 = { alwaysinline nounwind } +// CHECK:STDOUT: attributes #5 = { nounwind } // CHECK:STDOUT: // CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} // CHECK:STDOUT: !llvm.dbg.cu = !{!5} @@ -277,21 +388,64 @@ fn G() { // CHECK:STDOUT: !15 = !{!"p1 _ZTSN6Carbon1BE", !13, i64 0} // CHECK:STDOUT: !16 = !{!17, !17, i64 0} // CHECK:STDOUT: !17 = !{!"p1 _ZTSN6Carbon1CE", !13, i64 0} -// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "CallA__carbon_thunk", linkageName: "_CCallA__carbon_thunk.Main", scope: null, file: !6, line: 21, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !22) +// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.A.Main", scope: null, file: !6, line: 6, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !22) // CHECK:STDOUT: !19 = !DISubroutineType(types: !20) // CHECK:STDOUT: !20 = !{null, !21} // CHECK:STDOUT: !21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) // CHECK:STDOUT: !22 = !{!23} // CHECK:STDOUT: !23 = !DILocalVariable(arg: 1, scope: !18, type: !21) -// CHECK:STDOUT: !24 = !DILocation(line: 21, column: 1, scope: !18) -// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "CallB__carbon_thunk", linkageName: "_CCallB__carbon_thunk.Main", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !26) -// CHECK:STDOUT: !26 = !{!27} -// CHECK:STDOUT: !27 = !DILocalVariable(arg: 1, scope: !25, type: !21) -// CHECK:STDOUT: !28 = !DILocation(line: 22, column: 1, scope: !25) -// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "CallC__carbon_thunk", linkageName: "_CCallC__carbon_thunk.Main", scope: null, file: !6, line: 23, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30) -// CHECK:STDOUT: !30 = !{!31} -// CHECK:STDOUT: !31 = !DILocalVariable(arg: 1, scope: !29, type: !21) -// CHECK:STDOUT: !32 = !DILocation(line: 23, column: 1, scope: !29) +// CHECK:STDOUT: !24 = !DILocation(line: 6, column: 1, scope: !18) +// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "Op", linkageName: "_COp.7e389eab4a7e5487:core.Destroy.Core", scope: null, file: !6, line: 6, type: !26, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !29) +// CHECK:STDOUT: !26 = !DISubroutineType(types: !27) +// CHECK:STDOUT: !27 = !{null, !28} +// CHECK:STDOUT: !28 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +// CHECK:STDOUT: !29 = !{!30} +// CHECK:STDOUT: !30 = !DILocalVariable(arg: 1, scope: !25, type: !28) +// CHECK:STDOUT: !31 = !DILocation(line: 6, column: 1, scope: !25) +// CHECK:STDOUT: !32 = distinct !DISubprogram(name: "Op", linkageName: "_COp.ce21b459230035a4:core.Destroy.Core", scope: null, file: !6, line: 6, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !33) +// CHECK:STDOUT: !33 = !{!34} +// CHECK:STDOUT: !34 = !DILocalVariable(arg: 1, scope: !32, type: !21) +// CHECK:STDOUT: !35 = !DILocation(line: 6, column: 1, scope: !32) +// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "Op", linkageName: "_COp.1afa5e4ee26f3f8f:core.Destroy.Core", scope: null, file: !6, line: 6, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !37) +// CHECK:STDOUT: !37 = !{!38} +// CHECK:STDOUT: !38 = !DILocalVariable(arg: 1, scope: !36, type: !21) +// CHECK:STDOUT: !39 = !DILocation(line: 6, column: 1, scope: !36) +// CHECK:STDOUT: !40 = distinct !DISubprogram(name: "CallA__carbon_thunk", linkageName: "_CCallA__carbon_thunk.Main", scope: null, file: !6, line: 21, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !41) +// CHECK:STDOUT: !41 = !{!42} +// CHECK:STDOUT: !42 = !DILocalVariable(arg: 1, scope: !40, type: !21) +// CHECK:STDOUT: !43 = !DILocation(line: 21, column: 1, scope: !40) +// CHECK:STDOUT: !44 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.B.Main", scope: null, file: !6, line: 11, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !45) +// CHECK:STDOUT: !45 = !{!46} +// CHECK:STDOUT: !46 = !DILocalVariable(arg: 1, scope: !44, type: !21) +// CHECK:STDOUT: !47 = !DILocation(line: 11, column: 1, scope: !44) +// CHECK:STDOUT: !48 = distinct !DISubprogram(name: "Op", linkageName: "_COp.1a8ac7d7e1ca560e:core.Destroy.Core", scope: null, file: !6, line: 11, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !49) +// CHECK:STDOUT: !49 = !{!50} +// CHECK:STDOUT: !50 = !DILocalVariable(arg: 1, scope: !48, type: !21) +// CHECK:STDOUT: !51 = !DILocation(line: 11, column: 1, scope: !48) +// CHECK:STDOUT: !52 = distinct !DISubprogram(name: "Op", linkageName: "_COp.301c2cde953858ec:core.Destroy.Core", scope: null, file: !6, line: 11, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !53) +// CHECK:STDOUT: !53 = !{!54} +// CHECK:STDOUT: !54 = !DILocalVariable(arg: 1, scope: !52, type: !21) +// CHECK:STDOUT: !55 = !DILocation(line: 11, column: 1, scope: !52) +// CHECK:STDOUT: !56 = distinct !DISubprogram(name: "CallB__carbon_thunk", linkageName: "_CCallB__carbon_thunk.Main", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !57) +// CHECK:STDOUT: !57 = !{!58} +// CHECK:STDOUT: !58 = !DILocalVariable(arg: 1, scope: !56, type: !21) +// CHECK:STDOUT: !59 = !DILocation(line: 22, column: 1, scope: !56) +// CHECK:STDOUT: !60 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.C.Main", scope: null, file: !6, line: 16, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !61) +// CHECK:STDOUT: !61 = !{!62} +// CHECK:STDOUT: !62 = !DILocalVariable(arg: 1, scope: !60, type: !21) +// CHECK:STDOUT: !63 = !DILocation(line: 16, column: 1, scope: !60) +// CHECK:STDOUT: !64 = distinct !DISubprogram(name: "Op", linkageName: "_COp.e9c7e36fd2e174ea:core.Destroy.Core", scope: null, file: !6, line: 16, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !65) +// CHECK:STDOUT: !65 = !{!66} +// CHECK:STDOUT: !66 = !DILocalVariable(arg: 1, scope: !64, type: !21) +// CHECK:STDOUT: !67 = !DILocation(line: 16, column: 1, scope: !64) +// CHECK:STDOUT: !68 = distinct !DISubprogram(name: "Op", linkageName: "_COp.71e25083d63c4d6c:core.Destroy.Core", scope: null, file: !6, line: 16, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !69) +// CHECK:STDOUT: !69 = !{!70} +// CHECK:STDOUT: !70 = !DILocalVariable(arg: 1, scope: !68, type: !21) +// CHECK:STDOUT: !71 = !DILocation(line: 16, column: 1, scope: !68) +// CHECK:STDOUT: !72 = distinct !DISubprogram(name: "CallC__carbon_thunk", linkageName: "_CCallC__carbon_thunk.Main", scope: null, file: !6, line: 23, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !73) +// CHECK:STDOUT: !73 = !{!74} +// CHECK:STDOUT: !74 = !DILocalVariable(arg: 1, scope: !72, type: !21) +// CHECK:STDOUT: !75 = !DILocation(line: 23, column: 1, scope: !72) // CHECK:STDOUT: ; ModuleID = 'field.carbon' // CHECK:STDOUT: source_filename = "field.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" @@ -315,47 +469,55 @@ fn G() { // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CG.Main() #1 !dbg !19 { +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.C.Main"(ptr %self) #1 !dbg !19 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %c.var = alloca { i32, i32 }, align 8, !dbg !22 -// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c.var), !dbg !22 -// CHECK:STDOUT: %.loc19_29.3.a = getelementptr inbounds nuw { i32, i32 }, ptr %c.var, i32 0, i32 0, !dbg !23 -// CHECK:STDOUT: %.loc19_29.6.b = getelementptr inbounds nuw { i32, i32 }, ptr %c.var, i32 0, i32 1, !dbg !23 -// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %c.var, ptr align 4 @C.val.loc19_3, i64 8, i1 false), !dbg !22 -// CHECK:STDOUT: call void @_Z1FRN6Carbon1CE(ptr %c.var), !dbg !24 -// CHECK:STDOUT: call void @"_COp.71e25083d63c4d6c:core.Destroy.Core"(ptr %c.var), !dbg !22 +// CHECK:STDOUT: call void @"_COp.71e25083d63c4d6c:core.Destroy.Core"(ptr %self), !dbg !25 // CHECK:STDOUT: ret void, !dbg !25 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define weak_odr void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %self) #1 !dbg !26 { +// CHECK:STDOUT: define weak_odr void @"_COp.7e389eab4a7e5487:core.Destroy.Core"(ptr %self) #2 !dbg !26 { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret void, !dbg !32 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define weak_odr void @"_COp.fb32c4dfca65e378:core.Destroy.Core"(ptr %self) #1 !dbg !33 { +// CHECK:STDOUT: define weak_odr void @"_COp.fb32c4dfca65e378:core.Destroy.Core"(ptr %self) #2 !dbg !33 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret void, !dbg !39 +// CHECK:STDOUT: ret void, !dbg !36 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define weak_odr void @"_COp.71e25083d63c4d6c:core.Destroy.Core"(ptr %self) #1 !dbg !40 { +// CHECK:STDOUT: define weak_odr void @"_COp.71e25083d63c4d6c:core.Destroy.Core"(ptr %self) #2 !dbg !37 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: ret void, !dbg !43 +// CHECK:STDOUT: ret void, !dbg !40 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CG.Main() #2 !dbg !41 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %c.var = alloca { i32, i32 }, align 8, !dbg !44 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %c.var), !dbg !44 +// CHECK:STDOUT: %.loc19_29.3.a = getelementptr inbounds nuw { i32, i32 }, ptr %c.var, i32 0, i32 0, !dbg !45 +// CHECK:STDOUT: %.loc19_29.6.b = getelementptr inbounds nuw { i32, i32 }, ptr %c.var, i32 0, i32 1, !dbg !45 +// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %c.var, ptr align 4 @C.val.loc19_3, i64 8, i1 false), !dbg !44 +// CHECK:STDOUT: call void @_Z1FRN6Carbon1CE(ptr %c.var), !dbg !46 +// CHECK:STDOUT: call void @"_COp.71e25083d63c4d6c:core.Destroy.Core"(ptr %c.var), !dbg !44 +// CHECK:STDOUT: ret void, !dbg !47 // 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: declare void @llvm.lifetime.start.p0(ptr captures(none)) #3 // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) -// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #3 +// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #4 // CHECK:STDOUT: // CHECK:STDOUT: attributes #0 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } -// CHECK:STDOUT: attributes #1 = { nounwind } -// CHECK:STDOUT: attributes #2 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } -// CHECK:STDOUT: attributes #3 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #1 = { alwaysinline nounwind } +// CHECK:STDOUT: attributes #2 = { nounwind } +// CHECK:STDOUT: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +// CHECK:STDOUT: attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } // CHECK:STDOUT: // CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} // CHECK:STDOUT: !llvm.dbg.cu = !{!5} @@ -380,28 +542,32 @@ fn G() { // CHECK:STDOUT: !16 = !{!17, !8, i64 0} // CHECK:STDOUT: !17 = !{!"_ZTSN6Carbon1CE", !8, i64 0, !8, i64 4} // CHECK:STDOUT: !18 = !{!17, !8, i64 4} -// CHECK:STDOUT: !19 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main", scope: null, file: !6, line: 18, type: !20, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !19 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.C.Main", scope: null, file: !6, line: 6, type: !20, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !23) // CHECK:STDOUT: !20 = !DISubroutineType(types: !21) -// CHECK:STDOUT: !21 = !{null} -// CHECK:STDOUT: !22 = !DILocation(line: 19, column: 3, scope: !19) -// CHECK:STDOUT: !23 = !DILocation(line: 19, column: 14, scope: !19) -// CHECK:STDOUT: !24 = !DILocation(line: 20, column: 3, scope: !19) -// CHECK:STDOUT: !25 = !DILocation(line: 18, column: 1, scope: !19) -// CHECK:STDOUT: !26 = distinct !DISubprogram(name: "Op", linkageName: "_COp.7e389eab4a7e5487:core.Destroy.Core", scope: null, file: !6, line: 19, type: !27, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30) +// CHECK:STDOUT: !21 = !{null, !22} +// CHECK:STDOUT: !22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !23 = !{!24} +// CHECK:STDOUT: !24 = !DILocalVariable(arg: 1, scope: !19, type: !22) +// CHECK:STDOUT: !25 = !DILocation(line: 6, column: 1, scope: !19) +// CHECK:STDOUT: !26 = distinct !DISubprogram(name: "Op", linkageName: "_COp.7e389eab4a7e5487:core.Destroy.Core", scope: null, file: !6, line: 6, type: !27, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30) // CHECK:STDOUT: !27 = !DISubroutineType(types: !28) // CHECK:STDOUT: !28 = !{null, !29} // CHECK:STDOUT: !29 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) // CHECK:STDOUT: !30 = !{!31} // CHECK:STDOUT: !31 = !DILocalVariable(arg: 1, scope: !26, type: !29) -// CHECK:STDOUT: !32 = !DILocation(line: 19, column: 3, scope: !26) -// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "Op", linkageName: "_COp.fb32c4dfca65e378:core.Destroy.Core", scope: null, file: !6, line: 19, type: !34, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !37) -// CHECK:STDOUT: !34 = !DISubroutineType(types: !35) -// CHECK:STDOUT: !35 = !{null, !36} -// CHECK:STDOUT: !36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) -// CHECK:STDOUT: !37 = !{!38} -// CHECK:STDOUT: !38 = !DILocalVariable(arg: 1, scope: !33, type: !36) -// CHECK:STDOUT: !39 = !DILocation(line: 19, column: 3, scope: !33) -// CHECK:STDOUT: !40 = distinct !DISubprogram(name: "Op", linkageName: "_COp.71e25083d63c4d6c:core.Destroy.Core", scope: null, file: !6, line: 19, type: !34, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !41) -// CHECK:STDOUT: !41 = !{!42} -// CHECK:STDOUT: !42 = !DILocalVariable(arg: 1, scope: !40, type: !36) -// CHECK:STDOUT: !43 = !DILocation(line: 19, column: 3, scope: !40) +// CHECK:STDOUT: !32 = !DILocation(line: 6, column: 1, scope: !26) +// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "Op", linkageName: "_COp.fb32c4dfca65e378:core.Destroy.Core", scope: null, file: !6, line: 6, type: !20, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !34) +// CHECK:STDOUT: !34 = !{!35} +// CHECK:STDOUT: !35 = !DILocalVariable(arg: 1, scope: !33, type: !22) +// CHECK:STDOUT: !36 = !DILocation(line: 6, column: 1, scope: !33) +// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.71e25083d63c4d6c:core.Destroy.Core", scope: null, file: !6, line: 6, type: !20, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38) +// CHECK:STDOUT: !38 = !{!39} +// CHECK:STDOUT: !39 = !DILocalVariable(arg: 1, scope: !37, type: !22) +// CHECK:STDOUT: !40 = !DILocation(line: 6, column: 1, scope: !37) +// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "G", linkageName: "_CG.Main", scope: null, file: !6, line: 18, type: !42, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !42 = !DISubroutineType(types: !43) +// CHECK:STDOUT: !43 = !{null} +// CHECK:STDOUT: !44 = !DILocation(line: 19, column: 3, scope: !41) +// CHECK:STDOUT: !45 = !DILocation(line: 19, column: 14, scope: !41) +// CHECK:STDOUT: !46 = !DILocation(line: 20, column: 3, scope: !41) +// CHECK:STDOUT: !47 = !DILocation(line: 18, column: 1, scope: !41) diff --git a/toolchain/lower/testdata/interop/cpp/reverse/method.carbon b/toolchain/lower/testdata/interop/cpp/reverse/method.carbon index 24972d4ad41f..cdeb9f401246 100644 --- a/toolchain/lower/testdata/interop/cpp/reverse/method.carbon +++ b/toolchain/lower/testdata/interop/cpp/reverse/method.carbon @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // INCLUDE-FILE: toolchain/testing/testdata/min_prelude/int.carbon +// EXTRA-ARGS: --clang-arg=-fno-exceptions // // AUTOUPDATE // TIP: To test this file alone, run: @@ -69,13 +70,16 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: // CHECK:STDOUT: %"class.Carbon::A" = type {} // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable +// CHECK:STDOUT: $_ZN6Carbon1AD2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local void @_Z5CallFv() #0 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A", align 1 -// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #3 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #4 // CHECK:STDOUT: call void @_ZN6Carbon1A1FEv(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp) -// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %ref.tmp) #3 +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp) +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %ref.tmp) #4 // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: @@ -92,26 +96,51 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: ret void // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(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 dereferenceable(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 @_CF.A.Main(ptr %self) #3 !dbg !14 { +// CHECK:STDOUT: define void @_CF.A.Main(ptr %self) #4 !dbg !14 { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret void, !dbg !20 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CF__carbon_thunk.A.Main(ptr %self) #3 !dbg !21 { +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.A.Main"(ptr %self) #5 !dbg !21 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_CF.A.Main(ptr %self), !dbg !24 +// CHECK:STDOUT: call void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self), !dbg !24 // CHECK:STDOUT: ret void, !dbg !24 // CHECK:STDOUT: } // 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: ; Function Attrs: nounwind +// CHECK:STDOUT: define weak_odr void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self) #4 !dbg !25 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: ret void, !dbg !28 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CF__carbon_thunk.A.Main(ptr %self) #4 !dbg !29 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CF.A.Main(ptr %self), !dbg !32 +// CHECK:STDOUT: ret void, !dbg !32 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } // CHECK:STDOUT: attributes #1 = { 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 = { nounwind } +// 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.module.flags = !{!0, !1, !2, !3, !4} // CHECK:STDOUT: !llvm.dbg.cu = !{!5} @@ -138,10 +167,18 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: !18 = !{!19} // CHECK:STDOUT: !19 = !DILocalVariable(arg: 1, scope: !14, type: !17) // CHECK:STDOUT: !20 = !DILocation(line: 6, column: 3, scope: !14) -// CHECK:STDOUT: !21 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.A.Main", scope: null, file: !6, line: 6, type: !15, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !22) +// CHECK:STDOUT: !21 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.A.Main", scope: null, file: !6, line: 5, type: !15, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !22) // CHECK:STDOUT: !22 = !{!23} // CHECK:STDOUT: !23 = !DILocalVariable(arg: 1, scope: !21, type: !17) -// CHECK:STDOUT: !24 = !DILocation(line: 6, column: 3, scope: !21) +// CHECK:STDOUT: !24 = !DILocation(line: 5, column: 1, scope: !21) +// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "Op", linkageName: "_COp.1afa5e4ee26f3f8f:core.Destroy.Core", scope: null, file: !6, line: 5, type: !15, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !26) +// CHECK:STDOUT: !26 = !{!27} +// CHECK:STDOUT: !27 = !DILocalVariable(arg: 1, scope: !25, type: !17) +// CHECK:STDOUT: !28 = !DILocation(line: 5, column: 1, scope: !25) +// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.A.Main", scope: null, file: !6, line: 6, type: !15, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30) +// CHECK:STDOUT: !30 = !{!31} +// CHECK:STDOUT: !31 = !DILocalVariable(arg: 1, scope: !29, type: !17) +// CHECK:STDOUT: !32 = !DILocation(line: 6, column: 3, scope: !29) // CHECK:STDOUT: ; ModuleID = 'method_with_args_and_return.carbon' // CHECK:STDOUT: source_filename = "method_with_args_and_return.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" @@ -149,13 +186,16 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: // CHECK:STDOUT: %"class.Carbon::A" = type {} // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable +// CHECK:STDOUT: $_ZN6Carbon1AD2Ev = comdat any +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local noundef i32 @_Z5CallFv() #0 { // CHECK:STDOUT: entry: // CHECK:STDOUT: %ref.tmp = alloca %"class.Carbon::A", align 1 -// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #3 +// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %ref.tmp) #4 // CHECK:STDOUT: %call = call noundef i32 @_ZN6Carbon1A1FEi(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp, i32 noundef 123) -// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %ref.tmp) #3 +// CHECK:STDOUT: call void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(1) %ref.tmp) +// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %ref.tmp) #4 // CHECK:STDOUT: ret i32 %call // CHECK:STDOUT: } // CHECK:STDOUT: @@ -176,35 +216,60 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: ret i32 %1 // CHECK:STDOUT: } // CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable +// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon1AD2Ev(ptr noundef nonnull align 1 dereferenceable(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 dereferenceable(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 i32 @_CF.A.Main(ptr %self, i32 %a) #3 !dbg !14 { +// CHECK:STDOUT: define i32 @_CF.A.Main(ptr %self, i32 %a) #4 !dbg !14 { // CHECK:STDOUT: entry: // CHECK:STDOUT: ret i32 %a, !dbg !22 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CF__carbon_thunk.A.Main(ptr %self, ptr %_, ptr %_1) #3 !dbg !23 { +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.A.Main"(ptr %self) #5 !dbg !23 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %.loc6_35.2 = load i32, ptr %_, align 4, !dbg !30 -// CHECK:STDOUT: %A.F.call = call i32 @_CF.A.Main(ptr %self, i32 %.loc6_35.2), !dbg !30 -// CHECK:STDOUT: store i32 %A.F.call, ptr %_1, align 4, !dbg !30 -// CHECK:STDOUT: ret void, !dbg !30 +// CHECK:STDOUT: call void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self), !dbg !28 +// CHECK:STDOUT: ret void, !dbg !28 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define i32 @_CCallCallF.Main() #3 !dbg !31 { +// CHECK:STDOUT: define weak_odr void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self) #4 !dbg !29 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: %CallF.call = call i32 @_Z5CallFv(), !dbg !34 -// CHECK:STDOUT: ret i32 %CallF.call, !dbg !35 +// CHECK:STDOUT: ret void, !dbg !32 // CHECK:STDOUT: } // 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: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CF__carbon_thunk.A.Main(ptr %self, ptr %_, ptr %_1) #4 !dbg !33 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %.loc6_35.2 = load i32, ptr %_, align 4, !dbg !40 +// CHECK:STDOUT: %A.F.call = call i32 @_CF.A.Main(ptr %self, i32 %.loc6_35.2), !dbg !40 +// CHECK:STDOUT: store i32 %A.F.call, ptr %_1, align 4, !dbg !40 +// CHECK:STDOUT: ret void, !dbg !40 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define i32 @_CCallCallF.Main() #4 !dbg !41 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: %CallF.call = call i32 @_Z5CallFv(), !dbg !44 +// CHECK:STDOUT: ret i32 %CallF.call, !dbg !45 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } // CHECK:STDOUT: attributes #1 = { 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 = { nounwind } +// 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.module.flags = !{!0, !1, !2, !3, !4} // CHECK:STDOUT: !llvm.dbg.cu = !{!5} @@ -233,25 +298,35 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: !20 = !DILocalVariable(arg: 1, scope: !14, type: !18) // CHECK:STDOUT: !21 = !DILocalVariable(arg: 2, scope: !14, type: !17) // CHECK:STDOUT: !22 = !DILocation(line: 8, column: 5, scope: !14) -// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.A.Main", scope: null, file: !6, line: 6, type: !24, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !26) +// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.A.Main", scope: null, file: !6, line: 5, type: !24, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !26) // CHECK:STDOUT: !24 = !DISubroutineType(types: !25) -// CHECK:STDOUT: !25 = !{null, !18, !17, !17} -// CHECK:STDOUT: !26 = !{!27, !28, !29} +// CHECK:STDOUT: !25 = !{null, !18} +// CHECK:STDOUT: !26 = !{!27} // CHECK:STDOUT: !27 = !DILocalVariable(arg: 1, scope: !23, type: !18) -// CHECK:STDOUT: !28 = !DILocalVariable(arg: 2, scope: !23, type: !17) -// CHECK:STDOUT: !29 = !DILocalVariable(arg: 3, scope: !23, type: !17) -// CHECK:STDOUT: !30 = !DILocation(line: 6, column: 3, scope: !23) -// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "CallCallF", linkageName: "_CCallCallF.Main", scope: null, file: !6, line: 18, type: !32, spFlags: DISPFlagDefinition, unit: !5) -// CHECK:STDOUT: !32 = !DISubroutineType(types: !33) -// CHECK:STDOUT: !33 = !{!17} -// CHECK:STDOUT: !34 = !DILocation(line: 18, column: 32, scope: !31) -// CHECK:STDOUT: !35 = !DILocation(line: 18, column: 25, scope: !31) +// CHECK:STDOUT: !28 = !DILocation(line: 5, column: 1, scope: !23) +// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "Op", linkageName: "_COp.1afa5e4ee26f3f8f:core.Destroy.Core", scope: null, file: !6, line: 5, type: !24, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !30) +// CHECK:STDOUT: !30 = !{!31} +// CHECK:STDOUT: !31 = !DILocalVariable(arg: 1, scope: !29, type: !18) +// CHECK:STDOUT: !32 = !DILocation(line: 5, column: 1, scope: !29) +// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.A.Main", scope: null, file: !6, line: 6, type: !34, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !36) +// CHECK:STDOUT: !34 = !DISubroutineType(types: !35) +// CHECK:STDOUT: !35 = !{null, !18, !17, !17} +// CHECK:STDOUT: !36 = !{!37, !38, !39} +// CHECK:STDOUT: !37 = !DILocalVariable(arg: 1, scope: !33, type: !18) +// CHECK:STDOUT: !38 = !DILocalVariable(arg: 2, scope: !33, type: !17) +// CHECK:STDOUT: !39 = !DILocalVariable(arg: 3, scope: !33, type: !17) +// CHECK:STDOUT: !40 = !DILocation(line: 6, column: 3, scope: !33) +// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "CallCallF", linkageName: "_CCallCallF.Main", scope: null, file: !6, line: 18, type: !42, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !42 = !DISubroutineType(types: !43) +// CHECK:STDOUT: !43 = !{!17} +// CHECK:STDOUT: !44 = !DILocation(line: 18, column: 32, scope: !41) +// CHECK:STDOUT: !45 = !DILocation(line: 18, column: 25, scope: !41) // CHECK:STDOUT: ; ModuleID = 'static.carbon' // CHECK:STDOUT: source_filename = "static.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: mustprogress uwtable +// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable // CHECK:STDOUT: define dso_local void @_Z5CallFv() #0 { // CHECK:STDOUT: entry: // CHECK:STDOUT: call void @_ZN6Carbon1A1FEv() @@ -271,23 +346,37 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: ret void, !dbg !14 // CHECK:STDOUT: } // CHECK:STDOUT: -// CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CF__carbon_thunk.A.Main() #2 !dbg !15 { +// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind +// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.A.Main"(ptr %self) #3 !dbg !15 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_CF.A.Main(), !dbg !16 -// CHECK:STDOUT: ret void, !dbg !16 +// CHECK:STDOUT: call void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self), !dbg !21 +// CHECK:STDOUT: ret void, !dbg !21 // CHECK:STDOUT: } // CHECK:STDOUT: // CHECK:STDOUT: ; Function Attrs: nounwind -// CHECK:STDOUT: define void @_CCallCallF.Main() #2 !dbg !17 { +// CHECK:STDOUT: define weak_odr void @"_COp.1afa5e4ee26f3f8f:core.Destroy.Core"(ptr %self) #2 !dbg !22 { // CHECK:STDOUT: entry: -// CHECK:STDOUT: call void @_Z5CallFv(), !dbg !18 -// CHECK:STDOUT: ret void, !dbg !19 +// CHECK:STDOUT: ret void, !dbg !25 // CHECK:STDOUT: } // 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: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CF__carbon_thunk.A.Main() #2 !dbg !26 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_CF.A.Main(), !dbg !27 +// CHECK:STDOUT: ret void, !dbg !27 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: ; Function Attrs: nounwind +// CHECK:STDOUT: define void @_CCallCallF.Main() #2 !dbg !28 { +// CHECK:STDOUT: entry: +// CHECK:STDOUT: call void @_Z5CallFv(), !dbg !29 +// CHECK:STDOUT: ret void, !dbg !30 +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: attributes #0 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } // CHECK:STDOUT: attributes #1 = { 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 #2 = { nounwind } +// CHECK:STDOUT: attributes #3 = { alwaysinline nounwind } // CHECK:STDOUT: // CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4} // CHECK:STDOUT: !llvm.dbg.cu = !{!5} @@ -308,8 +397,19 @@ fn CallCallF() { Cpp.CallF(); } // CHECK:STDOUT: !12 = !DISubroutineType(types: !13) // CHECK:STDOUT: !13 = !{null} // CHECK:STDOUT: !14 = !DILocation(line: 6, column: 3, scope: !11) -// CHECK:STDOUT: !15 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.A.Main", scope: null, file: !6, line: 6, type: !12, spFlags: DISPFlagDefinition, unit: !5) -// CHECK:STDOUT: !16 = !DILocation(line: 6, column: 3, scope: !15) -// CHECK:STDOUT: !17 = distinct !DISubprogram(name: "CallCallF", linkageName: "_CCallCallF.Main", scope: null, file: !6, line: 15, type: !12, spFlags: DISPFlagDefinition, unit: !5) -// CHECK:STDOUT: !18 = !DILocation(line: 15, column: 18, scope: !17) -// CHECK:STDOUT: !19 = !DILocation(line: 15, column: 1, scope: !17) +// CHECK:STDOUT: !15 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.A.Main", scope: null, file: !6, line: 5, type: !16, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !19) +// CHECK:STDOUT: !16 = !DISubroutineType(types: !17) +// CHECK:STDOUT: !17 = !{null, !18} +// CHECK:STDOUT: !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +// CHECK:STDOUT: !19 = !{!20} +// CHECK:STDOUT: !20 = !DILocalVariable(arg: 1, scope: !15, type: !18) +// CHECK:STDOUT: !21 = !DILocation(line: 5, column: 1, scope: !15) +// CHECK:STDOUT: !22 = distinct !DISubprogram(name: "Op", linkageName: "_COp.1afa5e4ee26f3f8f:core.Destroy.Core", scope: null, file: !6, line: 5, type: !16, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !23) +// CHECK:STDOUT: !23 = !{!24} +// CHECK:STDOUT: !24 = !DILocalVariable(arg: 1, scope: !22, type: !18) +// CHECK:STDOUT: !25 = !DILocation(line: 5, column: 1, scope: !22) +// CHECK:STDOUT: !26 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.A.Main", scope: null, file: !6, line: 6, type: !12, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !27 = !DILocation(line: 6, column: 3, scope: !26) +// CHECK:STDOUT: !28 = distinct !DISubprogram(name: "CallCallF", linkageName: "_CCallCallF.Main", scope: null, file: !6, line: 15, type: !12, spFlags: DISPFlagDefinition, unit: !5) +// CHECK:STDOUT: !29 = !DILocation(line: 15, column: 18, scope: !28) +// CHECK:STDOUT: !30 = !DILocation(line: 15, column: 1, scope: !28)