mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:20:10 +01:00
Export Carbon classes as base / final / abstract. (#7191)
* For Carbon `base class C`, export as a regular C++ class. * For Carbon `class C`, export with the C++ `final` keyword attribute. * For Carbon `abstract C`, mark the destructor as pure virtual in cases where no member function is abstract, or emit an error if the destructor is not virtual. To support the final point, mark the destructor of an exported class as virtual if it overrides a virtual destructor from the base class. In passing, fix a crash exporting fields if the class has an invalid base type.
This commit is contained in:
@@ -76,8 +76,6 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN6Carbon7DerivedD2Ev = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $__clang_call_terminate = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN11FurtherBase17further_base_funcEv = comdat any
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: $_ZN4Base4funcEv = comdat any
|
||||
@@ -130,33 +128,33 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: ret i32 %call
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: mustprogress uwtable
|
||||
// CHECK:STDOUT: define dso_local void @_Z29WorkaroundToEmitCtorAndVtablev() #0 {
|
||||
// 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) #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)
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
|
||||
// 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: ret void
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #1
|
||||
// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #2 comdat align 2 {
|
||||
// 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: %this1 = load ptr, ptr %this.addr, align 8
|
||||
// CHECK:STDOUT: call void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1) #5
|
||||
// CHECK:STDOUT: call void @_ZN4BaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1) #4
|
||||
// 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: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %this) unnamed_addr #2 comdat align 2 {
|
||||
// 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
|
||||
@@ -167,7 +165,7 @@ auto DoThing() -> int {
|
||||
// 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: 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 {
|
||||
@@ -175,14 +173,14 @@ auto DoThing() -> int {
|
||||
// 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) #5
|
||||
// CHECK:STDOUT: call void @_ZN6Carbon7DerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %d) #5
|
||||
// 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)
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
|
||||
// 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
|
||||
@@ -192,26 +190,16 @@ auto DoThing() -> int {
|
||||
// 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: invoke void @_ZN6Carbon7DerivedD2Ev(ptr noundef nonnull align 8 dead_on_return(12) dereferenceable(12) %d)
|
||||
// CHECK:STDOUT: to label %invoke.cont1 unwind label %terminate.lpad
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: invoke.cont1: ; preds = %lpad
|
||||
// CHECK:STDOUT: call void @llvm.lifetime.end.p0(ptr %d) #5
|
||||
// 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 = %invoke.cont1
|
||||
// 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.val2 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1
|
||||
// CHECK:STDOUT: resume { ptr, i32 } %lpad.val2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: terminate.lpad: ; preds = %lpad
|
||||
// CHECK:STDOUT: %3 = landingpad { ptr, i32 }
|
||||
// CHECK:STDOUT: catch ptr null
|
||||
// CHECK:STDOUT: %4 = extractvalue { ptr, i32 } %3, 0
|
||||
// CHECK:STDOUT: call void @__clang_call_terminate(ptr %4) #7
|
||||
// CHECK:STDOUT: unreachable
|
||||
// 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 }
|
||||
@@ -219,19 +207,8 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare i32 @__gxx_personality_v0(...)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: noinline noreturn nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr hidden void @__clang_call_terminate(ptr noundef %0) #3 comdat {
|
||||
// CHECK:STDOUT: %2 = call ptr @__cxa_begin_catch(ptr %0) #5
|
||||
// CHECK:STDOUT: call void @_ZSt9terminatev() #7
|
||||
// CHECK:STDOUT: unreachable
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare ptr @__cxa_begin_catch(ptr)
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: declare void @_ZSt9terminatev()
|
||||
// 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 #4 comdat align 2 {
|
||||
// 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
|
||||
@@ -240,7 +217,7 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: }
|
||||
// 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 #4 comdat align 2 {
|
||||
// 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: entry:
|
||||
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
||||
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !11
|
||||
@@ -249,43 +226,43 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define i32 @_Cother_func.Derived.Main(ptr %self) #5 !dbg !22 {
|
||||
// CHECK:STDOUT: define i32 @_Cother_func.Derived.Main(ptr %self) #4 !dbg !22 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret i32 3, !dbg !29
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: alwaysinline nounwind
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #6 !dbg !30 {
|
||||
// CHECK:STDOUT: define void @"_C__destroy_thunk:thunk.Derived.Main"(ptr %self) #5 !dbg !30 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self), !dbg !35
|
||||
// CHECK:STDOUT: ret void, !dbg !35
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.bfe31446004e2b71:core.Destroy.Core"(ptr %self) #5 !dbg !36 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.bfe31446004e2b71:core.Destroy.Core"(ptr %self) #4 !dbg !36 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !39
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self) #5 !dbg !40 {
|
||||
// CHECK:STDOUT: define weak_odr void @"_COp.12e0d0434542305a:core.Destroy.Core"(ptr %self) #4 !dbg !40 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: ret void, !dbg !43
|
||||
// CHECK:STDOUT: }
|
||||
// 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 #2 comdat align 2 {
|
||||
// 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) #5
|
||||
// CHECK:STDOUT: call void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this1) #4
|
||||
// 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: inlinehint mustprogress nounwind uwtable
|
||||
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN11FurtherBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(8) %this) unnamed_addr #2 comdat align 2 {
|
||||
// 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
|
||||
@@ -302,13 +279,11 @@ auto DoThing() -> int {
|
||||
// CHECK:STDOUT: uselistorder ptr @_ZN4Base4funcEv, { 2, 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 #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT: attributes #2 = { 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 #3 = { noinline noreturn nounwind uwtable "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 = { 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 #5 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #6 = { alwaysinline nounwind }
|
||||
// CHECK:STDOUT: attributes #7 = { noreturn nounwind }
|
||||
// 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:
|
||||
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4}
|
||||
// CHECK:STDOUT: !llvm.dbg.cu = !{!5}
|
||||
|
||||
Reference in New Issue
Block a user