]> granicus.if.org Git - clang/commitdiff
[MS] Always use base dtors in place of complete/vbase dtors when possible
authorReid Kleckner <rnk@google.com>
Fri, 16 Mar 2018 19:40:50 +0000 (19:40 +0000)
committerReid Kleckner <rnk@google.com>
Fri, 16 Mar 2018 19:40:50 +0000 (19:40 +0000)
Summary:
Previously we tried too hard to uphold the fiction that destructor
variants work like they do on Itanium throughout the ABI-neutral parts
of clang. This lead to MS C++ ABI incompatiblities and other bugs. Now,
-mconstructor-aliases will no longer control this ABI detail, and clang
-cc1's LLVM IR output will be this much closer to the clang driver's.

Based on a patch by Zahira Ammarguellat:
  https://reviews.llvm.org/D39063

I've tried to move the logic that Zahira added into MicrosoftCXXABI.cpp.
There is only one ABI-specific detail sticking out, and that is in
CodeGenModule::getAddrOfCXXStructor, where we collapse complete dtors to
base dtors in the MS ABI.

This fixes PR32990.

Reviewers: erichkeane, zahiraam, majnemer, rjmccall

Subscribers: cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@327732 91177308-0d34-0410-b5e6-96231b3b80d8

17 files changed:
lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGCXXABI.cpp
lib/CodeGen/CGCXXABI.h
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/cxx2a-destroying-delete.cpp
test/CodeGenCXX/debug-info-ms-dtor-thunks.cpp
test/CodeGenCXX/dllexport-dtor-thunks.cpp
test/CodeGenCXX/dllimport-dtor-thunks.cpp
test/CodeGenCXX/exceptions-cxx-new.cpp
test/CodeGenCXX/inheriting-constructor.cpp
test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
test/CodeGenCXX/microsoft-abi-methods.cpp
test/CodeGenCXX/regcall.cpp
test/CodeGenCoroutines/coro-eh-cleanup.cpp
test/CodeGenCoroutines/coro-promise-dtor.cpp
test/CodeGenCoroutines/coro-unhandled-exception.cpp

index 738c635d26f50c8d30dcbe6c2e363a9c6efbfe68..dfae7d5f5f7de468533d587e4ce5ba446cf5d9d2 100644 (file)
@@ -242,6 +242,11 @@ llvm::Constant *CodeGenModule::getAddrOfCXXStructor(
   if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) {
     GD = GlobalDecl(CD, toCXXCtorType(Type));
   } else {
+    // Always alias equivalent complete destructors to base destructors in the
+    // MS ABI.
+    if (getTarget().getCXXABI().isMicrosoft() &&
+        Type == StructorType::Complete && MD->getParent()->getNumVBases() == 0)
+      Type = StructorType::Base;
     GD = GlobalDecl(cast<CXXDestructorDecl>(MD), toCXXDtorType(Type));
   }
 
index a27c3e9d27e39abbc21e4ead976a993daf1dea80..0611749acf17a3dbb8ec15431509639603824eea 100644 (file)
@@ -287,6 +287,20 @@ CGCXXABI::EmitCtorCompleteObjectHandler(CodeGenFunction &CGF,
   return nullptr;
 }
 
+void CGCXXABI::setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
+                                          const CXXDestructorDecl *Dtor,
+                                          CXXDtorType DT) const {
+  // Assume the base C++ ABI has no special rules for destructor variants.
+  CGM.setDLLImportDLLExport(GV, Dtor);
+}
+
+llvm::GlobalValue::LinkageTypes CGCXXABI::getCXXDestructorLinkage(
+    GVALinkage Linkage, const CXXDestructorDecl *Dtor, CXXDtorType DT) const {
+  // Delegate back to CGM by default.
+  return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage,
+                                         /*isConstantVariable=*/false);
+}
+
 bool CGCXXABI::NeedsVTTParameter(GlobalDecl GD) {
   return false;
 }
index 65a4c3d072e3793b9ea47f7e7fa37927422ab3fe..1e4e13273a110fe8b36d791c29e0ad5ea28eb334 100644 (file)
@@ -319,6 +319,14 @@ public:
   virtual bool useThunkForDtorVariant(const CXXDestructorDecl *Dtor,
                                       CXXDtorType DT) const = 0;
 
