Export virtual functions when exporting a class definition (#7210)

This allows Clang to correctly generate the vtable for the exported
class.

There's still something wrong with new virtual functions in the Carbon
type (left a TODO) - I thought it might be related to not flagging
the CXXMethodDecl as virtual, but my initial experiments don't seem to
back that up, so I'll look into it further separately.

There's also a test regression due to an virtual (well, abstract
specifically, but I think it'd happen with a virtual one too) function
in an abstract class taking `self` by value being rejected since
the abstract class can't be instantiated. Not sure if this is a correct
change - the test's behavior could be preserved by using `ref self`
instnead of `self` in this function. Is that reasonable/expected? Should
we not require a type to be complete when passing by value if we can
compute the value representation without such completeness?

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
David Blaikie
2026-05-15 23:53:12 +00:00
committed by GitHub
co-authored by Richard Smith
parent 6d5a883d6d
commit 843323b864
4 changed files with 226 additions and 174 deletions
+45 -9
View File
@@ -355,6 +355,9 @@ class CarbonExternalASTSource : public clang::ExternalASTSource {
auto MapInstIdToClangDeclOrType(LookupResult lookup)
-> std::variant<clang::NamedDecl*, clang::QualType>;
auto GetOrExportFunctionToCpp(SemIR::InstId target_inst_id,
SemIR::FunctionId function_id)
-> clang::FunctionDecl*;
// Get a current best-effort location for the current position within C++
// processing.
auto GetCurrentCppLocId() -> SemIR::LocId {
@@ -426,15 +429,8 @@ auto CarbonExternalASTSource::MapInstIdToClangDeclOrType(LookupResult lookup)
return nullptr;
}
const SemIR::Function& function =
context_->functions().Get(callee_function->function_id);
if (function.clang_decl_id.has_value()) {
return cast<clang::NamedDecl>(
context_->clang_decls().Get(function.clang_decl_id).key.decl);
}
return ExportFunctionToCpp(*context_, SemIR::LocId(target_inst_id),
callee_function->function_id);
return GetOrExportFunctionToCpp(target_inst_id,
callee_function->function_id);
}
case CARBON_KIND(SemIR::FieldDecl field_decl): {
return ExportFieldToCpp(*context_, target_inst_id, field_decl);
@@ -444,6 +440,19 @@ auto CarbonExternalASTSource::MapInstIdToClangDeclOrType(LookupResult lookup)
}
}
auto CarbonExternalASTSource::GetOrExportFunctionToCpp(
SemIR::InstId target_inst_id, SemIR::FunctionId function_id)
-> clang::FunctionDecl* {
const SemIR::Function& function = context_->functions().Get(function_id);
if (function.clang_decl_id.has_value()) {
return cast<clang::FunctionDecl>(
context_->clang_decls().Get(function.clang_decl_id).key.decl);
}
return ExportFunctionToCpp(*context_, SemIR::LocId(target_inst_id),
function_id);
}
auto CarbonExternalASTSource::BuildCarbonNamespace() -> void {
static const llvm::StringLiteral carbon_namespace_name = "Carbon";
auto& ast_context = context_->ast_context();
@@ -653,6 +662,33 @@ auto CarbonExternalASTSource::CompleteType(clang::TagDecl* tag_decl) -> void {
class_decl->addDecl(ExportDestructorToCpp(*context_, class_info, class_decl));
// TODO: Import any special member functions that affect class properties.
if (class_info.vtable_decl_id.has_value()) {
auto vtable_inst_block = context_->inst_blocks().Get(
context_->vtables()
.Get(context_->insts()
.GetAs<SemIR::VtableDecl>(class_info.vtable_decl_id)
.vtable_id)
.virtual_functions_id);
for (auto vtable_entry_id : vtable_inst_block) {
if (!vtable_entry_id.has_value()) {
continue;
}
auto callee_function =
GetCalleeAsFunction(context_->sem_ir(), vtable_entry_id);
const SemIR::Function& function =
context_->functions().Get(callee_function.function_id);
// If this is a member of a base class, nothing to do here.
if (function.parent_scope_id != class_info.scope_id) {
continue;
}
auto* method_decl = cast<clang::CXXMethodDecl>(GetOrExportFunctionToCpp(
vtable_entry_id, callee_function.function_id));
context_->clang_sema().AddOverriddenMethods(class_decl, method_decl);
}
}
class_decl->completeDefinition();
}
@@ -133,6 +133,16 @@ import Cpp;
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR:
abstract class Abstract {
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE+10]]:3: error: initialization of abstract type `Abstract` [AbstractTypeInInit]
// CHECK:STDERR: abstract fn F[self: Self]();
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE-4]]:1: note: class was declared abstract here [ClassAbstractHere]
// CHECK:STDERR: abstract class Abstract {
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~
// CHECK:STDERR: fail_todo_abstract_nonvirtual_dtor_but_virtual_fns.carbon:[[@LINE+4]]:17: note: initializing function parameter [InCallToFunctionParam]
// CHECK:STDERR: abstract fn F[self: Self]();
// CHECK:STDERR: ^~~~~~~~~~
// CHECK:STDERR:
abstract fn F[self: Self]();
}
+123 -148
View File
@@ -19,31 +19,26 @@ import Cpp;
inline Cpp '''
struct FurtherBase {
virtual auto further_base_func() -> int {
return 11;
}
virtual auto further_base_func() -> void;
};
struct Base: FurtherBase {
int i;
virtual auto func() -> int {
return 7;
}
virtual auto func() & -> void;
};
auto Use(Base& b) -> int {
return b.func();
__attribute__((optnone)) auto Use(Base& b) {
}
''';
base class Derived {
extend base: Cpp.Base;
// TODO: `other_func` should appear in the vtable (it currently
// doesn't because the CXXRecordDecl we export has no CXXMethodDecl
// children - those need to be added, and in the right order)
virtual fn other_func[unused self: Self]() -> i32 {
return 3;
// TODO: `other_func` should appear in the vtable (it currently doesn't
// maybe because the CXXMethodDecl isn't marked as virtual)
virtual fn other_func[unused self: Self]() {
}
override fn func[unused ref self: Self]() {
}
}
@@ -56,9 +51,9 @@ void WorkaroundToEmitCtorAndVtable() {
// TODO: Carbon lowering should emit initialization that refers to the
// Clang-lowered vtable.
auto DoThing() -> int {
auto DoThing() -> void {
Carbon::Derived d;
return Use(d);
Use(d);
}
''';
@@ -76,10 +71,6 @@ auto DoThing() -> int {
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZN6Carbon7DerivedD2Ev = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZN11FurtherBase17further_base_funcEv = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZN4Base4funcEv = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZN4BaseC2Ev = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZN11FurtherBaseC2Ev = comdat any
@@ -90,51 +81,31 @@ auto DoThing() -> int {
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZTSN6Carbon7DerivedE = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZTI4Base = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZTS4Base = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZTI11FurtherBase = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZTS11FurtherBase = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZTV4Base = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: $_ZTV11FurtherBase = comdat any
// CHECK:STDOUT:
// CHECK:STDOUT: @_ZTVN6Carbon7DerivedE = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIN6Carbon7DerivedE, ptr @_ZN11FurtherBase17further_base_funcEv, ptr @_ZN4Base4funcEv] }, comdat, align 8
// CHECK:STDOUT: @_ZTVN6Carbon7DerivedE = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIN6Carbon7DerivedE, ptr @_ZN11FurtherBase17further_base_funcEv, ptr @_ZNR6Carbon7Derived4funcEv] }, comdat, align 8
// CHECK:STDOUT: @_ZTIN6Carbon7DerivedE = linkonce_odr dso_local constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTSN6Carbon7DerivedE, ptr @_ZTI4Base }, comdat, align 8
// CHECK:STDOUT: @_ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
// CHECK:STDOUT: @_ZTSN6Carbon7DerivedE = linkonce_odr dso_local constant [18 x i8] c"N6Carbon7DerivedE\00", comdat, align 1
// CHECK:STDOUT: @_ZTI4Base = linkonce_odr dso_local constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTS4Base, ptr @_ZTI11FurtherBase }, comdat, align 8
// CHECK:STDOUT: @_ZTS4Base = linkonce_odr dso_local constant [6 x i8] c"4Base\00", comdat, align 1
// CHECK:STDOUT: @_ZTI11FurtherBase = linkonce_odr dso_local constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS11FurtherBase }, comdat, align 8
// CHECK:STDOUT: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
// CHECK:STDOUT: @_ZTS11FurtherBase = linkonce_odr dso_local constant [14 x i8] c"11FurtherBase\00", comdat, align 1
// CHECK:STDOUT: @_ZTV4Base = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI4Base, ptr @_ZN11FurtherBase17further_base_funcEv, ptr @_ZN4Base4funcEv] }, comdat, align 8
// CHECK:STDOUT: @_ZTV11FurtherBase = linkonce_odr dso_local unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr @_ZTI11FurtherBase, ptr @_ZN11FurtherBase17further_base_funcEv] }, comdat, align 8
// CHECK:STDOUT: @_ZTI4Base = external constant ptr
// CHECK:STDOUT: @_ZTV4Base = available_externally unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI4Base, ptr @_ZN11FurtherBase17further_base_funcEv, ptr @_ZNR4Base4funcEv] }, align 8
// CHECK:STDOUT: @_ZTV11FurtherBase = available_externally unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr @_ZTI11FurtherBase, ptr @_ZN11FurtherBase17further_base_funcEv] }, align 8
// CHECK:STDOUT: @_ZTI11FurtherBase = external constant ptr
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable
// CHECK:STDOUT: define dso_local noundef i32 @_Z3UseR4Base(ptr noundef nonnull align 8 dereferenceable(12) %b) #0 {
// CHECK:STDOUT: ; Function Attrs: mustprogress noinline nounwind optnone uwtable
// CHECK:STDOUT: define dso_local void @_Z3UseR4Base(ptr noundef nonnull align 8 dereferenceable(12) %b) #0 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %b.addr = alloca ptr, align 8
// CHECK:STDOUT: store ptr %b, ptr %b.addr, align 8, !tbaa !11
// CHECK:STDOUT: %0 = load ptr, ptr %b.addr, align 8, !tbaa !11, !nonnull !14, !align !15
// CHECK:STDOUT: %vtable = load ptr, ptr %0, align 8, !tbaa !16
// CHECK:STDOUT: %vfn = getelementptr inbounds ptr, ptr %vtable, i64 1
// CHECK:STDOUT: %1 = load ptr, ptr %vfn, align 8
// CHECK:STDOUT: %call = call noundef i32 %1(ptr noundef nonnull align 8 dereferenceable(12) %0)
// CHECK:STDOUT: ret i32 %call
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
// CHECK:STDOUT: define dso_local void @_Z29WorkaroundToEmitCtorAndVtablev() #1 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %d = alloca %"class.Carbon::Derived", align 8
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #4
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #4
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #4
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #4
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #5
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #5
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #5
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
@@ -145,9 +116,9 @@ auto DoThing() -> int {
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 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 !18
// 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 @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1) #4
// CHECK:STDOUT: call void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1) #5
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTVN6Carbon7DerivedE, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !16
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
@@ -156,7 +127,7 @@ auto DoThing() -> int {
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedD2Ev(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 !18
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !14
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTVN6Carbon7DerivedE, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !16
// CHECK:STDOUT: call void @"_C__destroy_thunk:thunk.Derived.Main"(ptr noundef nonnull align 8 dereferenceable(12) %this1)
@@ -166,123 +137,120 @@ auto DoThing() -> int {
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
// CHECK:STDOUT: declare void @llvm.lifetime.end.p0(ptr captures(none)) #2
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable
// CHECK:STDOUT: define dso_local noundef i32 @_Z7DoThingv() #0 personality ptr @__gxx_personality_v0 {
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
// CHECK:STDOUT: define dso_local void @_Z7DoThingv() #1 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %d = alloca %"class.Carbon::Derived", align 8
// CHECK:STDOUT: %exn.slot = alloca ptr, align 8
// CHECK:STDOUT: %ehselector.slot = alloca i32, align 4
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #4
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #4
// CHECK:STDOUT: %call = invoke noundef i32 @_Z3UseR4Base(ptr noundef nonnull align 8 dereferenceable(12) %d)
// CHECK:STDOUT: to label %invoke.cont unwind label %lpad
// CHECK:STDOUT:
// CHECK:STDOUT: invoke.cont: ; preds = %entry
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #4
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #4
// CHECK:STDOUT: ret i32 %call
// CHECK:STDOUT:
// CHECK:STDOUT: lpad: ; preds = %entry
// CHECK:STDOUT: %0 = landingpad { ptr, i32 }
// CHECK:STDOUT: cleanup
// CHECK:STDOUT: %1 = extractvalue { ptr, i32 } %0, 0
// CHECK:STDOUT: store ptr %1, ptr %exn.slot, align 8
// CHECK:STDOUT: %2 = extractvalue { ptr, i32 } %0, 1
// CHECK:STDOUT: store i32 %2, ptr %ehselector.slot, align 4
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #4
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #4
// CHECK:STDOUT: br label %eh.resume
// CHECK:STDOUT:
// CHECK:STDOUT: eh.resume: ; preds = %lpad
// CHECK:STDOUT: %exn = load ptr, ptr %exn.slot, align 8
// CHECK:STDOUT: %sel = load i32, ptr %ehselector.slot, align 4
// CHECK:STDOUT: %lpad.val = insertvalue { ptr, i32 } poison, ptr %exn, 0
// CHECK:STDOUT: %lpad.val1 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1
// CHECK:STDOUT: resume { ptr, i32 } %lpad.val1
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
// CHECK:STDOUT: uselistorder ptr %d, { 0, 2, 1, 3, 4, 5, 6 }
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %d) #5
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #5
// CHECK:STDOUT: call void @_Z3UseR4Base(ptr noundef nonnull align 8 dereferenceable(12) %d)
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d) #5
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: declare i32 @__gxx_personality_v0(...)
// CHECK:STDOUT: declare void @_ZN11FurtherBase17further_base_funcEv(ptr noundef nonnull align 8 dereferenceable(8)) unnamed_addr #4
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
// CHECK:STDOUT: define linkonce_odr dso_local noundef i32 @_ZN11FurtherBase17further_base_funcEv(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #1 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 !20
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
// CHECK:STDOUT: ret i32 11
// CHECK:STDOUT: }
// CHECK:STDOUT: declare void @_ZNR4Base4funcEv(ptr noundef nonnull align 8 dereferenceable(12)) unnamed_addr #4
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: mustprogress nounwind uwtable
// CHECK:STDOUT: define linkonce_odr dso_local noundef i32 @_ZN4Base4funcEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #1 comdat align 2 {
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define void @_Cother_func.Derived.Main(ptr %self) #5 !dbg !18 {
// 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: ret i32 7
// CHECK:STDOUT: ret void, !dbg !24
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define i32 @_Cother_func.Derived.Main(ptr %self) #4 !dbg !22 {
// CHECK:STDOUT: define void @_Cfunc.Derived.Main(ptr %self) #5 !dbg !25 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret i32 3, !dbg !29
// CHECK:STDOUT: ret void, !dbg !28
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #5 !dbg !30 {
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #6 !dbg !29 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: call void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self), !dbg !35
// CHECK:STDOUT: ret void, !dbg !35
// CHECK:STDOUT: call void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self), !dbg !32
// CHECK:STDOUT: ret void, !dbg !32
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define weak_odr void @"_COp.bfe31446004e2b71:core.Destroy.Core"(ptr %self) #4 !dbg !36 {
// CHECK:STDOUT: define weak_odr void @"_COp.bfe31446004e2b71:core.Destroy.Core"(ptr %self) #5 !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.12e0d0434542305a:core.Destroy.Core"(ptr %self) #4 !dbg !40 {
// CHECK:STDOUT: define weak_odr void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self) #5 !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 @_Cfunc__carbon_thunk.Derived.Main(ptr %self) #5 !dbg !41 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %Derived.func.call.vtable = load ptr, ptr %self, align 8, !dbg !44
// CHECK:STDOUT: %Derived.func.call = call ptr @llvm.load.relative.i32(ptr %Derived.func.call.vtable, i32 4), !dbg !44
// CHECK:STDOUT: call void %Derived.func.call(ptr %self), !dbg !44
// CHECK:STDOUT: ret void, !dbg !44
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define void @_Cother_func__carbon_thunk.Derived.Main(ptr %self) #5 !dbg !45 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %Derived.other_func.call.vtable = load ptr, ptr %self, align 8, !dbg !48
// CHECK:STDOUT: %Derived.other_func.call = call ptr @llvm.load.relative.i32(ptr %Derived.other_func.call.vtable, i32 8), !dbg !48
// CHECK:STDOUT: call void %Derived.other_func.call(ptr %self), !dbg !48
// CHECK:STDOUT: ret void, !dbg !48
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
// CHECK:STDOUT: declare ptr @llvm.load.relative.i32(ptr, i32) #7
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 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 @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1) #4
// CHECK:STDOUT: call void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1) #5
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 16) ({ [4 x ptr] }, ptr @_ZTV4Base, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !16
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress nounwind uwtable
// CHECK:STDOUT: define internal void @_ZNR6Carbon7Derived4funcEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #8 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 @_Cfunc__carbon_thunk.Derived.Main(ptr noundef nonnull align 8 dereferenceable(12) %this1)
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %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 !20
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !49
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV11FurtherBase, i32 0, i32 0, i32 2), ptr %this1, align 8, !tbaa !16
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
// CHECK:STDOUT: uselistorder ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), { 1, 0 }
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon7DerivedC2Ev, { 1, 0 }
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon7DerivedD2Ev, { 2, 1, 0 }
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon7DerivedD2Ev, { 1, 0 }
// CHECK:STDOUT: uselistorder ptr @_ZN11FurtherBase17further_base_funcEv, { 2, 1, 0 }
// CHECK:STDOUT: uselistorder ptr @_ZN4Base4funcEv, { 1, 0 }
// CHECK:STDOUT: uselistorder ptr @llvm.load.relative.i32, { 1, 0 }
// CHECK:STDOUT:
// CHECK:STDOUT: attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
// CHECK:STDOUT: attributes #0 = { mustprogress noinline nounwind optnone 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 = { 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 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
// 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: 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: attributes #5 = { nounwind }
// CHECK:STDOUT: attributes #6 = { alwaysinline nounwind }
// CHECK:STDOUT: attributes #7 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
// CHECK:STDOUT: attributes #8 = { 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:
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4}
// CHECK:STDOUT: !llvm.dbg.cu = !{!5}
@@ -302,33 +270,40 @@ auto DoThing() -> int {
// CHECK:STDOUT: !11 = !{!12, !12, i64 0}
// CHECK:STDOUT: !12 = !{!"p1 _ZTS4Base", !13, i64 0}
// CHECK:STDOUT: !13 = !{!"any pointer", !9, i64 0}
// CHECK:STDOUT: !14 = !{}
// CHECK:STDOUT: !15 = !{i64 8}
// CHECK:STDOUT: !14 = !{!15, !15, i64 0}
// CHECK:STDOUT: !15 = !{!"p1 _ZTSN6Carbon7DerivedE", !13, i64 0}
// CHECK:STDOUT: !16 = !{!17, !17, i64 0}
// CHECK:STDOUT: !17 = !{!"vtable pointer", !10, i64 0}
// CHECK:STDOUT: !18 = !{!19, !19, i64 0}
// CHECK:STDOUT: !19 = !{!"p1 _ZTSN6Carbon7DerivedE", !13, i64 0}
// CHECK:STDOUT: !20 = !{!21, !21, i64 0}
// CHECK:STDOUT: !21 = !{!"p1 _ZTS11FurtherBase", !13, i64 0}
// CHECK:STDOUT: !22 = distinct !DISubprogram(name: "other_func", linkageName: "_Cother_func.Derived.Main", scope: null, file: !6, line: 32, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !27)
// CHECK:STDOUT: !23 = !DISubroutineType(types: !24)
// CHECK:STDOUT: !24 = !{!25, !26}
// CHECK:STDOUT: !25 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
// CHECK:STDOUT: !26 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
// CHECK:STDOUT: !27 = !{!28}
// CHECK:STDOUT: !28 = !DILocalVariable(arg: 1, scope: !22, type: !26)
// CHECK:STDOUT: !29 = !DILocation(line: 33, column: 5, scope: !22)
// CHECK:STDOUT: !30 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Derived.Main", scope: null, file: !6, line: 27, type: !31, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !33)
// CHECK:STDOUT: !31 = !DISubroutineType(types: !32)
// CHECK:STDOUT: !32 = !{null, !26}
// CHECK:STDOUT: !33 = !{!34}
// CHECK:STDOUT: !34 = !DILocalVariable(arg: 1, scope: !30, type: !26)
// CHECK:STDOUT: !35 = !DILocation(line: 27, column: 1, scope: !30)
// CHECK:STDOUT: !36 = distinct !DISubprogram(name: "Op", linkageName: "_COp.bfe31446004e2b71:core.Destroy.Core", scope: null, file: !6, line: 27, type: !31, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !37)
// CHECK:STDOUT: !37 = !{!38}
// CHECK:STDOUT: !38 = !DILocalVariable(arg: 1, scope: !36, type: !26)
// CHECK:STDOUT: !39 = !DILocation(line: 27, column: 1, scope: !36)
// CHECK:STDOUT: !40 = distinct !DISubprogram(name: "Op", linkageName: "_COp.12e0d0434542305a:core.Destroy.Core", scope: null, file: !6, line: 27, type: !31, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !41)
// CHECK:STDOUT: !41 = !{!42}
// CHECK:STDOUT: !42 = !DILocalVariable(arg: 1, scope: !40, type: !26)
// CHECK:STDOUT: !43 = !DILocation(line: 27, column: 1, scope: !40)
// CHECK:STDOUT: !18 = distinct !DISubprogram(name: "other_func", linkageName: "_Cother_func.Derived.Main", scope: null, file: !6, line: 26, 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: 26, column: 3, scope: !18)
// CHECK:STDOUT: !25 = distinct !DISubprogram(name: "func", linkageName: "_Cfunc.Derived.Main", scope: null, file: !6, line: 28, 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: 28, column: 3, scope: !25)
// CHECK:STDOUT: !29 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Derived.Main", scope: null, file: !6, line: 22, 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: 22, column: 1, scope: !29)
// CHECK:STDOUT: !33 = distinct !DISubprogram(name: "Op", linkageName: "_COp.bfe31446004e2b71:core.Destroy.Core", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !34)
// CHECK:STDOUT: !34 = !{!35}
// CHECK:STDOUT: !35 = !DILocalVariable(arg: 1, scope: !33, type: !21)
// CHECK:STDOUT: !36 = !DILocation(line: 22, column: 1, scope: !33)
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "Op", linkageName: "_COp.12e0d0434542305a:core.Destroy.Core", scope: null, file: !6, line: 22, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38)
// CHECK:STDOUT: !38 = !{!39}
// CHECK:STDOUT: !39 = !DILocalVariable(arg: 1, scope: !37, type: !21)
// CHECK:STDOUT: !40 = !DILocation(line: 22, column: 1, scope: !37)
// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "func__carbon_thunk", linkageName: "_Cfunc__carbon_thunk.Derived.Main", scope: null, file: !6, line: 28, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !42)
// CHECK:STDOUT: !42 = !{!43}
// CHECK:STDOUT: !43 = !DILocalVariable(arg: 1, scope: !41, type: !21)
// CHECK:STDOUT: !44 = !DILocation(line: 28, column: 3, scope: !41)
// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "other_func__carbon_thunk", linkageName: "_Cother_func__carbon_thunk.Derived.Main", scope: null, file: !6, line: 26, type: !19, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !46)
// CHECK:STDOUT: !46 = !{!47}
// CHECK:STDOUT: !47 = !DILocalVariable(arg: 1, scope: !45, type: !21)
// CHECK:STDOUT: !48 = !DILocation(line: 26, column: 3, scope: !45)
// CHECK:STDOUT: !49 = !{!50, !50, i64 0}
// CHECK:STDOUT: !50 = !{!"p1 _ZTS11FurtherBase", !13, i64 0}
+48 -17
View File
@@ -95,7 +95,7 @@ void delete_new_Base() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %p = alloca ptr, align 8
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %p) #8
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #10
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #11
// CHECK:STDOUT: call void @_ZN6Carbon5FinalC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %call) #8
// CHECK:STDOUT: store ptr %call, ptr %p, align 8, !tbaa !11
// CHECK:STDOUT: %0 = load ptr, ptr %p, align 8, !tbaa !11
@@ -104,7 +104,7 @@ void delete_new_Base() {
// CHECK:STDOUT:
// CHECK:STDOUT: delete.notnull: ; preds = %entry
// CHECK:STDOUT: call void @_ZN6Carbon5FinalD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %0) #8
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %0, i64 noundef 8) #11
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %0, i64 noundef 8) #12
// CHECK:STDOUT: br label %delete.end
// CHECK:STDOUT:
// CHECK:STDOUT: delete.end: ; preds = %delete.notnull, %entry
@@ -151,7 +151,7 @@ void delete_new_Base() {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %p = alloca ptr, align 8
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %p) #8
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #10
// CHECK:STDOUT: %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 8) #11
// CHECK:STDOUT: call void @_ZN6Carbon4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %call) #8
// CHECK:STDOUT: store ptr %call, ptr %p, align 8, !tbaa !16
// CHECK:STDOUT: %0 = load ptr, ptr %p, align 8, !tbaa !16
@@ -220,19 +220,40 @@ void delete_new_Base() {
// CHECK:STDOUT: ret void, !dbg !36
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Base.Main"(ptr %self) #6 !dbg !37 {
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define void @_CF__carbon_thunk.Final.Main(ptr %self) #8 !dbg !37 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: call void @"_COp.96a711151205ee34:core.Destroy.Core"(ptr %self), !dbg !40
// CHECK:STDOUT: %Final.F.call.vtable = load ptr, ptr %self, align 8, !dbg !40
// CHECK:STDOUT: %Final.F.call = call ptr @llvm.load.relative.i32(ptr %Final.F.call.vtable, i32 8), !dbg !40
// CHECK:STDOUT: call void %Final.F.call(ptr %self), !dbg !40
// CHECK:STDOUT: ret void, !dbg !40
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define weak_odr void @"_COp.96a711151205ee34:core.Destroy.Core"(ptr %self) #8 !dbg !41 {
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Base.Main"(ptr %self) #6 !dbg !41 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: call void @"_COp.96a711151205ee34:core.Destroy.Core"(ptr %self), !dbg !44
// CHECK:STDOUT: ret void, !dbg !44
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define weak_odr void @"_COp.96a711151205ee34:core.Destroy.Core"(ptr %self) #8 !dbg !45 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: ret void, !dbg !48
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nounwind
// CHECK:STDOUT: define void @_CF__carbon_thunk.Base.Main(ptr %self) #8 !dbg !49 {
// CHECK:STDOUT: entry:
// CHECK:STDOUT: %Base.F.call.vtable = load ptr, ptr %self, align 8, !dbg !52
// CHECK:STDOUT: %Base.F.call = call ptr @llvm.load.relative.i32(ptr %Base.F.call.vtable, i32 8), !dbg !52
// CHECK:STDOUT: call void %Base.F.call(ptr %self), !dbg !52
// CHECK:STDOUT: ret void, !dbg !52
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
// CHECK:STDOUT: declare ptr @llvm.load.relative.i32(ptr, i32) #9
// CHECK:STDOUT:
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN1AC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #3 comdat align 2 {
// CHECK:STDOUT: entry:
@@ -250,11 +271,11 @@ void delete_new_Base() {
// 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 @_ZN6Carbon5FinalD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %this1) #8
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #11
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #12
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: declare void @_ZNK1A1FEv(ptr noundef nonnull align 8 dereferenceable(8)) unnamed_addr #9
// CHECK:STDOUT: declare void @_ZNK1A1FEv(ptr noundef nonnull align 8 dereferenceable(8)) unnamed_addr #10
// CHECK:STDOUT:
// CHECK:STDOUT: declare void @__cxa_pure_virtual() unnamed_addr
// CHECK:STDOUT:
@@ -280,12 +301,13 @@ void delete_new_Base() {
// 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 @_ZN6Carbon4BaseD2Ev(ptr noundef nonnull align 8 dead_on_return(8) dereferenceable(8) %this1) #8
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #11
// CHECK:STDOUT: call void @_ZdlPvm(ptr noundef %this1, i64 noundef 8) #12
// CHECK:STDOUT: ret void
// CHECK:STDOUT: }
// CHECK:STDOUT:
// CHECK:STDOUT: ; uselistorder directives
// CHECK:STDOUT: uselistorder ptr @_ZN6Carbon5FinalD2Ev, { 2, 1, 0 }
// CHECK:STDOUT: uselistorder ptr @llvm.load.relative.i32, { 1, 0 }
// CHECK:STDOUT: uselistorder ptr @_ZN1AC2Ev, { 1, 0 }
// CHECK:STDOUT: uselistorder ptr @_ZNK1A1FEv, { 2, 1, 0 }
// CHECK:STDOUT: uselistorder ptr @__cxa_pure_virtual, { 1, 0 }
@@ -300,9 +322,10 @@ void delete_new_Base() {
// CHECK:STDOUT: attributes #6 = { alwaysinline nounwind }
// CHECK:STDOUT: attributes #7 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
// CHECK:STDOUT: attributes #8 = { nounwind }
// CHECK:STDOUT: attributes #9 = { "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 #10 = { builtin allocsize(0) }
// CHECK:STDOUT: attributes #11 = { builtin nounwind }
// CHECK:STDOUT: attributes #9 = { nocallback nofree nosync nounwind willreturn memory(argmem: read) }
// CHECK:STDOUT: attributes #10 = { "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 #11 = { builtin allocsize(0) }
// CHECK:STDOUT: attributes #12 = { builtin nounwind }
// CHECK:STDOUT:
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4}
// CHECK:STDOUT: !llvm.dbg.cu = !{!5}
@@ -345,11 +368,19 @@ void delete_new_Base() {
// CHECK:STDOUT: !34 = !{!35}
// CHECK:STDOUT: !35 = !DILocalVariable(arg: 1, scope: !33, type: !25)
// CHECK:STDOUT: !36 = !DILocation(line: 12, column: 1, scope: !33)
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Base.Main", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38)
// CHECK:STDOUT: !37 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.Final.Main", scope: null, file: !6, line: 14, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !38)
// CHECK:STDOUT: !38 = !{!39}
// CHECK:STDOUT: !39 = !DILocalVariable(arg: 1, scope: !37, type: !25)
// CHECK:STDOUT: !40 = !DILocation(line: 17, column: 1, scope: !37)
// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "Op", linkageName: "_COp.96a711151205ee34:core.Destroy.Core", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !42)
// CHECK:STDOUT: !40 = !DILocation(line: 14, column: 3, scope: !37)
// CHECK:STDOUT: !41 = distinct !DISubprogram(name: "__destroy_thunk", linkageName: "_C__destroy_thunk:thunk.Base.Main", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !42)
// CHECK:STDOUT: !42 = !{!43}
// CHECK:STDOUT: !43 = !DILocalVariable(arg: 1, scope: !41, type: !25)
// CHECK:STDOUT: !44 = !DILocation(line: 17, column: 1, scope: !41)
// CHECK:STDOUT: !45 = distinct !DISubprogram(name: "Op", linkageName: "_COp.96a711151205ee34:core.Destroy.Core", scope: null, file: !6, line: 17, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !46)
// CHECK:STDOUT: !46 = !{!47}
// CHECK:STDOUT: !47 = !DILocalVariable(arg: 1, scope: !45, type: !25)
// CHECK:STDOUT: !48 = !DILocation(line: 17, column: 1, scope: !45)
// CHECK:STDOUT: !49 = distinct !DISubprogram(name: "F__carbon_thunk", linkageName: "_CF__carbon_thunk.Base.Main", scope: null, file: !6, line: 19, type: !23, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !50)
// CHECK:STDOUT: !50 = !{!51}
// CHECK:STDOUT: !51 = !DILocalVariable(arg: 1, scope: !49, type: !25)
// CHECK:STDOUT: !52 = !DILocation(line: 19, column: 3, scope: !49)