From e5fdb78baffc29df6c772dbe80c113bc22bd72c6 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Wed, 25 Jun 2014 18:25:57 +0000 Subject: MS ABI: Propagate class-level DLL attributes to class template specialization bases (PR11170) Consider the following code: template class Base {}; class __declspec(dllexport) class Derived : public Base {} When the base of an exported or imported class is a class template specialization, MSVC will propagate the dll attribute to the base. In the example code, Base becomes a dllexported class. This commit makes Clang do the proopagation when the base hasn't been instantiated yet, and warns about it being unsupported otherwise. This is different from MSVC, which allows changing a specialization back and forth between dllimport and dllexport and seems to let the last one win. Changing the dll attribute after instantiation would be hard for us, and doesn't seem to come up in practice, so I think this is a reasonable limitation to have. MinGW doesn't do this kind of propagation. Differential Revision: http://reviews.llvm.org/D4264 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211725 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 9 +++ lib/Sema/SemaDeclCXX.cpp | 67 ++++++++++++++++++-- test/CodeGenCXX/dllexport.cpp | 98 +++++++++++++++++++++++++++++ test/CodeGenCXX/dllimport.cpp | 99 ++++++++++++++++++++++++++++++ test/SemaCXX/dllexport.cpp | 82 ++++++++++++++++++++++++- test/SemaCXX/dllimport.cpp | 83 +++++++++++++++++++++++++ 6 files changed, 433 insertions(+), 5 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b240295e9c..c691921fa1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2130,6 +2130,11 @@ def warn_attribute_dllimport_static_field_definition : Warning< InGroup>; def err_attribute_dll_member_of_dll_class : Error< "attribute %q0 cannot be applied to member of %q1 class">; +def warn_attribute_dll_instantiated_base_class : Warning< + "propagating dll attribute to %select{already instantiated|explicitly specialized}0 " + "base class template " + "%select{without dll attribute|with different dll attribute}1 is unsupported">, + InGroup>; def err_attribute_weakref_not_static : Error< "weakref declaration must have internal linkage">; def err_attribute_weakref_not_global_context : Error< @@ -3405,6 +3410,10 @@ def err_template_instantiate_undefined : Error< "%select{implicit|explicit}0 instantiation of undefined template %1">; def err_implicit_instantiate_member_undefined : Error< "implicit instantiation of undefined member %0">; +def note_template_class_instantiation_was_here : Note< + "class template %0 was instantiated here">; +def note_template_class_explicit_specialization_was_here : Note< + "class template %0 was explicitly specialized here">; def note_template_class_instantiation_here : Note< "in instantiation of template class %0 requested here">; def note_template_member_class_here : Note< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 5ca53b0a08..35fd22c060 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1296,6 +1296,57 @@ 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; + } + + if (BaseTemplateSpec->getSpecializationKind() == TSK_Undeclared) { + // If the base class is not already specialized, we can do the propagation. + auto *NewAttr = cast(ClassAttr->clone(S.getASTContext())); + NewAttr->setInherited(true); + BaseTemplateSpec->addAttr(NewAttr); + return; + } + + bool DifferentAttribute = false; + if (Attr *SpecializationAttr = getDLLAttr(BaseTemplateSpec)) { + if (!SpecializationAttr->isInherited()) { + // The template has previously been specialized or instantiated with an + // explicit attribute. We should not try to change it. + return; + } + if (SpecializationAttr->getKind() == ClassAttr->getKind()) { + // The specialization already has the right attribute. + return; + } + DifferentAttribute = true; + } + + // The template was previously instantiated or explicitly specialized without + // a dll attribute, or the template was previously instantiated with a + // different inherited attribute. It's too late for us to change the + // attribute, so warn that this is unsupported. + S.Diag(BaseLoc, diag::warn_attribute_dll_instantiated_base_class) + << BaseTemplateSpec->isExplicitSpecialization() << DifferentAttribute; + 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 @@ -1362,6 +1413,17 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, return nullptr; } + // For the MS ABI, propagate DLL attributes to base class templates. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + if (Attr *ClassAttr = getDLLAttr(Class)) { + if (auto *BaseTemplate = dyn_cast_or_null( + BaseType->getAsCXXRecordDecl())) { + propagateDLLAttrToBaseClassTemplate(*this, Class, ClassAttr, + BaseTemplate, BaseLoc); + } + } + } + // C++ [class.derived]p2: // The class-name in a base-specifier shall not be an incompletely // defined class. @@ -4361,9 +4423,6 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { // FIXME: MSVC's docs say all bases must be exportable, but this doesn't // seem to be true in practice? - // FIXME: We also need to propagate the attribute upwards to class template - // specialization bases. - for (Decl *Member : Class->decls()) { VarDecl *VD = dyn_cast(Member); CXXMethodDecl *MD = dyn_cast(Member); @@ -4385,7 +4444,7 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { if (InheritableAttr *MemberAttr = getDLLAttr(Member)) { if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() && - !MemberAttr->isInherited()) { + !MemberAttr->isInherited() && !ClassAttr->isInherited()) { S.Diag(MemberAttr->getLocation(), diag::err_attribute_dll_member_of_dll_class) << MemberAttr << ClassAttr; diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp index 114e5a7809..0090d95afb 100644 --- a/test/CodeGenCXX/dllexport.cpp +++ b/test/CodeGenCXX/dllexport.cpp @@ -582,3 +582,101 @@ template <> struct __declspec(dllexport) ExplicitlySpecializedClassTemplate, f); // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ExplicitlySpecializedClassTemplate@PAX@@QAEXXZ" // G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN34ExplicitlySpecializedClassTemplateIPvE1fEv + +//===----------------------------------------------------------------------===// +// Classes with template base classes +//===----------------------------------------------------------------------===// + +template struct ClassTemplate { void func() {} }; +template struct __declspec(dllexport) ExportedClassTemplate { void func() {} }; +template struct __declspec(dllimport) ImportedClassTemplate { void func() {} }; + +template struct ExplicitlySpecializedTemplate { void func() {} }; +template <> struct ExplicitlySpecializedTemplate { void func() {} }; +template struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate { void func() {} }; +template struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate { void func() {} }; + +template struct ExplicitlyInstantiatedTemplate { void func() {} }; +template struct ExplicitlyInstantiatedTemplate; +template struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate; +template struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate; + + +// MS: ClassTemplate gets exported. +struct __declspec(dllexport) DerivedFromTemplate : public ClassTemplate {}; +USEMEMFUNC(ClassTemplate, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ClassTemplate@H@@QAEXXZ" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIiE4funcEv + +// ExportedTemplate is explicitly exported. +struct __declspec(dllexport) DerivedFromExportedTemplate : public ExportedClassTemplate {}; +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExportedClassTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN21ExportedClassTemplateIiE4funcEv + +// ImportedClassTemplate is explicitly imported. +struct __declspec(dllexport) DerivedFromImportedTemplate : public ImportedClassTemplate {}; +USEMEMFUNC(ImportedClassTemplate, 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. +struct DerivedFromTemplateD : public ClassTemplate {}; +struct __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate {}; +USEMEMFUNC(ClassTemplate, func) +// M32-DAG: define linkonce_odr 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. +struct __declspec(dllimport) DerivedFromTemplateB : public ClassTemplate {}; +struct __declspec(dllexport) DerivedFromTemplateB2 : public ClassTemplate {}; +USEMEMFUNC(ClassTemplate, func) +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ClassTemplate@_N@@QAEXXZ" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIbE4funcEv + +// Base class already specialized without dll attribute. +struct __declspec(dllexport) DerivedFromExplicitlySpecializedTemplate : public ExplicitlySpecializedTemplate {}; +USEMEMFUNC(ExplicitlySpecializedTemplate, func) +// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?func@?$ExplicitlySpecializedTemplate@H@@QAEXXZ" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN29ExplicitlySpecializedTemplateIiE4funcEv + +// Base class alredy specialized with export attribute. +struct __declspec(dllexport) DerivedFromExplicitlyExportSpecializedTemplate : public ExplicitlyExportSpecializedTemplate {}; +USEMEMFUNC(ExplicitlyExportSpecializedTemplate, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitlyExportSpecializedTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN35ExplicitlyExportSpecializedTemplateIiE4funcEv + +// Base class already specialized with import attribute. +struct __declspec(dllexport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate {}; +USEMEMFUNC(ExplicitlyImportSpecializedTemplate, func) +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ" +// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv + +// Base class already instantiated without dll attribute. +struct __declspec(dllexport) DerivedFromExplicitlyInstantiatedTemplate : public ExplicitlyInstantiatedTemplate {}; +USEMEMFUNC(ExplicitlyInstantiatedTemplate, func) +// M32-DAG: define weak_odr x86_thiscallcc void @"\01?func@?$ExplicitlyInstantiatedTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN30ExplicitlyInstantiatedTemplateIiE4funcEv + +// Base class already instantiated with export attribute. +struct __declspec(dllexport) DerivedFromExplicitlyExportInstantiatedTemplate : public ExplicitlyExportInstantiatedTemplate {}; +USEMEMFUNC(ExplicitlyExportInstantiatedTemplate, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitlyExportInstantiatedTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN36ExplicitlyExportInstantiatedTemplateIiE4funcEv + +// Base class already instantiated with import attribute. +struct __declspec(dllexport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate {}; +USEMEMFUNC(ExplicitlyImportInstantiatedTemplate, func) +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ" +// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv + +// MS: A dll attribute propagates through multiple levels of instantiation. +template struct TopClass { void func() {} }; +template struct MiddleClass : public TopClass { }; +struct __declspec(dllexport) BottomClas : public MiddleClass { }; +USEMEMFUNC(TopClass, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$TopClass@H@@QAEXXZ" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN8TopClassIiE4funcEv diff --git a/test/CodeGenCXX/dllimport.cpp b/test/CodeGenCXX/dllimport.cpp index 3f3c34b8a2..63b119277e 100644 --- a/test/CodeGenCXX/dllimport.cpp +++ b/test/CodeGenCXX/dllimport.cpp @@ -662,3 +662,102 @@ template <> struct __declspec(dllimport) ExplicitlySpecializedClassTemplate, f); // M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$ExplicitlySpecializedClassTemplate@PAX@@QAEXXZ" // G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN34ExplicitlySpecializedClassTemplateIPvE1fEv + +//===----------------------------------------------------------------------===// +// Classes with template base classes +//===----------------------------------------------------------------------===// + +template struct ClassTemplate { void func() {} }; +template struct __declspec(dllexport) ExportedClassTemplate { void func() {} }; +template struct __declspec(dllimport) ImportedClassTemplate { void func() {} }; + +template struct ExplicitlySpecializedTemplate { void func() {} }; +template <> struct ExplicitlySpecializedTemplate { void func() {} }; +template struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate { void func() {} }; +template struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate { void func() {} }; + +template struct ExplicitlyInstantiatedTemplate { void func() {} }; +template struct ExplicitlyInstantiatedTemplate; +template struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate; +template struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate; + + +// MS: ClassTemplate gets imported. +struct __declspec(dllimport) DerivedFromTemplate : public ClassTemplate {}; +USEMEMFUNC(ClassTemplate, func) +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ClassTemplate@H@@QAEXXZ" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIiE4funcEv + +// ImportedTemplate is explicitly imported. +struct __declspec(dllimport) DerivedFromImportedTemplate : public ImportedClassTemplate {}; +USEMEMFUNC(ImportedClassTemplate, func) +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ImportedClassTemplate@H@@QAEXXZ" +// G32-DAG: declare dllimport x86_thiscallcc void @_ZN21ImportedClassTemplateIiE4funcEv + +// ExportedTemplate is explicitly exported. +struct __declspec(dllimport) DerivedFromExportedTemplate : public ExportedClassTemplate {}; +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. +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" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIdE4funcEv + +// MS: Base class already instantiated with dfferent attribute. +struct __declspec(dllexport) DerivedFromTemplateB : public ClassTemplate {}; +struct __declspec(dllimport) DerivedFromTemplateB2 : public ClassTemplate {}; +USEMEMFUNC(ClassTemplate, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ClassTemplate@_N@@QAEXXZ" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIbE4funcEv + +// Base class already specialized without dll attribute. +struct __declspec(dllimport) DerivedFromExplicitlySpecializedTemplate : public ExplicitlySpecializedTemplate {}; +USEMEMFUNC(ExplicitlySpecializedTemplate, func) +// M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?func@?$ExplicitlySpecializedTemplate@H@@QAEXXZ" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN29ExplicitlySpecializedTemplateIiE4funcEv + +// Base class alredy specialized with export attribute. +struct __declspec(dllimport) DerivedFromExplicitlyExportSpecializedTemplate : public ExplicitlyExportSpecializedTemplate {}; +USEMEMFUNC(ExplicitlyExportSpecializedTemplate, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitlyExportSpecializedTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN35ExplicitlyExportSpecializedTemplateIiE4funcEv + +// Base class already specialized with import attribute. +struct __declspec(dllimport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate {}; +USEMEMFUNC(ExplicitlyImportSpecializedTemplate, func) +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ" +// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv + +// Base class already instantiated without dll attribute. +struct __declspec(dllimport) DerivedFromExplicitlyInstantiatedTemplate : public ExplicitlyInstantiatedTemplate {}; +USEMEMFUNC(ExplicitlyInstantiatedTemplate, func) +// M32-DAG: define weak_odr x86_thiscallcc void @"\01?func@?$ExplicitlyInstantiatedTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN30ExplicitlyInstantiatedTemplateIiE4funcEv + +// Base class already instantiated with export attribute. +struct __declspec(dllimport) DerivedFromExplicitlyExportInstantiatedTemplate : public ExplicitlyExportInstantiatedTemplate {}; +USEMEMFUNC(ExplicitlyExportInstantiatedTemplate, func) +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?func@?$ExplicitlyExportInstantiatedTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN36ExplicitlyExportInstantiatedTemplateIiE4funcEv + +// Base class already instantiated with import attribute. +struct __declspec(dllimport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate {}; +USEMEMFUNC(ExplicitlyImportInstantiatedTemplate, func) +// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ" +// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv + +// MS: A dll attribute propagates through multiple levels of instantiation. +template struct TopClass { void func() {} }; +template struct MiddleClass : public TopClass { }; +struct __declspec(dllimport) BottomClas : 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 diff --git a/test/SemaCXX/dllexport.cpp b/test/SemaCXX/dllexport.cpp index 362e063590..9a53e27957 100644 --- a/test/SemaCXX/dllexport.cpp +++ b/test/SemaCXX/dllexport.cpp @@ -316,7 +316,7 @@ template<> __declspec(dllexport) inline void funcTmpl struct ExpliciallySpecializedClassTemplate {}; template <> struct __declspec(dllexport) ExpliciallySpecializedClassTemplate { void f() {} }; +//===----------------------------------------------------------------------===// +// Classes with template base classes +//===----------------------------------------------------------------------===// + +template class ClassTemplate {}; +template class __declspec(dllexport) ExportedClassTemplate {}; +template class __declspec(dllimport) ImportedClassTemplate {}; + +template struct ExplicitlySpecializedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlySpecializedTemplate' was explicitly specialized here}} +#endif +template <> struct ExplicitlySpecializedTemplate { void func() {} }; +template struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate { void func() {} }; +template struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate { void func() {} }; + +template struct ExplicitlyInstantiatedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlyInstantiatedTemplate' was instantiated here}} +#endif +template struct ExplicitlyInstantiatedTemplate; +template struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate; +template struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate; + +// ClassTemplate gets exported. +class __declspec(dllexport) DerivedFromTemplate : public ClassTemplate {}; + +// ClassTemplate is already exported. +class __declspec(dllexport) DerivedFromTemplate2 : public ClassTemplate {}; + +// ExportedTemplate is explicitly exported. +class __declspec(dllexport) DerivedFromExportedTemplate : public ExportedClassTemplate {}; + +// 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 unsupported}} +// expected-note@+3{{attribute is here}} +#endif +class DerivedFromTemplateD : public ClassTemplate {}; +class __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate {}; + +#ifdef MS +// expected-note@+4{{class template 'ClassTemplate' was instantiated here}} +// expected-warning@+4{{propagating dll attribute to already instantiated base class template with different dll attribute is unsupported}} +// expected-note@+3{{attribute is here}} +#endif +class __declspec(dllimport) DerivedFromTemplateB : public ClassTemplate {}; +class __declspec(dllexport) DerivedFromTemplateB2 : public ClassTemplate {}; + +#ifdef MS +// expected-warning@+3{{propagating dll attribute to explicitly specialized base class template without dll attribute is unsupported}} +// expected-note@+2{{attribute is here}} +#endif +struct __declspec(dllexport) DerivedFromExplicitlySpecializedTemplate : public ExplicitlySpecializedTemplate {}; + +// Base class alredy specialized with export attribute. +struct __declspec(dllexport) DerivedFromExplicitlyExportSpecializedTemplate : public ExplicitlyExportSpecializedTemplate {}; + +// Base class already specialized with import attribute. +struct __declspec(dllexport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate {}; + +#ifdef MS +// expected-warning@+3{{propagating dll attribute to already instantiated base class template without dll attribute is unsupported}} +// expected-note@+2{{attribute is here}} +#endif +struct __declspec(dllexport) DerivedFromExplicitlyInstantiatedTemplate : public ExplicitlyInstantiatedTemplate {}; + +// Base class already instantiated with export attribute. +struct __declspec(dllexport) DerivedFromExplicitlyExportInstantiatedTemplate : public ExplicitlyExportInstantiatedTemplate {}; + +// Base class already instantiated with import attribute. +struct __declspec(dllexport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate {}; + //===----------------------------------------------------------------------===// // Precedence diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp index 8df17d7627..855893ccaf 100644 --- a/test/SemaCXX/dllimport.cpp +++ b/test/SemaCXX/dllimport.cpp @@ -955,6 +955,8 @@ class __declspec(dllimport) ClassDecl; class __declspec(dllimport) ClassDef { }; +template class ClassTemplate {}; + #ifdef MS // expected-note@+5{{previous attribute is here}} // expected-note@+4{{previous attribute is here}} @@ -1000,3 +1002,84 @@ template struct __declspec(dllimport) PartiallySpecializedClassTemp template struct ExpliciallySpecializedClassTemplate {}; template <> struct __declspec(dllimport) ExpliciallySpecializedClassTemplate { void f() {} }; + + +//===----------------------------------------------------------------------===// +// Classes with template base classes +//===----------------------------------------------------------------------===// + +template class __declspec(dllexport) ExportedClassTemplate {}; + +template class __declspec(dllimport) ImportedClassTemplate {}; + +// ClassTemplate gets imported. +class __declspec(dllimport) DerivedFromTemplate : public ClassTemplate {}; + +// ClassTemplate is already imported. +class __declspec(dllimport) DerivedFromTemplate2 : public ClassTemplate {}; + +// ImportedClassTemplate is expliitly imported. +class __declspec(dllimport) DerivedFromImportedTemplate : public ImportedClassTemplate {}; + +// 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 unsupported}} +// expected-note@+3{{attribute is here}} +#endif +class DerivedFromTemplateD : public ClassTemplate {}; +class __declspec(dllimport) DerivedFromTemplateD2 : public ClassTemplate {}; + +#ifdef MS +// expected-note@+4{{class template 'ClassTemplate' was instantiated here}} +// expected-warning@+4{{propagating dll attribute to already instantiated base class template with different dll attribute is unsupported}} +// expected-note@+3{{attribute is here}} +#endif +class __declspec(dllexport) DerivedFromTemplateB : public ClassTemplate {}; +class __declspec(dllimport) DerivedFromTemplateB2 : public ClassTemplate {}; + +template struct ExplicitlySpecializedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlySpecializedTemplate' was explicitly specialized here}} +#endif +template <> struct ExplicitlySpecializedTemplate { void func() {} }; +template struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate { void func() {} }; +template struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate { void func() {} }; + +template struct ExplicitlyInstantiatedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlyInstantiatedTemplate' was instantiated here}} +#endif +template struct ExplicitlyInstantiatedTemplate; +template struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate; +template struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate; + +#ifdef MS +// expected-warning@+3{{propagating dll attribute to explicitly specialized base class template without dll attribute is unsupported}} +// expected-note@+2{{attribute is here}} +#endif +struct __declspec(dllimport) DerivedFromExplicitlySpecializedTemplate : public ExplicitlySpecializedTemplate {}; + +// Base class already specialized with export attribute. +struct __declspec(dllimport) DerivedFromExplicitlyExportSpecializedTemplate : public ExplicitlyExportSpecializedTemplate {}; + +// Base class already specialized with import attribute. +struct __declspec(dllimport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate {}; + +#ifdef MS +// expected-warning@+3{{propagating dll attribute to already instantiated base class template without dll attribute is unsupported}} +// expected-note@+2{{attribute is here}} +#endif +struct __declspec(dllimport) DerivedFromExplicitlyInstantiatedTemplate : public ExplicitlyInstantiatedTemplate {}; + +// Base class already instantiated with export attribute. +struct __declspec(dllimport) DerivedFromExplicitlyExportInstantiatedTemplate : public ExplicitlyExportInstantiatedTemplate {}; + +// Base class already instantiated with import attribute. +struct __declspec(dllimport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate {}; -- cgit v1.2.3