From a1e12412adb04103283d7fac7ee18cb43f5f74f9 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Tue, 9 Jun 2015 00:39:09 +0000 Subject: [PATCH] Enable DLL attribute propagation on explicit instantiation definitions (PR23770) This is a follow-up to r225570 which enabled adding DLL attributes when a class template goes from explicit instantiation declaration to explicit instantiation definition. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@239375 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 4 ++ lib/Sema/SemaDeclCXX.cpp | 114 +++++++++++++++++----------------- lib/Sema/SemaTemplate.cpp | 7 +++ test/CodeGenCXX/dllexport.cpp | 5 ++ test/CodeGenCXX/dllimport.cpp | 6 ++ 5 files changed, 79 insertions(+), 57 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 39ea3c62a8..60664c5fdc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -5110,6 +5110,10 @@ public: bool AnyErrors); void checkClassLevelDLLAttribute(CXXRecordDecl *Class); + 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/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 8859cc1b67..c80ef2d2bd 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1345,61 +1345,6 @@ static bool findCircularInheritance(const CXXRecordDecl *Class, return false; } -/// \brief Perform propagation of DLL attributes from a derived class to a -/// templated base class for MS compatibility. -static void propagateDLLAttrToBaseClassTemplate( - Sema &S, CXXRecordDecl *Class, Attr *ClassAttr, - ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc) { - if (getDLLAttr( - BaseTemplateSpec->getSpecializedTemplate()->getTemplatedDecl())) { - // If the base class template has a DLL attribute, don't try to change it. - return; - } - - auto TSK = BaseTemplateSpec->getSpecializationKind(); - if (!getDLLAttr(BaseTemplateSpec) && - (TSK == TSK_Undeclared || TSK == TSK_ExplicitInstantiationDeclaration || - TSK == TSK_ImplicitInstantiation)) { - // The template hasn't been instantiated yet (or it has, but only as an - // explicit instantiation declaration or implicit instantiation, which means - // we haven't codegenned any members yet), so propagate the attribute. - auto *NewAttr = cast(ClassAttr->clone(S.getASTContext())); - NewAttr->setInherited(true); - BaseTemplateSpec->addAttr(NewAttr); - - // If the template is already instantiated, checkDLLAttributeRedeclaration() - // needs to be run again to work see the new attribute. Otherwise this will - // get run whenever the template is instantiated. - if (TSK != TSK_Undeclared) - S.checkClassLevelDLLAttribute(BaseTemplateSpec); - - return; - } - - if (getDLLAttr(BaseTemplateSpec)) { - // The template has already been specialized or instantiated with an - // attribute, explicitly or through propagation. We should not try to change - // it. - return; - } - - // The template was previously instantiated or explicitly specialized without - // a dll attribute, It's too late for us to add an attribute, so warn that - // this is unsupported. - S.Diag(BaseLoc, diag::warn_attribute_dll_instantiated_base_class) - << BaseTemplateSpec->isExplicitSpecialization(); - S.Diag(ClassAttr->getLocation(), diag::note_attribute); - if (BaseTemplateSpec->isExplicitSpecialization()) { - S.Diag(BaseTemplateSpec->getLocation(), - diag::note_template_class_explicit_specialization_was_here) - << BaseTemplateSpec; - } else { - S.Diag(BaseTemplateSpec->getPointOfInstantiation(), - diag::note_template_class_instantiation_was_here) - << BaseTemplateSpec; - } -} - /// \brief Check the validity of a C++ base class specifier. /// /// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics @@ -1471,8 +1416,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, if (Attr *ClassAttr = getDLLAttr(Class)) { if (auto *BaseTemplate = dyn_cast_or_null( BaseType->getAsCXXRecordDecl())) { - propagateDLLAttrToBaseClassTemplate(*this, Class, ClassAttr, - BaseTemplate, BaseLoc); + propagateDLLAttrToBaseClassTemplate(Class, ClassAttr, BaseTemplate, + BaseLoc); } } } @@ -4884,6 +4829,61 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { } } +/// \brief Perform propagation of DLL attributes from a derived class to a +/// templated base class for MS compatibility. +void Sema::propagateDLLAttrToBaseClassTemplate( + CXXRecordDecl *Class, Attr *ClassAttr, + ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc) { + if (getDLLAttr( + BaseTemplateSpec->getSpecializedTemplate()->getTemplatedDecl())) { + // If the base class template has a DLL attribute, don't try to change it. + return; + } + + auto TSK = BaseTemplateSpec->getSpecializationKind(); + if (!getDLLAttr(BaseTemplateSpec) && + (TSK == TSK_Undeclared || TSK == TSK_ExplicitInstantiationDeclaration || + TSK == TSK_ImplicitInstantiation)) { + // The template hasn't been instantiated yet (or it has, but only as an + // explicit instantiation declaration or implicit instantiation, which means + // we haven't codegenned any members yet), so propagate the attribute. + auto *NewAttr = cast(ClassAttr->clone(getASTContext())); + NewAttr->setInherited(true); + BaseTemplateSpec->addAttr(NewAttr); + + // If the template is already instantiated, checkDLLAttributeRedeclaration() + // needs to be run again to work see the new attribute. Otherwise this will + // get run whenever the template is instantiated. + if (TSK != TSK_Undeclared) + checkClassLevelDLLAttribute(BaseTemplateSpec); + + return; + } + + if (getDLLAttr(BaseTemplateSpec)) { + // The template has already been specialized or instantiated with an + // attribute, explicitly or through propagation. We should not try to change + // it. + return; + } + + // The template was previously instantiated or explicitly specialized without + // a dll attribute, It's too late for us to add an attribute, so warn that + // this is unsupported. + Diag(BaseLoc, diag::warn_attribute_dll_instantiated_base_class) + << BaseTemplateSpec->isExplicitSpecialization(); + Diag(ClassAttr->getLocation(), diag::note_attribute); + if (BaseTemplateSpec->isExplicitSpecialization()) { + Diag(BaseTemplateSpec->getLocation(), + diag::note_template_class_explicit_specialization_was_here) + << BaseTemplateSpec; + } else { + Diag(BaseTemplateSpec->getPointOfInstantiation(), + diag::note_template_class_instantiation_was_here) + << BaseTemplateSpec; + } +} + /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 4fb7cb8f1d..19c0f2a939 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -7379,6 +7379,13 @@ Sema::ActOnExplicitInstantiation(Scope *S, A->setInherited(true); Def->addAttr(A); checkClassLevelDLLAttribute(Def); + + // Propagate attribute to base class templates. + for (auto &B : Def->bases()) { + if (auto *BT = dyn_cast_or_null( + B.getType()->getAsCXXRecordDecl())) + propagateDLLAttrToBaseClassTemplate(Def, A, BT, B.getLocStart()); + } } } diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp index 3795cbcbee..477e7dcf0b 100644 --- a/test/CodeGenCXX/dllexport.cpp +++ b/test/CodeGenCXX/dllexport.cpp @@ -707,6 +707,11 @@ void PR23308::f(InternalLinkageType*) {} long use(PR23308* p) { p->f(nullptr); } // M32-DAG: define internal x86_thiscallcc void @"\01?f@PR23308@@QAEXPAUInternalLinkageType@?A@@@Z" +template struct PR23770BaseTemplate { void f() {} }; +template struct PR23770DerivedTemplate : PR23770BaseTemplate {}; +extern template struct PR23770DerivedTemplate; +template struct __declspec(dllexport) PR23770DerivedTemplate; +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$PR23770BaseTemplate@H@@QAEXXZ" //===----------------------------------------------------------------------===// diff --git a/test/CodeGenCXX/dllimport.cpp b/test/CodeGenCXX/dllimport.cpp index 9e3813e5e1..0f15ff0291 100644 --- a/test/CodeGenCXX/dllimport.cpp +++ b/test/CodeGenCXX/dllimport.cpp @@ -741,6 +741,12 @@ USEMEMFUNC(ExplicitInstantiationDeclExportedDefImportedTemplate, f); // M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$ExplicitInstantiationDeclExportedDefImportedTemplate@H@@QAEXXZ" // M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc %struct.ExplicitInstantiationDeclExportedDefImportedTemplate* @"\01??0?$ExplicitInstantiationDeclExportedDefImportedTemplate@H@@QAE@XZ" +template struct PR23770BaseTemplate { void f() {} }; +template struct PR23770DerivedTemplate : PR23770BaseTemplate {}; +extern template struct PR23770DerivedTemplate; +template struct __declspec(dllimport) PR23770DerivedTemplate; +USEMEMFUNC(PR23770BaseTemplate, f); +// M32-DAG: declare dllimport x86_thiscallcc void @"\01?f@?$PR23770BaseTemplate@H@@QAEXXZ" //===----------------------------------------------------------------------===// // Classes with template base classes -- 2.50.1