Index: cfe/trunk/lib/AST/MicrosoftMangle.cpp =================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp @@ -1890,14 +1890,18 @@ // ::= // ::= @ # structors (they have no declared return type) if (IsStructor) { - if (isa(D) && isStructorDecl(D) && - StructorType == Dtor_Deleting) { - // The scalar deleting destructor takes an extra int argument. - // However, the FunctionType generated has 0 arguments. - // FIXME: This is a temporary hack. - // Maybe should fix the FunctionType creation instead? - Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z"); - return; + if (isa(D) && isStructorDecl(D)) { + // The scalar deleting destructor takes an extra int argument which is not + // reflected in the AST. + if (StructorType == Dtor_Deleting) { + Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z"); + return; + } + // The vbase destructor returns void which is not reflected in the AST. + if (StructorType == Dtor_Complete) { + Out << "XXZ"; + return; + } } if (IsCtorClosure) { // Default constructor closure and copy constructor closure both return @@ -2005,13 +2009,20 @@ // ::= Y # global near // ::= Z # global far if (const CXXMethodDecl *MD = dyn_cast(FD)) { + bool IsVirtual = MD->isVirtual(); + // When mangling vbase destructor variants, ignore whether or not the + // underlying destructor was defined to be virtual. + if (isa(MD) && isStructorDecl(MD) && + StructorType == Dtor_Complete) { + IsVirtual = false; + } switch (MD->getAccess()) { case AS_none: llvm_unreachable("Unsupported access specifier"); case AS_private: if (MD->isStatic()) Out << 'C'; - else if (MD->isVirtual()) + else if (IsVirtual) Out << 'E'; else Out << 'A'; @@ -2019,7 +2030,7 @@ case AS_protected: if (MD->isStatic()) Out << 'K'; - else if (MD->isVirtual()) + else if (IsVirtual) Out << 'M'; else Out << 'I'; @@ -2027,7 +2038,7 @@ case AS_public: if (MD->isStatic()) Out << 'S'; - else if (MD->isVirtual()) + else if (IsVirtual) Out << 'U'; else Out << 'Q'; Index: cfe/trunk/test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp +++ cfe/trunk/test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp @@ -5,10 +5,10 @@ struct __declspec(dllexport) U : S, T { virtual ~U(); }; // 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: 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: 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]+}} Index: cfe/trunk/test/CodeGenCXX/exceptions-cxx-new.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/exceptions-cxx-new.cpp +++ cfe/trunk/test/CodeGenCXX/exceptions-cxx-new.cpp @@ -55,12 +55,12 @@ // CHECK: to label %[[LEAVE_FUNC:.*]] unwind label %[[CLEANUP:.*]] // CHECK: [[LEAVE_FUNC]] -// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAE@XZ"( +// CHECK: call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"( // CHECK: ret void // CHECK: [[CLEANUP]] // 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 Index: cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp +++ cfe/trunk/test/CodeGenCXX/inheriting-constructor.cpp @@ -137,7 +137,7 @@ // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) // WIN32: call void @llvm.stackrestore( // 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 // support that in the non-inlined case, so we force inlining. @@ -150,7 +150,7 @@ // 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??0Z@@QEAA@XZ"( - // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) + // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]]) struct C : B { using B::B; }; C c(1, 2, 3, 4); @@ -173,7 +173,7 @@ // WIN32: call {{.*}} @"\01??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]]) // WIN32: call void @llvm.stackrestore( // 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 // support that in the non-inlined case, so we force inlining. @@ -186,7 +186,7 @@ // 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??0Z@@QEAA@XZ"( - // WIN64: call void @"\01??_DQ@@QEAA@XZ"({{.*}}* %[[TMP]]) + // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]]) } namespace inalloca_virt { @@ -224,7 +224,7 @@ // destroy the parameters, but that's not actually possible. // 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 // support that in the non-inlined case, so we force inlining. @@ -239,7 +239,7 @@ // WIN64: br // 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; }; C c(1, 2, 3, 4); @@ -281,7 +281,7 @@ // // 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 // support that in the non-inlined case, so we force inlining. @@ -301,7 +301,7 @@ // WIN64: br // 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 { Index: cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp @@ -138,6 +138,6 @@ // CHECK: [[CALL:%.*]] = invoke i8* @__RTDynamicCast // 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]] } Index: cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-structors.cpp @@ -207,7 +207,7 @@ void foo() { 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*. // DTORS3: getelementptr i8, i8* %{{.*}}, i32 20 // DTORS3: bitcast i8* %{{.*}} to %"struct.test2::F"* @@ -361,12 +361,12 @@ 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: call x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"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"({{.*}}) {{.*}} comdat +// CHECK: define linkonce_odr x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"({{.*}}) {{.*}} comdat // CHECK-NOT: call // CHECK: call x86_thiscallcc void @"\01??1D@dtors@@QAE@XZ" // CHECK-NOT: call @@ -377,7 +377,7 @@ 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: call x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}}) // CHECK: ret } @@ -387,7 +387,7 @@ 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 x86_thiscallcc void @"\01??_DD@dtors@@QAEXXZ"(%"struct.dtors::D"* %{{[^,]+}}) // CHECK: call void @"\01??3@YAXPAX@Z" // CHECK: ret } Index: cfe/trunk/test/CodeGenCXX/microsoft-abi-throw.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-throw.cpp +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-throw.cpp @@ -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: @"_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: @"_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?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 Index: cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp @@ -84,7 +84,7 @@ // 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_i8:.*]] = bitcast %struct.B* %[[THIS]] to i8* // CHECK2: %[[B_i8:.*]] = getelementptr i8, i8* %[[THIS_i8]], i32 8 @@ -102,7 +102,7 @@ // CHECK2: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B* // CHECK2: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR:.*]], align 4 // 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 } @@ -208,7 +208,7 @@ B b; // CHECK: call x86_thiscallcc %struct.B* @"\01??0B@@QAE@XZ"(%struct.B* %[[B:.*]], i32 1) // 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 } Index: cfe/trunk/test/CodeGenCXX/regcall.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/regcall.cpp +++ cfe/trunk/test/CodeGenCXX/regcall.cpp @@ -47,8 +47,8 @@ // CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD2Ev // CHECK-LIN-DAG: define linkonce_odr x86_regcallcc void @_ZN10test_classD1Ev // Windows ignores calling convention on constructor/destructors. - // CHECK-WIN64-DAG: define linkonce_odr void @"\01??_Dtest_class@@QEAA@XZ" - // CHECK-WIN32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_Dtest_class@@QAE@XZ" + // CHECK-WIN64-DAG: define linkonce_odr void @"\01??_Dtest_class@@QEAAXXZ" + // CHECK-WIN32-DAG: define linkonce_odr x86_thiscallcc void @"\01??_Dtest_class@@QAEXXZ" test_class& __regcall operator+=(const test_class&){ return *this;