diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-07-22 13:51:44 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-07-22 13:51:44 +0000 |
commit | a4130baad9d10b7feabb7e003da53424e986d269 (patch) | |
tree | 6b153be413c9662233a02fad672aec2d6761d5f0 /test/CodeGenCXX/microsoft-abi-structors.cpp | |
parent | 73701ea646d067e5d26e83a95ae0e610f0e665ca (diff) |
[ms-cxxabi] Emit linkonce complete dtors in TUs that need them
Based on Peter Collingbourne's destructor patches.
Prior to this change, clang was considering ?1 to be the complete
destructor and the base destructor, which was wrong. This lead to
crashes when clang tried to emit two LLVM functions with the same name.
In this ABI, TUs with non-inline dtors might not emit a complete
destructor. They are emitted as inline thunks in TUs that need them,
and they always delegate to the base dtors of the complete class and its
virtual bases. This change uses the DeferredDecls machinery to emit
complete dtors as needed.
Currently in clang try body destructors can catch exceptions thrown by
virtual base destructors. In the Microsoft C++ ABI, clang may not have
the destructor definition, in which case clang won't wrap the virtual
virtual base destructor calls in a try-catch. Diagnosing this in user
code is TODO.
Finally, for classes that don't use virtual inheritance, MSVC always
calls the base destructor (?1) directly. This is a useful code size
optimization that avoids emitting lots of extra thunks or aliases.
Implementing it also means our existing tests continue to pass, and is
consistent with MSVC's output.
We can do the same for Itanium by tweaking GetAddrOfCXXDestructor, but
it will require further testing.
Reviewers: rjmccall
CC: cfe-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D1066
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186828 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CodeGenCXX/microsoft-abi-structors.cpp')
-rw-r--r-- | test/CodeGenCXX/microsoft-abi-structors.cpp | 79 |
1 files changed, 65 insertions, 14 deletions
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp index 6d43c7daf1..24be897b05 100644 --- a/test/CodeGenCXX/microsoft-abi-structors.cpp +++ b/test/CodeGenCXX/microsoft-abi-structors.cpp @@ -1,15 +1,15 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t 2>&1 +// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t // RUN: FileCheck %s < %t -// Using a different check prefix as the inline destructors might be placed -// anywhere in the output. -// RUN: FileCheck --check-prefix=DTORS %s < %t +// vftables are emitted very late, so do another pass to try to keep the checks +// in source order. +// RUN: FileCheck --check-prefix DTORS %s < %t namespace basic { class A { public: A() { } - ~A() { } + ~A(); }; void no_constructor_destructor_infinite_recursion() { @@ -21,7 +21,9 @@ void no_constructor_destructor_infinite_recursion() { // CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]] // CHECK-NEXT: ret %"class.basic::A"* [[T1]] // CHECK-NEXT: } +} +A::~A() { // Make sure that the destructor doesn't call itself: // CHECK: define {{.*}} @"\01??1A@basic@@QAE@XZ" // CHECK-NOT: call void @"\01??1A@basic@@QAE@XZ" @@ -40,12 +42,6 @@ B::B() { struct C { virtual ~C() { -// Complete destructor first: -// DTORS: define {{.*}} x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %this) - -// Then, the scalar deleting destructor (used in the vtable): -// FIXME: add a test that verifies that the out-of-line scalar deleting -// destructor is linkonce_odr too. // DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i1 zeroext %should_call_delete) // DTORS: %[[FROMBOOL:[0-9a-z]+]] = zext i1 %should_call_delete to i8 // DTORS-NEXT: store i8 %[[FROMBOOL]], i8* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 1 @@ -56,7 +52,7 @@ struct C { // // DTORS: [[CALL_DELETE_LABEL]] // DTORS-NEXT: %[[THIS_AS_VOID:[0-9a-z]+]] = bitcast %"struct.basic::C"* %[[THIS]] to i8* -// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[THIS_AS_VOID]]) [[NUW:#[0-9]+]] +// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[THIS_AS_VOID]]) // DTORS-NEXT: br label %[[CONTINUE_LABEL]] // // DTORS: [[CONTINUE_LABEL]] @@ -119,8 +115,6 @@ struct D { void use_D() { D c; } -// DTORS: attributes [[NUW]] = {{[{].*}} nounwind {{.*[}]}} - } // end namespace basic @@ -228,3 +222,60 @@ E::E() { } } // end namespace constructors + +namespace dtors { + +struct A { + ~A(); +}; + +void call_nv_complete(A *a) { + a->~A(); +// CHECK: define void @"\01?call_nv_complete@dtors@@YAXPAUA@1@@Z" +// CHECK: call x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ" +// CHECK: ret +} + +// CHECK: declare x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ" + +// Now try some virtual bases, where we need the complete dtor. + +struct B : virtual A { ~B(); }; +struct C : virtual A { ~C(); }; +struct D : B, C { ~D(); }; + +void call_vbase_complete(D *d) { + d->~D(); +// CHECK: define void @"\01?call_vbase_complete@dtors@@YAXPAUD@1@@Z" +// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}}) +// CHECK: ret +} + +// The complete dtor should call the base dtors for D and the vbase A (once). +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ" +// CHECK-NOT: call +// CHECK: call x86_thiscallcc void @"\01??1D@dtors@@QAE@XZ" +// CHECK-NOT: call +// CHECK: call x86_thiscallcc void @"\01??1A@dtors@@QAE@XZ" +// CHECK-NOT: call +// CHECK: ret + +void destroy_d_complete() { + D d; +// CHECK: define void @"\01?destroy_d_complete@dtors@@YAXXZ" +// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}}) +// CHECK: ret +} + +// FIXME: Clang manually inlines the deletion, so we don't get a call to the +// deleting dtor (_G). The only way to call deleting dtors currently is through +// a vftable. +void call_nv_deleting_dtor(D *d) { + delete d; +// CHECK: define void @"\01?call_nv_deleting_dtor@dtors@@YAXPAUD@1@@Z" +// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}}) +// CHECK: call void @"\01??3@YAXPAX@Z" +// CHECK: ret +} + +} |