]> granicus.if.org Git - clang/commitdiff
[dllexport] Sort out emission order of delayed exported classes
authorReid Kleckner <rnk@google.com>
Fri, 26 Feb 2016 19:51:02 +0000 (19:51 +0000)
committerReid Kleckner <rnk@google.com>
Fri, 26 Feb 2016 19:51:02 +0000 (19:51 +0000)
Relands r260194 with a fix. If we have a template that transitions from
an extern template to an explicitly instantiated dllexport template, we
would add that class to the delayed exported class list without flushing
it.

For explicit instantiations, we can just flush the list of delayed
classes immediately. We don't have to worry about the bug fixed in
r260194 in this case because explicit instantiations can only occur at
file and namespace scope.

Fixes PR26490.

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

include/clang/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
test/CodeGenCXX/dllexport-pr26549.cpp [new file with mode: 0644]
test/CodeGenCXX/dllexport.cpp

index 9d733ca032bb2a4dfc5263cad584866532539452..22a2ef7454b2b0a5da3b686f712968a6f5048a02 100644 (file)
@@ -5295,11 +5295,18 @@ public:
                             ArrayRef<CXXCtorInitializer*> MemInits,
                             bool AnyErrors);
 
+  /// \brief Check class-level dllimport/dllexport attribute. The caller must
+  /// ensure that referenceDLLExportedClassMethods is called some point later
+  /// when all outer classes of Class are complete.
   void checkClassLevelDLLAttribute(CXXRecordDecl *Class);
+
+  void referenceDLLExportedClassMethods();
+
   void propagateDLLAttrToBaseClassTemplate(
       CXXRecordDecl *Class, Attr *ClassAttr,
       ClassTemplateSpecializationDecl *BaseTemplateSpec,
       SourceLocation BaseLoc);
+
   void CheckCompletedCXXClass(CXXRecordDecl *Record);
   void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
                                          Decl *TagDecl,
index c160f444ca53998414400c92165ad7ab5294a09f..38901203416691499f91a89cf8b43995cf06928b 100644 (file)
@@ -9533,6 +9533,10 @@ void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
   if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft())
     getDefaultArgExprsForConstructors(*this, RD);
 
+  referenceDLLExportedClassMethods();
+}
+
+void Sema::referenceDLLExportedClassMethods() {
   if (!DelayedDllExportClasses.empty()) {
     // Calling ReferenceDllExportedMethods might cause the current function to
     // be called again, so use a local copy of DelayedDllExportClasses.
index 38df76ee3153ae983bf739bb92e73d72ca574afd..3b85b98abdd369c21c3684babd40ba3b0f114c6d 100644 (file)
@@ -7458,7 +7458,13 @@ Sema::ActOnExplicitInstantiation(Scope *S,
             getDLLAttr(Specialization)->clone(getASTContext()));
         A->setInherited(true);
         Def->addAttr(A);
+
+        // We reject explicit instantiations in class scope, so there should
+        // never be any delayed exported classes to worry about.
+        assert(DelayedDllExportClasses.empty() &&
+               "delayed exports present at explicit instantiation");
         checkClassLevelDLLAttribute(Def);
+        referenceDLLExportedClassMethods();
 
         // Propagate attribute to base class templates.
         for (auto &B : Def->bases()) {
index 56858bcc7e6afa4a9fe8e06e22f4a8399e5e3490..db3f47fd91672cb79541a41e4311745f92e0ba6b 100644 (file)
@@ -1949,6 +1949,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
   bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod();
   LocalInstantiationScope Scope(*this, MergeWithParentScope);
 
+  // All dllexported classes created during instantiation should be fully
+  // emitted after instantiation completes. We may not be ready to emit any
+  // delayed classes already on the stack, so save them away and put them back
+  // later.
+  decltype(DelayedDllExportClasses) ExportedClasses;
+  std::swap(ExportedClasses, DelayedDllExportClasses);
+
   // Pull attributes from the pattern onto the instantiation.
   InstantiateAttrs(TemplateArgs, Pattern, Instantiation);
 
@@ -2034,6 +2041,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
   // default arg exprs for default constructors if necessary now.
   ActOnFinishCXXNonNestedClass(Instantiation);
 
+  // Put back the delayed exported classes that we moved out of the way.
+  std::swap(ExportedClasses, DelayedDllExportClasses);
+
   // Instantiate late parsed attributes, and attach them to their decls.
   // See Sema::InstantiateAttrs
   for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
diff --git a/test/CodeGenCXX/dllexport-pr26549.cpp b/test/CodeGenCXX/dllexport-pr26549.cpp
new file mode 100644 (file)
index 0000000..ceb2e06
--- /dev/null
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -fms-extensions -triple x86_64-windows-msvc -emit-llvm -o - | FileCheck %s
+
+template <typename> struct MessageT { };
+extern template struct MessageT<int>;
+
+// CHECK: define weak_odr dllexport {{.*}} %struct.MessageT* @"\01??4?$MessageT@H@@QEAAAEAU0@AEBU0@@Z"(
+template struct __declspec(dllexport) MessageT<int>;
+// Previously we crashed when this dllexport was the last thing in the file.
+// DO NOT ADD MORE TESTS AFTER THIS LINE!
index 1412ad866bd3996c8a5f4b892c0739e459e5f0a4..04007e8212ddb98ed51d3d575d86a835449ece78 100644 (file)
@@ -777,6 +777,17 @@ struct __declspec(dllexport) Baz {
 // M32-DAG: define weak_odr dllexport x86_thiscallcc dereferenceable(1) %"struct.InClassInits::Baz"* @"\01??4Baz@InClassInits@@QAEAAU01@ABU01@@Z"
 }
 
+// We had an issue where instantiating A would force emission of B's delayed
+// exported methods.
+namespace pr26490 {
+template <typename T> struct A { };
+struct __declspec(dllexport) B {
+  B(int = 0) {}
+  A<int> m_fn1() {}
+};
+// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FB@pr26490@@QAEXXZ"
+}
+
 
 //===----------------------------------------------------------------------===//
 // Classes with template base classes