]> granicus.if.org Git - clang/commitdiff
Re-land "[MS] Don't expect vftables to be provided for extern template instantiations"
authorReid Kleckner <rnk@google.com>
Wed, 29 Jun 2016 18:29:21 +0000 (18:29 +0000)
committerReid Kleckner <rnk@google.com>
Wed, 29 Jun 2016 18:29:21 +0000 (18:29 +0000)
Reverts r273305 and re-instates r273296.

We needed to fix a bug in Sema::MarkVTableUsed to ensure that operator
delete lookup occurs when the vtable is referenced. We already had a
special case to look up operator delete when dllimport was used, but I
think should really mark virtual destructors referenced any time the
vtable is used.

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

lib/AST/VTableBuilder.cpp
lib/CodeGen/CGVTables.cpp
lib/Sema/SemaDeclCXX.cpp
test/CodeGenCXX/microsoft-abi-extern-template.cpp [new file with mode: 0644]
test/CodeGenCXX/microsoft-abi-vbtables.cpp
test/CodeGenCXX/microsoft-abi-vftables.cpp

index e43acc4de78f06af6493cdbe7f57c0341db69cba..640fbf47aeab5e5f7842bdaad762f900bc959cd7 100644 (file)
@@ -2545,14 +2545,13 @@ public:
         MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
         WhichVFPtr(*Which),
         Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
-    // Only include the RTTI component if we know that we will provide a
-    // definition of the vftable.  We always provide the definition of
-    // dllimported classes.
+    // Provide the RTTI component if RTTIData is enabled. If the vftable would
+    // be available externally, we should not provide the RTTI componenent. It
+    // is currently impossible to get available externally vftables with either
+    // dllimport or extern template instantiations, but eventually we may add a
+    // flag to support additional devirtualization that needs this.
     if (Context.getLangOpts().RTTIData)
-      if (MostDerivedClass->hasAttr<DLLImportAttr>() ||
-          MostDerivedClass->getTemplateSpecializationKind() !=
-              TSK_ExplicitInstantiationDeclaration)
-        HasRTTIComponent = true;
+      HasRTTIComponent = true;
 
     LayoutVFTable();
 
index 83974e0d214ab3160a68b018647780aa19de0027..957055033890a321fe2c263d1f96819d66134f10 100644 (file)
@@ -794,6 +794,10 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
       return DiscardableODRLinkage;
 
     case TSK_ExplicitInstantiationDeclaration:
+      // Explicit instantiations in MSVC do not provide vtables, so we must emit
+      // our own.
+      if (getTarget().getCXXABI().isMicrosoft())
+        return DiscardableODRLinkage;
       return shouldEmitAvailableExternallyVTable(*this, RD)
                  ? llvm::GlobalVariable::AvailableExternallyLinkage
                  : llvm::GlobalVariable::ExternalLinkage;
@@ -839,9 +843,9 @@ CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
 bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
   assert(RD->isDynamicClass() && "Non-dynamic classes have no VTable.");
 
-  // We always synthesize vtables on the import side regardless of whether or
-  // not it is an explicit instantiation declaration.
-  if (CGM.getTarget().getCXXABI().isMicrosoft() && RD->hasAttr<DLLImportAttr>())
+  // We always synthesize vtables if they are needed in the MS ABI. MSVC doesn't
+  // emit them even if there is an explicit template instantiation.
+  if (CGM.getTarget().getCXXABI().isMicrosoft())
     return false;
 
   // If we have an explicit instantiation declaration (and not a
index d8bb3d0d958a2ed657423d07692c95c1876aa0e3..948ad5fa9c481a082fbdf5a7a1b70fea0453b5f2 100644 (file)
@@ -13425,20 +13425,18 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
     // checks (i.e. operator delete() lookup) when the vtable is marked used, as
     // the deleting destructor is emitted with the vtable, not with the
     // destructor definition as in the Itanium ABI.
-    // If it has a definition, we do the check at that point instead.
     if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
-      if (Class->hasUserDeclaredDestructor() &&
-          !Class->getDestructor()->isDefined() &&
-          !Class->getDestructor()->isDeleted()) {
-        CXXDestructorDecl *DD = Class->getDestructor();
-        ContextRAII SavedContext(*this, DD);
-        CheckDestructor(DD);
-      } else if (Class->hasAttr<DLLImportAttr>()) {
-        // We always synthesize vtables on the import side. To make sure
-        // CheckDestructor gets called, mark the destructor referenced.
-        assert(Class->getDestructor() &&
-               "The destructor has always been declared on a dllimport class");
-        MarkFunctionReferenced(Loc, Class->getDestructor());
+      CXXDestructorDecl *DD = Class->getDestructor();
+      if (DD && DD->isVirtual() && !DD->isDeleted()) {
+        if (Class->hasUserDeclaredDestructor() && !DD->isDefined()) {
+          // If this is an out-of-line declaration, marking it referenced will
+          // not do anything. Manually call CheckDestructor to look up operator
+          // delete().
+          ContextRAII SavedContext(*this, DD);
+          CheckDestructor(DD);
+        } else {
+          MarkFunctionReferenced(Loc, Class->getDestructor());
+        }
       }
     }
   }