+  virtual void setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
+                                          const CXXDestructorDecl *Dtor,
+                                          CXXDtorType DT) const;
+
+  virtual llvm::GlobalValue::LinkageTypes
+  getCXXDestructorLinkage(GVALinkage Linkage, const CXXDestructorDecl *Dtor,
+                          CXXDtorType DT) const;
+
   /// Emit destructor variants required by this ABI.
   virtual void EmitCXXDestructors(const CXXDestructorDecl *D) = 0;
 
index 3c503eb66fadcc2babcb6735869788a22df66d4b..cb1bfc143bfd1f445911caaa980597b1aff71c79 100644 (file)
@@ -786,12 +786,10 @@ void CodeGenModule::setDSOLocal(llvm::GlobalValue *GV) const {
 void CodeGenModule::setDLLImportDLLExport(llvm::GlobalValue *GV,
                                           GlobalDecl GD) const {
   const auto *D = dyn_cast<NamedDecl>(GD.getDecl());
+  // C++ destructors have a few C++ ABI specific special cases.
   if (const auto *Dtor = dyn_cast_or_null<CXXDestructorDecl>(D)) {
-    if (getCXXABI().useThunkForDtorVariant(Dtor, GD.getDtorType())) {
-      // Don't dllexport/import destructor thunks.
-      GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
-      return;
-    }
+    getCXXABI().setCXXDestructorDLLStorage(GV, Dtor, GD.getDtorType());
+    return;
   }
   setDLLImportDLLExport(GV, D);
 }
@@ -1074,14 +1072,8 @@ CodeGenModule::getFunctionLinkage(GlobalDecl GD) {
 
   GVALinkage Linkage = getContext().GetGVALinkageForFunction(D);
 
-  if (isa<CXXDestructorDecl>(D) &&
-      getCXXABI().useThunkForDtorVariant(cast<CXXDestructorDecl>(D),
-                                         GD.getDtorType())) {
-    // Destructor variants in the Microsoft C++ ABI are always internal or
-    // linkonce_odr thunks emitted on an as-needed basis.
-    return Linkage == GVA_Internal ? llvm::GlobalValue::InternalLinkage
-                                   : llvm::GlobalValue::LinkOnceODRLinkage;
-  }
+  if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(D))
+    return getCXXABI().getCXXDestructorLinkage(Linkage, Dtor, GD.getDtorType());
 
   if (isa<CXXConstructorDecl>(D) &&
       cast<CXXConstructorDecl>(D)->isInheritingConstructor() &&
index d48dfbf0909667a4ddd81c0ce733ccceab880abd..221ee76a257ae0e472ee5a7f8908c2dd005a8b3f 100644 (file)
@@ -216,6 +216,14 @@ public:
     return DT != Dtor_Base;
   }
 
+  void setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
+                                  const CXXDestructorDecl *Dtor,
+                                  CXXDtorType DT) const override;
+
+  llvm::GlobalValue::LinkageTypes
+  getCXXDestructorLinkage(GVALinkage Linkage, const CXXDestructorDecl *Dtor,
+                          CXXDtorType DT) const override;
+
   void EmitCXXDestructors(const CXXDestructorDecl *D) override;
 
   const CXXRecordDecl *
@@ -1310,6 +1318,52 @@ MicrosoftCXXABI::buildStructorSignature(const CXXMethodDecl *MD, StructorType T,
   return Added;
 }
 
+void MicrosoftCXXABI::setCXXDestructorDLLStorage(llvm::GlobalValue *GV,
+                                                 const CXXDestructorDecl *Dtor,
+                                                 CXXDtorType DT) const {
+  // Deleting destructor variants are never imported or exported. Give them the
+  // default storage class.
+  if (DT == Dtor_Deleting) {
+    GV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
+  } else {
+    const NamedDecl *ND = Dtor;
+    CGM.setDLLImportDLLExport(GV, ND);
+  }
+}
+
+llvm::GlobalValue::LinkageTypes MicrosoftCXXABI::getCXXDestructorLinkage(
+    GVALinkage Linkage, const CXXDestructorDecl *Dtor, CXXDtorType DT) const {
+  // Internal things are always internal, regardless of attributes. After this,
+  // we know the thunk is externally visible.
+  if (Linkage == GVA_Internal)
+    return llvm::GlobalValue::InternalLinkage;
+
+  switch (DT) {
+  case Dtor_Base:
+    // The base destructor most closely tracks the user-declared constructor, so
+    // we delegate back to the normal declarator case.
+    return CGM.getLLVMLinkageForDeclarator(Dtor, Linkage,
+                                           /*isConstantVariable=*/false);
+  case Dtor_Complete:
+    // The complete destructor is like an inline function, but it may be
+    // imported and therefore must be exported as well. This requires changing
+    // the linkage if a DLL attribute is present.
+    if (Dtor->hasAttr<DLLExportAttr>())
+      return llvm::GlobalValue::WeakODRLinkage;
+    if (Dtor->hasAttr<DLLImportAttr>())
+      return llvm::GlobalValue::AvailableExternallyLinkage;
+    return llvm::GlobalValue::LinkOnceODRLinkage;
+  case Dtor_Deleting:
+    // Deleting destructors are like inline functions. They have vague linkage
+    // and are emitted everywhere they are used. They are internal if the class
+    // is internal.
+    return llvm::GlobalValue::LinkOnceODRLinkage;
+  case Dtor_Comdat:
+    llvm_unreachable("MS C++ ABI does not support comdat dtors");
+  }
+  llvm_unreachable("invalid dtor type");
+}
+
 void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) {
   // The TU defining a dtor is only guaranteed to emit a base destructor.  All
   // other destructor variants are delegating thunks.
@@ -1549,6 +1603,12 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF,
                                          const CXXDestructorDecl *DD,
                                          CXXDtorType Type, bool ForVirtualBase,
                                          bool Delegating, Address This) {
+  // Use the base destructor variant in place of the complete destructor variant
+  // if the class has no virtual bases. This effectively implements some of the
+  // -mconstructor-aliases optimization, but as part of the MS C++ ABI.
+  if (Type == Dtor_Complete && DD->getParent()->getNumVBases() == 0)
+    Type = Dtor_Base;
+
   CGCallee Callee = CGCallee::forDirect(
                           CGM.getAddrOfCXXStructor(DD, getFromDtorType(Type)),
                                         DD);
@@ -3821,19 +3881,12 @@ static void emitCXXConstructor(CodeGenModule &CGM,
 
 static void emitCXXDestructor(CodeGenModule &CGM, const CXXDestructorDecl *dtor,
                               StructorType dtorType) {
-  // The complete destructor is equivalent to the base destructor for
-  // classes with no virtual bases, so try to emit it as an alias.
-  if (!dtor->getParent()->getNumVBases() &&
-      (dtorType == StructorType::Complete || dtorType == StructorType::Base)) {
-    bool ProducedAlias = !CGM.TryEmitDefinitionAsAlias(
-        GlobalDecl(dtor, Dtor_Complete), GlobalDecl(dtor, Dtor_Base));
-    if (ProducedAlias) {
-      if (dtorType == StructorType::Complete)
-        return;
-      if (dtor->isVirtual())
-        CGM.getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete));
-    }
-  }
+  // Emit the base destructor if the base and complete (vbase) destructors are
+  // equivalent. This effectively implements -mconstructor-aliases as part of
+  // the ABI.
+  if (dtorType == StructorType::Complete &&
+      dtor->getParent()->getNumVBases() == 0)
+    dtorType = StructorType::Base;
 
   // The base destructor is equivalent to the base destructor of its
   // base class if there is exactly one non-virtual base class with a
index 9c6db1bb9bbb4df7996be9f31155d1f11991bd32..9e37eee4a7e9b6cbbd6ba6956e40dd7df96144e2 100644 (file)
@@ -128,7 +128,7 @@ H::~H() { call_in_dtor(); }
 // CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 48, i64 16)
 // CHECK-MSABI: br label %[[RETURN:.*]]
 //
-// CHECK-MSABI: call void @"\01??_DH@@QEAAXXZ"(
+// CHECK-MSABI: call void @"\01??1H@@UEAA@XZ"(
 // CHECK-MSABI: br label %[[RETURN]]
 //
 // CHECK-MSABI: }
@@ -155,7 +155,7 @@ I::~I() { call_in_dtor(); }
 // CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 96, i64 32)
 // CHECK-MSABI: br label %[[RETURN:.*]]
 //
-// CHECK-MSABI: call void @"\01??_DI@@QEAAXXZ"(
+// CHECK-MSABI: call void @"\01??1I@@UEAA@XZ"(
 // CHECK-MSABI: br label %[[RETURN]]
 //
 // CHECK-MSABI: }
index f876267eb5d69a3a66b67ad4b062bf94020614f4..e05b51da137546522b94fc0350dbd3ae529b2701 100644 (file)
@@ -5,10 +5,10 @@ struct __declspec(dllexport) T { virtual ~T(); };
 struct __declspec(dllexport) U : S, T { virtual ~U(); };
 
 // CHECK-LABEL: define {{.*}} @"\01??_GS@@UAEPAXI@Z"
-// CHECK: call x86_thiscallcc void @"\01??_DS@@QAEXXZ"(%struct.S* %this1){{.*}}!dbg !{{[0-9]+}}
+// CHECK: call x86_thiscallcc void @"\01??1S@@UAE@XZ"(%struct.S* %this1){{.*}}!dbg !{{[0-9]+}}
 
 // CHECK-LABEL: define {{.*}} @"\01??_GT@@UAEPAXI@Z"
-// CHECK: call x86_thiscallcc void @"\01??_DT@@QAEXXZ"(%struct.T* %this1){{.*}}!dbg !{{[0-9]+}}
+// CHECK: call x86_thiscallcc void @"\01??1T@@UAE@XZ"(%struct.T* %this1){{.*}}!dbg !{{[0-9]+}}
 
 // CHECK-LABEL: define {{.*}} @"\01??_GU@@UAEPAXI@Z"
-// CHECK: call x86_thiscallcc void @"\01??_DU@@QAEXXZ"(%struct.U* %this1){{.*}}!dbg !{{[0-9]+}}
+// CHECK: call x86_thiscallcc void @"\01??1U@@UAE@XZ"(%struct.U* %this1){{.*}}!dbg !{{[0-9]+}}
index 45cce8bb6a26cca2d9fc133c37acd9cad59394b2..935dfa5166e04564d124e8a8df42520e1cc73eeb 100644 (file)
@@ -5,6 +5,6 @@ struct __declspec(dllexport) B { virtual ~B(); };
 struct __declspec(dllexport) C : A, B { virtual ~C(); };
 C::~C() {}
 
+// CHECK: define dso_local dllexport void @"\01??1C@@UEAA@XZ"
 // This thunk should *not* be dllexport.
 // CHECK: define linkonce_odr dso_local i8* @"\01??_EC@@W7EAAPEAXI@Z"
-// CHECK: define dso_local dllexport void @"\01??1C@@UEAA@XZ"
index a1ff34c02a3128f3f1a6131671ef58e32c0a6aed..99dd4058dd35f730b58e9ef1c72f104aeaf32611 100644 (file)
@@ -1,9 +1,5 @@
 // RUN: %clang_cc1 -mconstructor-aliases %s -triple x86_64-windows-msvc -fms-extensions -emit-llvm -o - | FileCheck %s
 
-// FIXME: We should really consider removing -mconstructor-aliases for MS C++
-// ABI. The risk of bugs introducing ABI incompatibility under
-// -mno-constructor-aliases is too high.
-
 // PR32990
 
 // Introduces the virtual destructor. We should use the base destructor
@@ -44,6 +40,6 @@ extern "C" void testit() {
 // CHECK:  call void @"\01??1ImportOverrideVDtor@@UEAA@XZ"(%struct.ImportOverrideVDtor* %{{.*}})
 // CHECK:  call void @"\01??1ImportIntroVDtor@@UEAA@XZ"(%struct.ImportIntroVDtor* %{{.*}})
 
-// CHECK-LABEL: define linkonce_odr dso_local void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ"
+// CHECK-LABEL: declare dllimport void @"\01??_DImportVBaseOverrideVDtor@@QEAAXXZ"
 // CHECK-LABEL: declare dllimport void @"\01??1ImportOverrideVDtor@@UEAA@XZ"
 // CHECK-LABEL: declare dllimport void @"\01??1ImportIntroVDtor@@UEAA@XZ"
index 3a8ce7d553bfd25268d2476d968841a03636da2c..bc65953fb3fade50a3402593ccf815d338c00955 100644 (file)
@@ -55,12 +55,12 @@ void test_cleanup() {
 // CHECK:           to label %[[LEAVE_FUNC:.*]] unwind label %[[CLEANUP:.*]]
 
 // CHECK: [[LEAVE_FUNC]]
-// CHECK:   call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"(
+// CHECK:   call x86_thiscallcc void @"\01??1Cleanup@@QAE@XZ"(
 // CHECK:   ret void
 
 // CHECK: [[CLEANUP]]
 // CHECK:   %[[CLEANUPPAD:.*]] = cleanuppad within none []
-// CHECK:   call x86_thiscallcc void @"\01??_DCleanup@@QAEXXZ"(
+// CHECK:   call x86_thiscallcc void @"\01??1Cleanup@@QAE@XZ"(
 // CHECK:   cleanupret from %[[CLEANUPPAD]] unwind to caller
 
 
index 1be59b9305d338dbcc3f1bb6e0aa0364b5711178..5a3f5ab322a74e108aebe712e025a659a8f12cc5 100644 (file)
@@ -137,7 +137,7 @@ namespace inalloca_nonvirt {
   // 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@@QAEXXZ"(
+  // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"(
 
   // 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 @@ namespace inalloca_nonvirt {
   // 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@@QEAAXXZ"({{.*}}* %[[TMP]])
+  // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]])
 
   struct C : B { using B::B; };
   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 void @llvm.stackrestore(
   // WIN32: call {{.*}} @"\01??0Z@@QAE@XZ"(
-  // WIN32: call {{.*}} @"\01??_DQ@@QAEXXZ"(
+  // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"(
 
   // 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 @@ namespace inalloca_nonvirt {
   // 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@@QEAAXXZ"({{.*}}* %[[TMP]])
+  // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]])
 }
 
 namespace inalloca_virt {
@@ -224,7 +224,7 @@ namespace inalloca_virt {
   // 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@@QAEXXZ"(
+  // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"(
 
   // 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 @@ namespace inalloca_virt {
   // WIN64: br
   // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
   // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
-  // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
+  // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]])
 
   struct C : B { using B::B; };
   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??_DQ@@QAEXXZ"(
+  // WIN32: call {{.*}} @"\01??1Q@@QAE@XZ"(
 
   // 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 @@ namespace inalloca_virt {
   // WIN64: br
   // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
   // WIN64: call {{.*}} @"\01??0Z@@QEAA@XZ"(
-  // WIN64: call void @"\01??_DQ@@QEAAXXZ"({{.*}}* %[[TMP]])
+  // WIN64: call void @"\01??1Q@@QEAA@XZ"({{.*}}* %[[TMP]])
 }
 
 namespace inline_nonvirt {
index 07356e4ca6eea6ecc3338f02c60744922d686db2..0ab6f1c77c0f1d17c5add0f2acb9e44916ddfcc6 100644 (file)
@@ -138,6 +138,6 @@ S3 *f(S2 &s) {
 // CHECK:    [[CALL:%.*]] = invoke i8* @__RTDynamicCast
 
 // CHECK:    [[BC:%.*]] = bitcast i8* [[CALL]] to %"struct.PR25606::S3"*
-// CHECK:    call x86_thiscallcc void @"\01??_DCleanup@PR25606@@QAEXXZ"(
+// CHECK:    call x86_thiscallcc void @"\01??1Cleanup@PR25606@@QAE@XZ"(
 // CHECK:    ret %"struct.PR25606::S3"* [[BC]]
 }
index 6dbbf45d4ff290e982163e88c16a3d04ad3e5a47..7348eeba6dee0e8107d166dce3c21034a3b20b6f 100644 (file)
@@ -75,15 +75,15 @@ void constructors() {
 // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ"
 // CHECK: ret
 
-// Make sure that the Base constructor definition uses the right CC:
-// CHECK: define linkonce_odr dso_local x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ"
-
 // Make sure that the Base destructor call in the Child denstructor uses
 // the right calling convention:
 // CHECK: define linkonce_odr dso_local x86_thiscallcc void @"\01??1Child@@QAE@XZ"
 // CHECK: call x86_thiscallcc void @"\01??1Base@@QAE@XZ"
 // CHECK: ret
 
+// Make sure that the Base constructor definition uses the right CC:
+// CHECK: define linkonce_odr dso_local x86_thiscallcc %class.Base* @"\01??0Base@@QAE@XZ"
+
 // Make sure that the Base destructor definition uses the right CC:
 // CHECK: define linkonce_odr dso_local x86_thiscallcc void @"\01??1Base@@QAE@XZ"
 }
index ea1f878ca62763b78edac0295700da948f4323cc..b7bda1b2b561e552f7ae05d0e5820aa83046afb1 100644 (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_classD1Ev
   // Windows ignores calling convention on constructor/destructors.
-  // CHECK-WIN64-DAG: define linkonce_odr dso_local void @"\01??_Dtest_class@@QEAAXXZ"
-  // CHECK-WIN32-DAG: define linkonce_odr dso_local x86_thiscallcc void @"\01??_Dtest_class@@QAEXXZ"
+  // CHECK-WIN64-DAG: define linkonce_odr dso_local void @"\01??1test_class@@QEAA@XZ"
+  // CHECK-WIN32-DAG: define linkonce_odr dso_local x86_thiscallcc void @"\01??1test_class@@QAE@XZ"
   
   test_class& __regcall operator+=(const test_class&){
     return *this;
index 5a3ecd1da4949ee96c0b26eb29a250b225d8264c..1f21c69e0e0d52b39e3e859e0cfa77bb45a1c822 100644 (file)
@@ -50,7 +50,7 @@ coro_t f() {
 // CHECK:       to label %[[CONT:.+]] unwind label %[[EHCLEANUP:.+]]
 // CHECK: [[EHCLEANUP]]:
 // CHECK:   %[[INNERPAD:.+]] = cleanuppad within none []
-// CHECK:   call void @"\01??_DCleanup@@QEAAXXZ"(
+// CHECK:   call void @"\01??1Cleanup@@QEAA@XZ"(
 // CHECK:   cleanupret from %{{.+}} unwind label %[[CATCHDISPATCH:.+]]
 
 // CHECK: [[CATCHDISPATCH]]:
index 5cc472054a521ff86ecdbeb8dc0954399a9dd37a..53e07eeb2a1e27d89b086a4a85f79bd7ac3406d9 100644 (file)
@@ -44,4 +44,4 @@ coro_t f() {
 // CHECK:  br i1 %[[NRVO]], label %{{.+}}, label %[[DTOR:.+]]
 
 // CHECK: [[DTOR]]:
-// CHECK:  call void @"\01??_Dcoro_t@@QEAAXXZ"(
+// CHECK:  call void @"\01??1coro_t@@QEAA@XZ"(
index e26a51861d9f29eeadab45a9e4d27c9f940ea705..e0fef07545a72e376d83eac1cd2db4e38f91f748 100644 (file)
@@ -37,7 +37,7 @@ coro_t f() {
 // CHECK:       to label %{{.+}} unwind label %[[EHCLEANUP:.+]]
 // CHECK: [[EHCLEANUP]]:
 // CHECK:   %[[INNERPAD:.+]] = cleanuppad within none []
-// CHECK:   call void @"\01??_DCleanup@@QEAAXXZ"(
+// CHECK:   call void @"\01??1Cleanup@@QEAA@XZ"(
 // CHECK:   cleanupret from %[[INNERPAD]] unwind label %[[CATCHSW:.+]]
 // CHECK: [[CATCHSW]]:
 // CHECK:   %[[CATCHSWTOK:.+]] = catchswitch within none [label %[[CATCH:.+]]] unwind label