[MS ABI] Correctly mangling vbase destructors

They are a little bit of a special case in the mangling. They are always
mangled without taking into account their virtual-ness of the
destructor. They are also mangled to return void, unlike the actual
destructor.

This fixes PR31931.

Differential Revision: https://reviews.llvm.org/D29912

llvm-svn: 295010
This commit is contained in:
David Majnemer 2017-02-14 00:54:11 +00:00
parent d96089b248
commit dc169759ca
9 changed files with 47 additions and 36 deletions

View File

@ -1890,15 +1890,19 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// <return-type> ::= <type> // <return-type> ::= <type>
// ::= @ # structors (they have no declared return type) // ::= @ # structors (they have no declared return type)
if (IsStructor) { if (IsStructor) {
if (isa<CXXDestructorDecl>(D) && isStructorDecl(D) && if (isa<CXXDestructorDecl>(D) && isStructorDecl(D)) {
StructorType == Dtor_Deleting) { // The scalar deleting destructor takes an extra int argument which is not
// The scalar deleting destructor takes an extra int argument. // reflected in the AST.
// However, the FunctionType generated has 0 arguments. if (StructorType == Dtor_Deleting) {
// FIXME: This is a temporary hack.
// Maybe should fix the FunctionType creation instead?
Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z"); Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
return; return;
} }
// The vbase destructor returns void which is not reflected in the AST.
if (StructorType == Dtor_Complete) {
Out << "XXZ";
return;
}
}
if (IsCtorClosure) { if (IsCtorClosure) {
// Default constructor closure and copy constructor closure both return // Default constructor closure and copy constructor closure both return
// void. // void.
@ -2005,13 +2009,20 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
// <global-function> ::= Y # global near // <global-function> ::= Y # global near
// ::= Z # global far // ::= Z # global far
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
bool IsVirtual = MD->isVirtual();
// When mangling vbase destructor variants, ignore whether or not the
// underlying destructor was defined to be virtual.
if (isa<CXXDestructorDecl>(MD) && isStructorDecl(MD) &&
StructorType == Dtor_Complete) {
IsVirtual = false;
}
switch (MD->getAccess()) { switch (MD->getAccess()) {
case AS_none: case AS_none:
llvm_unreachable("Unsupported access specifier"); llvm_unreachable("Unsupported access specifier");
case AS_private: case AS_private:
if (MD->isStatic()) if (MD->isStatic())
Out << 'C'; Out << 'C';
else if (MD->isVirtual()) else if (IsVirtual)
Out << 'E'; Out << 'E';
else else
Out << 'A'; Out << 'A';
@ -2019,7 +2030,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
case AS_protected: case AS_protected:
if (MD->isStatic()) if (MD->isStatic())
Out << 'K'; Out << 'K';
else if (MD->isVirtual()) else if (IsVirtual)
Out << 'M'; Out << 'M';
else else
Out << 'I'; Out << 'I';
@ -2027,7 +2038,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
case AS_public: case AS_public:
if (MD->isStatic()) if (MD->isStatic())
Out << 'S'; Out << 'S';
else if (MD->isVirtual()) else if (IsVirtual)
Out << 'U'; Out << 'U';
else else
Out << 'Q'; Out << 'Q';

View File

@ -5,10 +5,10 @@ struct __declspec(dllexport) T { virtual ~T(); };
struct __declspec(dllexport) U : S, T { virtual ~U(); }; struct __declspec(dllexport) U : S, T { virtual ~U(); };
// CHECK-LABEL: define {{.*}} @"\01??_GS@@UAEPAXI@Z" // CHECK-LABEL: define {{.*}} @"\01??_GS@@UAEPAXI@Z"
// CHECK: call x86_thiscallcc void @"\01??_DS@@UAE@XZ"(%struct.S* %this1){{.*}}!dbg !{{[0-9]+}} // CHECK: call x86_thiscallcc void @"\01??_DS@@QAEXXZ"(%struct.S* %this1){{.*}}!dbg !{{[0-9]+}}
// CHECK-LABEL: define {{.*}} @"\01??_GT@@UAEPAXI@Z" // CHECK-LABEL: define {{.*}} @"\01??_GT@@UAEPAXI@Z"
// CHECK: call x86_thiscallcc void @"\01??_DT@@UAE@XZ"(%struct.T* %this1){{.*}}!dbg !{{[0-9]+}} // CHECK: call x86_thiscallcc void @"\01??_DT@@QAEXXZ"(%struct.T* %this1){{.*}}!dbg !{{[0-9]+}}
// CHECK-LABEL: define {{.*}} @"\01??_GU@@UAEPAXI@Z" // CHECK-LABEL: define {{.*}} @"\01??_GU@@UAEPAXI@Z"
// CHECK: call x86_thiscallcc void @"\01??_DU@@UAE@XZ"(%struct.U* %this1){{.*}}!dbg !{{[0-9]+}} // CHECK: call x86_thiscallcc void @"\01??_DU@@QAEXXZ"(%struct.U* %this1){{.*}}!dbg !{{[0-9]+}}

View File

@ -55,12 +55,12 @@ void test_cleanup() {
// CHECK: to label %[[LEAVE_FUNC:.*]] unwind label %[[CLEANUP:.*]] // CHECK: to label %[[LEAVE_FUNC:.*]] unwind label %[[CLEANUP:.*]]
// CHECK: [[LEAVE_FUNC]] // CHECK: [[LEAVE_FUNC]]
// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAE@XZ"( // CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"(
// CHECK: ret void // CHECK: ret void
// CHECK: [[CLEANUP]] // CHECK: [[CLEANUP]]
// CHECK: %[[CLEANUPPAD:.*]] = cleanuppad within none [] // CHECK: %[[CLEANUPPAD:.*]] = cleanuppad within none []
// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAE@XZ"( // CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"(
// CHECK: cleanupret from %[[CLEANUPPAD]] unwind to caller // CHECK: cleanupret from %[[CLEANUPPAD]] unwind to caller

View File

@ -137,7 +137,7 @@ namespace inalloca_nonvirt {
// WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore( // WIN32: call void @llvm.stackrestore(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet // On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining. // support that in the non-inlined case, so we force inlining.
@ -150,7 +150,7 @@ namespace inalloca_nonvirt {
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) // WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]])
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
struct C : B { using B::B; }; struct C : B { using B::B; };
C c(1, 2, 3, 4); C c(1, 2, 3, 4);
@ -173,7 +173,7 @@ namespace inalloca_nonvirt {
// WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore( // WIN32: call void @llvm.stackrestore(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet // On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining. // support that in the non-inlined case, so we force inlining.
@ -186,7 +186,7 @@ namespace inalloca_nonvirt {
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]]) // WIN64: call {{.*}} @"\01??0A@inalloca_nonvirt@@QEAA@UQ@@H0$$QEAU2@@Z"(%{{.*}}, %{{.*}}* %[[ARG1]], i32 2, %{{.*}}* %[[ARG3]], %{{.*}} %[[TMP]])
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
} }
namespace inalloca_virt { namespace inalloca_virt {
@ -224,7 +224,7 @@ namespace inalloca_virt {
// destroy the parameters, but that's not actually possible. // destroy the parameters, but that's not actually possible.
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet // On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining. // support that in the non-inlined case, so we force inlining.
@ -239,7 +239,7 @@ namespace inalloca_virt {
// WIN64: br // WIN64: br
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
struct C : B { using B::B; }; struct C : B { using B::B; };
C c(1, 2, 3, 4); C c(1, 2, 3, 4);
@ -281,7 +281,7 @@ namespace inalloca_virt {
// //
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"( // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"\01??_DQ@@QAE@XZ"( // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
// On Win64, the Q arguments would be destroyed in the callee. We don't yet // On Win64, the Q arguments would be destroyed in the callee. We don't yet
// support that in the non-inlined case, so we force inlining. // support that in the non-inlined case, so we force inlining.
@ -301,7 +301,7 @@ namespace inalloca_virt {
// WIN64: br // WIN64: br
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"( // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
// WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
} }
namespace inline_nonvirt { namespace inline_nonvirt {

View File

@ -138,6 +138,6 @@ S3 *f(S2 &s) {
// CHECK: [[CALL:%.*]] = invoke i8* @__RTDynamicCast // CHECK: [[CALL:%.*]] = invoke i8* @__RTDynamicCast
// CHECK: [[BC:%.*]] = bitcast i8* [[CALL]] to %"struct.PR25606::S3"* // CHECK: [[BC:%.*]] = bitcast i8* [[CALL]] to %"struct.PR25606::S3"*
// CHECK: call x86_thiscallcc void @"\01??_DCleanup@PR25606@@QAE@XZ"( // CHECK: call x86_thiscallcc void @"\01??_DCleanup@PR25606@@QAEXXZ"(
// CHECK: ret %"struct.PR25606::S3"* [[BC]] // CHECK: ret %"struct.PR25606::S3"* [[BC]]
} }

View File

@ -207,7 +207,7 @@ F::~F() {
void foo() { void foo() {
F f; F f;
} }
// DTORS3-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DF@test2@@UAE@XZ"({{.*}} {{.*}} comdat // DTORS3-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DF@test2@@QAEXXZ"({{.*}} {{.*}} comdat
// Do an adjustment from C* to F*. // Do an adjustment from C* to F*.
// DTORS3: getelementptr i8, i8* %{{.*}}, i32 20 // DTORS3: getelementptr i8, i8* %{{.*}}, i32 20
// DTORS3: bitcast i8* %{{.*}} to %"struct.test2::F"* // DTORS3: bitcast i8* %{{.*}} to %"struct.test2::F"*
@ -361,12 +361,12 @@ struct D : B, C { ~D(); };
void call_vbase_complete(D *d) { void call_vbase_complete(D *d) {
d->~D(); d->~D();
// CHECK: define void @"\01?call_vbase_complete@dtors@@YAXPAUD@1@@Z" // 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: call x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}})
// CHECK: ret // CHECK: ret
} }
// The complete dtor should call the base dtors for D and the vbase A (once). // 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"({{.*}}) {{.*}} comdat // CHECK: define linkonce_odr x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"({{.*}}) {{.*}} comdat
// CHECK-NOT: call // CHECK-NOT: call
// CHECK: call x86_thiscallcc void @"\01??1D@dtors@@QAE@XZ" // CHECK: call x86_thiscallcc void @"\01??1D@dtors@@QAE@XZ"
// CHECK-NOT: call // CHECK-NOT: call
@ -377,7 +377,7 @@ void call_vbase_complete(D *d) {
void destroy_d_complete() { void destroy_d_complete() {
D d; D d;
// CHECK: define void @"\01?destroy_d_complete@dtors@@YAXXZ" // CHECK: define void @"\01?destroy_d_complete@dtors@@YAXXZ"
// CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAE@XZ"(%"struct.dtors::D"* %{{[^,]+}}) // CHECK: call x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}})
// CHECK: ret // CHECK: ret
} }
@ -387,7 +387,7 @@ void destroy_d_complete() {
void call_nv_deleting_dtor(D *d) { void call_nv_deleting_dtor(D *d) {
delete d; delete d;
// CHECK: define void @"\01?call_nv_deleting_dtor@dtors@@YAXPAUD@1@@Z" // 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 x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}})
// CHECK: call void @"\01??3@YAXPAX@Z" // CHECK: call void @"\01??3@YAXPAX@Z"
// CHECK: ret // CHECK: ret
} }

View File

@ -12,7 +12,7 @@
// CHECK-DAG: @"\01??_R0?AUV@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUV@@\00" }, comdat // CHECK-DAG: @"\01??_R0?AUV@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUV@@\00" }, comdat
// CHECK-DAG: @"_CT??_R0?AUV@@@81044" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUV@@@8" to i8*), i32 0, i32 4, i32 4, i32 1, i8* null }, section ".xdata", comdat // CHECK-DAG: @"_CT??_R0?AUV@@@81044" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUV@@@8" to i8*), i32 0, i32 4, i32 4, i32 1, i8* null }, section ".xdata", comdat
// CHECK-DAG: @"_CTA5?AUY@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.5 { i32 5, [5 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8", %eh.CatchableType* @"_CT??_R0?AUZ@@@81", %eh.CatchableType* @"_CT??_R0?AUW@@@8??0W@@QAE@ABU0@@Z44", %eh.CatchableType* @"_CT??_R0?AUM@@@818", %eh.CatchableType* @"_CT??_R0?AUV@@@81044"] }, section ".xdata", comdat // CHECK-DAG: @"_CTA5?AUY@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.5 { i32 5, [5 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8", %eh.CatchableType* @"_CT??_R0?AUZ@@@81", %eh.CatchableType* @"_CT??_R0?AUW@@@8??0W@@QAE@ABU0@@Z44", %eh.CatchableType* @"_CT??_R0?AUM@@@818", %eh.CatchableType* @"_CT??_R0?AUV@@@81044"] }, section ".xdata", comdat
// CHECK-DAG: @"_TI5?AUY@@" = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* bitcast (void (%struct.Y*)* @"\01??_DY@@QAE@XZ" to i8*), i8* null, i8* bitcast (%eh.CatchableTypeArray.5* @"_CTA5?AUY@@" to i8*) }, section ".xdata", comdat // CHECK-DAG: @"_TI5?AUY@@" = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* bitcast (void (%struct.Y*)* @"\01??_DY@@QAEXXZ" to i8*), i8* null, i8* bitcast (%eh.CatchableTypeArray.5* @"_CTA5?AUY@@" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CT??_R0?AUDefault@@@8??_ODefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor13* @"\01??_R0?AUDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Default*, %struct.Default*)* @"\01??_ODefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat // CHECK-DAG: @"_CT??_R0?AUDefault@@@8??_ODefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor13* @"\01??_R0?AUDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Default*, %struct.Default*)* @"\01??_ODefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CT??_R0?AUVariadic@@@8??_OVariadic@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor14* @"\01??_R0?AUVariadic@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Variadic*, %struct.Variadic*)* @"\01??_OVariadic@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat // CHECK-DAG: @"_CT??_R0?AUVariadic@@@8??_OVariadic@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor14* @"\01??_R0?AUVariadic@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Variadic*, %struct.Variadic*)* @"\01??_OVariadic@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
// CHECK-DAG: @"_CT??_R0?AUTemplateWithDefault@@@8??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor25* @"\01??_R0?AUTemplateWithDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.TemplateWithDefault*, %struct.TemplateWithDefault*)* @"\01??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat // CHECK-DAG: @"_CT??_R0?AUTemplateWithDefault@@@8??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor25* @"\01??_R0?AUTemplateWithDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.TemplateWithDefault*, %struct.TemplateWithDefault*)* @"\01??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat

View File

@ -84,7 +84,7 @@ B::~B() {
// CHECK: ret // CHECK: ret
// CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* // CHECK2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DB@@QAEXXZ"(%struct.B*
// CHECK2: %[[THIS:.*]] = load %struct.B*, %struct.B** {{.*}} // CHECK2: %[[THIS:.*]] = load %struct.B*, %struct.B** {{.*}}
// CHECK2: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* // CHECK2: %[[THIS_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8*
// CHECK2: %[[B_i8:.*]] = getelementptr i8, i8* %[[THIS_i8]], i32 8 // CHECK2: %[[B_i8:.*]] = getelementptr i8, i8* %[[THIS_i8]], i32 8
@ -102,7 +102,7 @@ B::~B() {
// CHECK2: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B* // CHECK2: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B*
// CHECK2: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4 // CHECK2: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4
// CHECK2: %[[THIS:.*]] = load %struct.B*, %struct.B** %[[THIS_ADDR]] // CHECK2: %[[THIS:.*]] = load %struct.B*, %struct.B** %[[THIS_ADDR]]
// CHECK2: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[THIS]]) // CHECK2: call x86_thiscallcc void @"\01??_DB@@QAEXXZ"(%struct.B* %[[THIS]])
// ... // ...
// CHECK2: ret // CHECK2: ret
} }
@ -208,7 +208,7 @@ void call_complete_dtor() {
B b; B b;
// CHECK: call x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"(%struct.B* %[[B:.*]], i32 1) // CHECK: call x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"(%struct.B* %[[B:.*]], i32 1)
// CHECK-NOT: getelementptr // CHECK-NOT: getelementptr
// CHECK: call x86_thiscallcc void @"\01??_DB@@UAE@XZ"(%struct.B* %[[B]]) // CHECK: call x86_thiscallcc void @"\01??_DB@@QAEXXZ"(%struct.B* %[[B]])
// CHECK: ret // CHECK: ret
} }

View File

@ -47,8 +47,8 @@ public:
// CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD2Ev // CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD2Ev
// CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD1Ev // CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD1Ev
// Windows ignores calling convention on constructor/destructors. // Windows ignores calling convention on constructor/destructors.
// CHECK-WIN64-DAG: define linkonce_odr void @"\01??_Dtest_class@@QEAA@XZ" // CHECK-WIN64-DAG: define linkonce_odr void @"\01??_Dtest_class@@QEAAXXZ"
// CHECK-WIN32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_Dtest_class@@QAE@XZ" // CHECK-WIN32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_Dtest_class@@QAEXXZ"
test_class& __regcall operator+=(const test_class&){ test_class& __regcall operator+=(const test_class&){
return *this; return *this;