diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b67dfb8e3424..8859cc1b67d7 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1356,11 +1356,23 @@ static void propagateDLLAttrToBaseClassTemplate( return; } - if (BaseTemplateSpec->getSpecializationKind() == TSK_Undeclared) { - // If the base class is not already specialized, we can do the propagation. + 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; } @@ -4783,8 +4795,9 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); - // Don't dllexport explicit class template instantiation declarations. - if (ClassExported && TSK == TSK_ExplicitInstantiationDeclaration) { + // Ignore explicit dllexport on explicit class template instantiation declarations. + if (ClassExported && !ClassAttr->isInherited() && + TSK == TSK_ExplicitInstantiationDeclaration) { Class->dropAttr(); return; } @@ -4832,12 +4845,15 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { } if (MD && ClassExported) { + if (TSK == TSK_ExplicitInstantiationDeclaration) + // Don't go any further if this is just an explicit instantiation + // declaration. + continue; + if (MD->isUserProvided()) { // Instantiate non-default class member functions ... // .. except for certain kinds of template specializations. - if (TSK == TSK_ExplicitInstantiationDeclaration) - continue; if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) continue; diff --git a/clang/test/CodeGenCXX/dllexport.cpp b/clang/test/CodeGenCXX/dllexport.cpp index 916e69500529..33df96402252 100644 --- a/clang/test/CodeGenCXX/dllexport.cpp +++ b/clang/test/CodeGenCXX/dllexport.cpp @@ -755,11 +755,11 @@ USEMEMFUNC(DerivedFromImportedTemplate, func) // M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ImportedClassTemplate@H@@QAEXXZ" // G32-DAG: declare dllimport x86_thiscallcc void @_ZN21ImportedClassTemplateIiE4funcEv -// Base class already instantiated without dll attribute. +// Base class already implicitly instantiated without dll attribute. struct DerivedFromTemplateD : public ClassTemplate {}; struct __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate {}; USEMEMFUNC(DerivedFromTemplateD2, func) -// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?func@?$ClassTemplate@N@@QAEXXZ" +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ClassTemplate@N@@QAEXXZ" // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIdE4funcEv // MS: Base class already instantiated with different dll attribute. @@ -812,3 +812,18 @@ struct __declspec(dllexport) BottomClass : public MiddleClass { }; USEMEMFUNC(BottomClass, func) // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$TopClass@H@@QAEXXZ" // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN8TopClassIiE4funcEv + +template struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase; +struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase {}; +template struct ExplicitInstantiationDeclTemplateBase; +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitInstantiationDeclTemplateBase@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN37ExplicitInstantiationDeclTemplateBaseIiE4funcEv + +template struct ExplicitInstantiationDeclTemplateBase2 { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase2; +struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase2 : public ExplicitInstantiationDeclTemplateBase2 {}; +template struct __declspec(dllimport) ExplicitInstantiationDeclTemplateBase2; +USEMEMFUNC(ExplicitInstantiationDeclTemplateBase2, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitInstantiationDeclTemplateBase2@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN38ExplicitInstantiationDeclTemplateBase2IiE4funcEv diff --git a/clang/test/CodeGenCXX/dllimport.cpp b/clang/test/CodeGenCXX/dllimport.cpp index 0867fdd3f037..779a27816eab 100644 --- a/clang/test/CodeGenCXX/dllimport.cpp +++ b/clang/test/CodeGenCXX/dllimport.cpp @@ -785,11 +785,11 @@ USEMEMFUNC(ExportedClassTemplate, func) // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExportedClassTemplate@H@@QAEXXZ" // G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN21ExportedClassTemplateIiE4funcEv -// Base class already instantiated without attribute. +// Base class already implicitly instantiated without attribute. struct DerivedFromTemplateD : public ClassTemplate {}; struct __declspec(dllimport) DerivedFromTemplateD2 : public ClassTemplate {}; USEMEMFUNC(ClassTemplate, func) -// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?func@?$ClassTemplate@N@@QAEXXZ" +// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ClassTemplate@N@@QAEXXZ" // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIdE4funcEv // MS: Base class already instantiated with dfferent attribute. @@ -842,3 +842,19 @@ struct __declspec(dllimport) BottomClass : public MiddleClass { }; USEMEMFUNC(TopClass, func) // M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$TopClass@H@@QAEXXZ" // G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN8TopClassIiE4funcEv + +template struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase; +struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase {}; +template struct ExplicitInstantiationDeclTemplateBase; +USEMEMFUNC(ExplicitInstantiationDeclTemplateBase, func) +// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitInstantiationDeclTemplateBase@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN37ExplicitInstantiationDeclTemplateBaseIiE4funcEv + +template struct ExplicitInstantiationDeclTemplateBase2 { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase2; +struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase2 : public ExplicitInstantiationDeclTemplateBase2 {}; +template struct __declspec(dllexport) ExplicitInstantiationDeclTemplateBase2; +USEMEMFUNC(ExplicitInstantiationDeclTemplateBase2, func) +// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitInstantiationDeclTemplateBase2@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN38ExplicitInstantiationDeclTemplateBase2IiE4funcEv diff --git a/clang/test/SemaCXX/dllexport.cpp b/clang/test/SemaCXX/dllexport.cpp index a6009f93c8d6..badb9e259597 100644 --- a/clang/test/SemaCXX/dllexport.cpp +++ b/clang/test/SemaCXX/dllexport.cpp @@ -439,14 +439,14 @@ class __declspec(dllexport) DerivedFromExportedTemplate : public ExportedClassTe // ImportedTemplate is explicitly imported. class __declspec(dllexport) DerivedFromImportedTemplate : public ImportedClassTemplate {}; -#ifdef MS -// expected-note@+4{{class template 'ClassTemplate' was instantiated here}} -// expected-warning@+4{{propagating dll attribute to already instantiated base class template without dll attribute is not supported}} -// expected-note@+3{{attribute is here}} -#endif class DerivedFromTemplateD : public ClassTemplate {}; +// Base class previously implicitly instantiated without attribute; it will get propagated. class __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate {}; +// Base class has explicit instantiation declaration; the attribute will get propagated. +extern template class ClassTemplate; +class __declspec(dllexport) DerivedFromTemplateF : public ClassTemplate {}; + class __declspec(dllexport) DerivedFromTemplateB : public ClassTemplate {}; // The second derived class doesn't change anything, the attribute that was propagated first wins. class __declspec(dllimport) DerivedFromTemplateB2 : public ClassTemplate {}; @@ -475,6 +475,10 @@ struct __declspec(dllexport) DerivedFromExplicitlyExportInstantiatedTemplate : p // Base class already instantiated with import attribute. struct __declspec(dllexport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate {}; +template struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase; +struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase {}; + //===----------------------------------------------------------------------===// // Precedence diff --git a/clang/test/SemaCXX/dllimport.cpp b/clang/test/SemaCXX/dllimport.cpp index 62d4f7b57590..0f616d43c89d 100644 --- a/clang/test/SemaCXX/dllimport.cpp +++ b/clang/test/SemaCXX/dllimport.cpp @@ -1274,14 +1274,14 @@ class __declspec(dllimport) DerivedFromImportedTemplate : public ImportedClassTe // ExportedClassTemplate is explicitly exported. class __declspec(dllimport) DerivedFromExportedTemplate : public ExportedClassTemplate {}; -#ifdef MS -// expected-note@+4{{class template 'ClassTemplate' was instantiated here}} -// expected-warning@+4{{propagating dll attribute to already instantiated base class template without dll attribute is not supported}} -// expected-note@+3{{attribute is here}} -#endif class DerivedFromTemplateD : public ClassTemplate {}; +// Base class previously implicitly instantiated without attribute; it will get propagated. class __declspec(dllimport) DerivedFromTemplateD2 : public ClassTemplate {}; +// Base class has explicit instantiation declaration; the attribute will get propagated. +extern template class ClassTemplate; +class __declspec(dllimport) DerivedFromTemplateF : public ClassTemplate {}; + class __declspec(dllimport) DerivedFromTemplateB : public ClassTemplate {}; // The second derived class doesn't change anything, the attribute that was propagated first wins. class __declspec(dllexport) DerivedFromTemplateB2 : public ClassTemplate {}; @@ -1329,3 +1329,7 @@ struct __declspec(dllimport) DerivedFromExplicitlyExportInstantiatedTemplate : p // Base class already instantiated with import attribute. struct __declspec(dllimport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate {}; + +template struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase; +struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase {};