diff options
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 1 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 13 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/dllexport.cpp | 9 |
4 files changed, 22 insertions, 2 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 92244cdf088..a709ebb249f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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 { diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 3941643893a..30b8d49b5bf 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -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( diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 6fa7d2afa2c..5f90790d7ff 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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() { diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp index 16cfb846584..5d4523f2ea6 100644 --- a/clang/test/CodeGenCXX/dllexport.cpp +++ b/clang/test/CodeGenCXX/dllexport.cpp @@ -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 |