]> granicus.if.org Git - clang/commitdiff
Delay emitting dllexport explicitly defaulted members until the class is fully parsed...
authorHans Wennborg <hans@hanshq.net>
Thu, 1 Aug 2019 08:01:09 +0000 (08:01 +0000)
committerHans Wennborg <hans@hanshq.net>
Thu, 1 Aug 2019 08:01:09 +0000 (08:01 +0000)
This is similar to r245139, but that only addressed dllexported classes.
It was still possible to run into the same problem with dllexported
members in an otherwise normal class (see bug). This uses the same
strategy to fix: delay defining the method until the whole class has
been parsed.

(The easiest way to see the ordering problem is in
Parser::ParseCXXMemberSpecification(): it calls
ParseLexedMemberInitializers() *after* ActOnFinishCXXMemberDecls(),
which was trying to define the dllexport method. Now we delay it to
ActOnFinishCXXNonNestedClass() which is called after both of those.)

Differential revision: https://reviews.llvm.org/D65511

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

include/clang/Sema/Sema.h
lib/Sema/Sema.cpp
lib/Sema/SemaDeclCXX.cpp
test/CodeGenCXX/dllexport.cpp

index 92244cdf088233e118b9b628422a21fd804540ce..a709ebb249f68f0870d354eaa4c2c5b40de88b12 100644 (file)
@@ -11136,6 +11136,7 @@ public:
   // Emitting members of dllexported classes is delayed until the class
   // (including field initializers) is fully parsed.
   SmallVector<CXXRecordDecl*, 4> DelayedDllExportClasses;
+  SmallVector<CXXMethodDecl*, 4> DelayedDllExportMemberFunctions;
 
 private:
   class SavePendingParsedClassStateRAII {
index 3941643893af61151fea68299e295eb864d680ea..30b8d49b5bf1764eb8b7b54895fd3fb1f8cc3dc1 100644 (file)
@@ -961,6 +961,7 @@ void Sema::ActOnEndOfTranslationUnit() {
 
   // All dllexport classes should have been processed already.
   assert(DelayedDllExportClasses.empty());
+  assert(DelayedDllExportMemberFunctions.empty());
 
   // Remove file scoped decls that turned out to be used.
   UnusedFileScopedDecls.erase(
index 6fa7d2afa2c36b23c0d8c86f2aab131a872ec924..5f90790d7ffbb82b7de211d40ba120fbfe1d3922 100644 (file)
@@ -6283,8 +6283,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
         M->dropAttr<DLLExportAttr>();
 
       if (M->hasAttr<DLLExportAttr>()) {
-        DefineImplicitSpecialMember(*this, M, M->getLocation());
-        ActOnFinishInlineFunctionDef(M);
+        // Define after any fields with in-class initializers have been parsed.
+        DelayedDllExportMemberFunctions.push_back(M);
       }
     }
   };
@@ -11537,6 +11537,15 @@ void Sema::ActOnFinishCXXMemberDecls() {
 
 void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
   referenceDLLExportedClassMethods();
+
+  if (!DelayedDllExportMemberFunctions.empty()) {
+    SmallVector<CXXMethodDecl*, 4> WorkList;
+    std::swap(DelayedDllExportMemberFunctions, WorkList);
+    for (CXXMethodDecl *M : WorkList) {
+      DefineImplicitSpecialMember(*this, M, M->getLocation());
+      ActOnFinishInlineFunctionDef(M);
+    }
+  }
 }
 
 void Sema::referenceDLLExportedClassMethods() {
index 16cfb8465845069b6d835d8e816735683d2f7507..5d4523f2ea61c74719badf5568bbb2c4f1756e90 100644 (file)
@@ -851,6 +851,15 @@ struct __declspec(dllexport) Baz {
 // Baz's operator=, causing instantiation of Foo<int> after which
 // ActOnFinishCXXNonNestedClass is called, and we would bite our own tail.
 // M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc dereferenceable(1) %"struct.InClassInits::Baz"* @"??4Baz@InClassInits@@QAEAAU01@ABU01@@Z"
+
+// Trying to define the explicitly defaulted ctor must be delayed until the
+// in-class initializer for x has been processed.
+struct PR40006 {
+  __declspec(dllexport) PR40006() = default;
+  int x = 42;
+};
+// M32-DAG: define weak_odr dso_local dllexport x86_thiscallcc %"struct.InClassInits::PR40006"* @"??0PR40006@InClassInits@@QAE@XZ"
+
 }
 
 // We had an issue where instantiating A would force emission of B's delayed