From 5b64034a435d2bd25813918bdb1f7368e2af77b7 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 26 Feb 2016 19:51:02 +0000 Subject: [PATCH] [dllexport] Sort out emission order of delayed exported classes 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. llvm-svn: 262056 --- clang/include/clang/Sema/Sema.h | 7 +++++++ clang/lib/Sema/SemaDeclCXX.cpp | 4 ++++ clang/lib/Sema/SemaTemplate.cpp | 6 ++++++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 10 ++++++++++ clang/test/CodeGenCXX/dllexport-pr26549.cpp | 9 +++++++++ clang/test/CodeGenCXX/dllexport.cpp | 11 +++++++++++ 6 files changed, 47 insertions(+) create mode 100644 clang/test/CodeGenCXX/dllexport-pr26549.cpp diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9d733ca..22a2ef7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5295,11 +5295,18 @@ public: ArrayRef 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, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c160f44..3890120 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 38df76e..3b85b98 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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()) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 56858bc..db3f47f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -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/clang/test/CodeGenCXX/dllexport-pr26549.cpp b/clang/test/CodeGenCXX/dllexport-pr26549.cpp new file mode 100644 index 0000000..ceb2e06 --- /dev/null +++ b/clang/test/CodeGenCXX/dllexport-pr26549.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -fms-extensions -triple x86_64-windows-msvc -emit-llvm -o - | FileCheck %s + +template struct MessageT { }; +extern template struct MessageT; + +// CHECK: define weak_odr dllexport {{.*}} %struct.MessageT* @"\01??4?$MessageT@H@@QEAAAEAU0@AEBU0@@Z"( +template struct __declspec(dllexport) MessageT; +// Previously we crashed when this dllexport was the last thing in the file. +// DO NOT ADD MORE TESTS AFTER THIS LINE! diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp index 1412ad8..04007e8 100644 --- a/clang/test/CodeGenCXX/dllexport.cpp +++ b/clang/test/CodeGenCXX/dllexport.cpp @@ -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 struct A { }; +struct __declspec(dllexport) B { + B(int = 0) {} + A m_fn1() {} +}; +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??_FB@pr26490@@QAEXXZ" +} + //===----------------------------------------------------------------------===// // Classes with template base classes -- 2.7.4