diff --git a/test/CodeGenCXX/microsoft-abi-extern-template.cpp b/test/CodeGenCXX/microsoft-abi-extern-template.cpp
new file mode 100644 (file)
index 0000000..de46d5b
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fno-rtti-data -O1 -disable-llvm-optzns %s -emit-llvm -o - -triple x86_64-windows-msvc | FileCheck %s
+
+// Even though Foo<int> has an extern template declaration, we have to emit our
+// own copy the vftable when emitting the available externally constructor.
+
+// CHECK: @"\01??_7?$Foo@H@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [
+// CHECK-SAME:   i8* bitcast (i8* (%struct.Foo*, i32)* @"\01??_G?$Foo@H@@UEAAPEAXI@Z" to i8*)
+// CHECK-SAME: ], comdat
+
+// CHECK-LABEL: define %struct.Foo* @"\01?f@@YAPEAU?$Foo@H@@XZ"()
+// CHECK: call %struct.Foo* @"\01??0?$Foo@H@@QEAA@XZ"(%struct.Foo* %{{.*}})
+
+// CHECK: define available_externally %struct.Foo* @"\01??0?$Foo@H@@QEAA@XZ"(%struct.Foo* returned %this)
+// CHECK:   store {{.*}} @"\01??_7?$Foo@H@@6B@"
+
+// CHECK: define linkonce_odr i8* @"\01??_G?$Foo@H@@UEAAPEAXI@Z"(%struct.Foo* %this, i32 %should_call_delete)
+
+struct Base {
+  virtual ~Base();
+};
+template <typename T> struct Foo : Base {
+  Foo() {}
+};
+extern template class Foo<int>;
+Foo<int> *f() { return new Foo<int>(); }
index 9cce6f8698c8f35b0713069d0bf03e4b85c78509..df0689423872c29401bba93ee111ea154dc5f83a 100644 (file)
@@ -537,5 +537,5 @@ template <class> struct B : virtual A {
 
 extern template class B<int>;
 template B<int>::B();
-// CHECK-DAG: @"\01??_8?$B@H@Test30@@7B@" = external unnamed_addr constant [2 x i32]{{$}}
+// CHECK-DAG: @"\01??_8?$B@H@Test30@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 4], comdat
 }
index d94c9c1a90931473c682877974a7cfcc2c63a55f..0c9b58bbb4d40efa2b938bdc93225fe8542c12a9 100644 (file)
@@ -33,7 +33,7 @@ struct __declspec(dllexport) V {
 
 namespace {
 struct W {
-  virtual ~W();
+  virtual ~W() {}
 } w;
 }
 // RTTI-DAG: [[VTABLE_W:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast ({{.*}} @"\01??_R4W@?A@@6B@" to i8*), i8* bitcast ({{.*}} @"\01??_GW@?A@@UAEPAXI@Z" to i8*)]
@@ -49,5 +49,7 @@ template <class> struct Y : virtual X {
 
 extern template class Y<int>;
 template Y<int>::Y();
-// RTTI-DAG: @"\01??_7?$Y@H@@6B@" = external unnamed_addr constant [1 x i8*]
-// NO-RTTI-DAG: @"\01??_7?$Y@H@@6B@" = external unnamed_addr constant [1 x i8*]
+// RTTI-DAG: [[VTABLE_Y:@.*]] = private unnamed_addr constant [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4?$Y@H@@6B@" to i8*), i8* bitcast (i8* (%struct.Y*, i32)* @"\01??_G?$Y@H@@UAEPAXI@Z" to i8*)], comdat($"\01??_7?$Y@H@@6B@")
+// RTTI-DAG: @"\01??_7?$Y@H@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ([2 x i8*], [2 x i8*]* [[VTABLE_Y]], i32 0, i32 1)
+
+// NO-RTTI-DAG: @"\01??_7?$Y@H@@6B@" = linkonce_odr unnamed_addr constant [1 x i8*] [i8* bitcast (i8* (%struct.Y*, i32)* @"\01??_G?$Y@H@@UAEPAXI@Z" to i8*)], comdat