diff options
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 28 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/dllexport.cpp | 19 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/dllimport.cpp | 20 | ||||
-rw-r--r-- | clang/test/SemaCXX/dllexport.cpp | 14 | ||||
-rw-r--r-- | clang/test/SemaCXX/dllimport.cpp | 14 |
5 files changed, 75 insertions, 20 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index b67dfb8e342..8859cc1b67d 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<InheritableAttr>(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<DLLExportAttr>(); 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 916e6950052..33df9640225 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<double> {}; struct __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate<double> {}; 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<int> { }; 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 <typename T> struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase<int>; +struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase<int> {}; +template struct ExplicitInstantiationDeclTemplateBase<int>; +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitInstantiationDeclTemplateBase@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN37ExplicitInstantiationDeclTemplateBaseIiE4funcEv + +template <typename T> struct ExplicitInstantiationDeclTemplateBase2 { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase2<int>; +struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase2 : public ExplicitInstantiationDeclTemplateBase2<int> {}; +template struct __declspec(dllimport) ExplicitInstantiationDeclTemplateBase2<int>; +USEMEMFUNC(ExplicitInstantiationDeclTemplateBase2<int>, 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 0867fdd3f03..779a27816ea 100644 --- a/clang/test/CodeGenCXX/dllimport.cpp +++ b/clang/test/CodeGenCXX/dllimport.cpp @@ -785,11 +785,11 @@ USEMEMFUNC(ExportedClassTemplate<int>, 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<double> {}; struct __declspec(dllimport) DerivedFromTemplateD2 : public ClassTemplate<double> {}; USEMEMFUNC(ClassTemplate<double>, 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<int> { }; USEMEMFUNC(TopClass<int>, 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 <typename T> struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase<int>; +struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase<int> {}; +template struct ExplicitInstantiationDeclTemplateBase<int>; +USEMEMFUNC(ExplicitInstantiationDeclTemplateBase<int>, func) +// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitInstantiationDeclTemplateBase@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN37ExplicitInstantiationDeclTemplateBaseIiE4funcEv + +template <typename T> struct ExplicitInstantiationDeclTemplateBase2 { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase2<int>; +struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase2 : public ExplicitInstantiationDeclTemplateBase2<int> {}; +template struct __declspec(dllexport) ExplicitInstantiationDeclTemplateBase2<int>; +USEMEMFUNC(ExplicitInstantiationDeclTemplateBase2<int>, 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 a6009f93c8d..badb9e25959 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<int> {}; -#ifdef MS -// expected-note@+4{{class template 'ClassTemplate<double>' 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<double> {}; +// Base class previously implicitly instantiated without attribute; it will get propagated. class __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate<double> {}; +// Base class has explicit instantiation declaration; the attribute will get propagated. +extern template class ClassTemplate<float>; +class __declspec(dllexport) DerivedFromTemplateF : public ClassTemplate<float> {}; + class __declspec(dllexport) DerivedFromTemplateB : public ClassTemplate<bool> {}; // The second derived class doesn't change anything, the attribute that was propagated first wins. class __declspec(dllimport) DerivedFromTemplateB2 : public ClassTemplate<bool> {}; @@ -475,6 +475,10 @@ struct __declspec(dllexport) DerivedFromExplicitlyExportInstantiatedTemplate : p // Base class already instantiated with import attribute. struct __declspec(dllexport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate<int> {}; +template <typename T> struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase<int>; +struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase<int> {}; + //===----------------------------------------------------------------------===// // Precedence diff --git a/clang/test/SemaCXX/dllimport.cpp b/clang/test/SemaCXX/dllimport.cpp index 62d4f7b5759..0f616d43c89 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<int> {}; -#ifdef MS -// expected-note@+4{{class template 'ClassTemplate<double>' 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<double> {}; +// Base class previously implicitly instantiated without attribute; it will get propagated. class __declspec(dllimport) DerivedFromTemplateD2 : public ClassTemplate<double> {}; +// Base class has explicit instantiation declaration; the attribute will get propagated. +extern template class ClassTemplate<float>; +class __declspec(dllimport) DerivedFromTemplateF : public ClassTemplate<float> {}; + class __declspec(dllimport) DerivedFromTemplateB : public ClassTemplate<bool> {}; // The second derived class doesn't change anything, the attribute that was propagated first wins. class __declspec(dllexport) DerivedFromTemplateB2 : public ClassTemplate<bool> {}; @@ -1329,3 +1329,7 @@ struct __declspec(dllimport) DerivedFromExplicitlyExportInstantiatedTemplate : p // Base class already instantiated with import attribute. struct __declspec(dllimport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate<int> {}; + +template <typename T> struct ExplicitInstantiationDeclTemplateBase { void func() {} }; +extern template struct ExplicitInstantiationDeclTemplateBase<int>; +struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase<int> {}; |