diff options
Diffstat (limited to 'clang/test/CodeGenCXX/microsoft-abi-structors.cpp')
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-structors.cpp | 79 |
1 files changed, 65 insertions, 14 deletions
diff --git a/clang/test/CodeGenCXX/microsoft-abi-structors.cpp b/clang/test/CodeGenCXX/microsoft-abi-structors.cpp index 6d43c7daf1e..24be897b057 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-structors.cpp +++ b/clang/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 +} + +} |