diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 67 | ||||
-rw-r--r-- | test/CodeGenCXX/dllexport.cpp | 98 | ||||
-rw-r--r-- | test/CodeGenCXX/dllimport.cpp | 99 | ||||
-rw-r--r-- | test/SemaCXX/dllexport.cpp | 82 | ||||
-rw-r--r-- | 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<DiagGroup<"dllimport-static-field-def">>; 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<DiagGroup<"unsupported-dll-base-class-template">>; 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<InheritableAttr>(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<ClassTemplateSpecializationDecl>( + 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<VarDecl>(Member); CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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<void USEMEMFUNC(ExplicitlySpecializedClassTemplate<void*>, 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 <typename T> struct ClassTemplate { void func() {} }; +template <typename T> struct __declspec(dllexport) ExportedClassTemplate { void func() {} }; +template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func() {} }; + +template <typename T> struct ExplicitlySpecializedTemplate { void func() {} }; +template <> struct ExplicitlySpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} }; + +template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} }; +template struct ExplicitlyInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>; + + +// MS: ClassTemplate<int> gets exported. +struct __declspec(dllexport) DerivedFromTemplate : public ClassTemplate<int> {}; +USEMEMFUNC(ClassTemplate<int>, 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<int> {}; +// 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<int> {}; +USEMEMFUNC(ImportedClassTemplate<int>, 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<double> {}; +struct __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate<double> {}; +USEMEMFUNC(ClassTemplate<double>, 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<bool> {}; +struct __declspec(dllexport) DerivedFromTemplateB2 : public ClassTemplate<bool> {}; +USEMEMFUNC(ClassTemplate<bool>, 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<int> {}; +USEMEMFUNC(ExplicitlySpecializedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyExportSpecializedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyImportSpecializedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyInstantiatedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyExportInstantiatedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyImportInstantiatedTemplate<int>, 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 <typename T> struct TopClass { void func() {} }; +template <typename T> struct MiddleClass : public TopClass<T> { }; +struct __declspec(dllexport) BottomClas : public MiddleClass<int> { }; +USEMEMFUNC(TopClass<int>, 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<void USEMEMFUNC(ExplicitlySpecializedClassTemplate<void*>, 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 <typename T> struct ClassTemplate { void func() {} }; +template <typename T> struct __declspec(dllexport) ExportedClassTemplate { void func() {} }; +template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func() {} }; + +template <typename T> struct ExplicitlySpecializedTemplate { void func() {} }; +template <> struct ExplicitlySpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} }; + +template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} }; +template struct ExplicitlyInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>; + + +// MS: ClassTemplate<int> gets imported. +struct __declspec(dllimport) DerivedFromTemplate : public ClassTemplate<int> {}; +USEMEMFUNC(ClassTemplate<int>, 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<int> {}; +USEMEMFUNC(ImportedClassTemplate<int>, 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<int> {}; +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. +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" +// G32-DAG: define linkonce_odr x86_thiscallcc void @_ZN13ClassTemplateIdE4funcEv + +// MS: Base class already instantiated with dfferent attribute. +struct __declspec(dllexport) DerivedFromTemplateB : public ClassTemplate<bool> {}; +struct __declspec(dllimport) DerivedFromTemplateB2 : public ClassTemplate<bool> {}; +USEMEMFUNC(ClassTemplate<bool>, 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<int> {}; +USEMEMFUNC(ExplicitlySpecializedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyExportSpecializedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyImportSpecializedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyInstantiatedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyExportInstantiatedTemplate<int>, 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<int> {}; +USEMEMFUNC(ExplicitlyImportInstantiatedTemplate<int>, 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 <typename T> struct TopClass { void func() {} }; +template <typename T> struct MiddleClass : public TopClass<T> { }; +struct __declspec(dllimport) BottomClas : 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 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<ExplicitSpec_InlineDef_Exp class __declspec(dllexport) ClassDecl; -class __declspec(dllexport) ClassDef { }; +class __declspec(dllexport) ClassDef {}; #ifdef MS // expected-warning@+3{{'dllexport' attribute ignored}} @@ -328,6 +328,86 @@ template <typename T> struct ExpliciallySpecializedClassTemplate {}; template <> struct __declspec(dllexport) ExpliciallySpecializedClassTemplate<int> { void f() {} }; +//===----------------------------------------------------------------------===// +// Classes with template base classes +//===----------------------------------------------------------------------===// + +template <typename T> class ClassTemplate {}; +template <typename T> class __declspec(dllexport) ExportedClassTemplate {}; +template <typename T> class __declspec(dllimport) ImportedClassTemplate {}; + +template <typename T> struct ExplicitlySpecializedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlySpecializedTemplate<int>' was explicitly specialized here}} +#endif +template <> struct ExplicitlySpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} }; + +template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlyInstantiatedTemplate<int>' was instantiated here}} +#endif +template struct ExplicitlyInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>; + +// ClassTemplate<int> gets exported. +class __declspec(dllexport) DerivedFromTemplate : public ClassTemplate<int> {}; + +// ClassTemplate<int> is already exported. +class __declspec(dllexport) DerivedFromTemplate2 : public ClassTemplate<int> {}; + +// ExportedTemplate is explicitly exported. +class __declspec(dllexport) DerivedFromExportedTemplate : public ExportedClassTemplate<int> {}; + +// 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 unsupported}} +// expected-note@+3{{attribute is here}} +#endif +class DerivedFromTemplateD : public ClassTemplate<double> {}; +class __declspec(dllexport) DerivedFromTemplateD2 : public ClassTemplate<double> {}; + +#ifdef MS +// expected-note@+4{{class template 'ClassTemplate<bool>' 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<bool> {}; +class __declspec(dllexport) DerivedFromTemplateB2 : public ClassTemplate<bool> {}; + +#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<int> {}; + +// Base class alredy specialized with export attribute. +struct __declspec(dllexport) DerivedFromExplicitlyExportSpecializedTemplate : public ExplicitlyExportSpecializedTemplate<int> {}; + +// Base class already specialized with import attribute. +struct __declspec(dllexport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate<int> {}; + +#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<int> {}; + +// Base class already instantiated with export attribute. +struct __declspec(dllexport) DerivedFromExplicitlyExportInstantiatedTemplate : public ExplicitlyExportInstantiatedTemplate<int> {}; + +// Base class already instantiated with import attribute. +struct __declspec(dllexport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate<int> {}; + //===----------------------------------------------------------------------===// // 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 <typename T> class ClassTemplate {}; + #ifdef MS // expected-note@+5{{previous attribute is here}} // expected-note@+4{{previous attribute is here}} @@ -1000,3 +1002,84 @@ template <typename T> struct __declspec(dllimport) PartiallySpecializedClassTemp template <typename T> struct ExpliciallySpecializedClassTemplate {}; template <> struct __declspec(dllimport) ExpliciallySpecializedClassTemplate<int> { void f() {} }; + + +//===----------------------------------------------------------------------===// +// Classes with template base classes +//===----------------------------------------------------------------------===// + +template <typename T> class __declspec(dllexport) ExportedClassTemplate {}; + +template <typename T> class __declspec(dllimport) ImportedClassTemplate {}; + +// ClassTemplate<int> gets imported. +class __declspec(dllimport) DerivedFromTemplate : public ClassTemplate<int> {}; + +// ClassTemplate<int> is already imported. +class __declspec(dllimport) DerivedFromTemplate2 : public ClassTemplate<int> {}; + +// ImportedClassTemplate is expliitly imported. +class __declspec(dllimport) DerivedFromImportedTemplate : public ImportedClassTemplate<int> {}; + +// 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 unsupported}} +// expected-note@+3{{attribute is here}} +#endif +class DerivedFromTemplateD : public ClassTemplate<double> {}; +class __declspec(dllimport) DerivedFromTemplateD2 : public ClassTemplate<double> {}; + +#ifdef MS +// expected-note@+4{{class template 'ClassTemplate<bool>' 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<bool> {}; +class __declspec(dllimport) DerivedFromTemplateB2 : public ClassTemplate<bool> {}; + +template <typename T> struct ExplicitlySpecializedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlySpecializedTemplate<int>' was explicitly specialized here}} +#endif +template <> struct ExplicitlySpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} }; +template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} }; +template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} }; + +template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} }; +#ifdef MS +// expected-note@+2{{class template 'ExplicitlyInstantiatedTemplate<int>' was instantiated here}} +#endif +template struct ExplicitlyInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>; +template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} }; +template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>; + +#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<int> {}; + +// Base class already specialized with export attribute. +struct __declspec(dllimport) DerivedFromExplicitlyExportSpecializedTemplate : public ExplicitlyExportSpecializedTemplate<int> {}; + +// Base class already specialized with import attribute. +struct __declspec(dllimport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate<int> {}; + +#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<int> {}; + +// Base class already instantiated with export attribute. +struct __declspec(dllimport) DerivedFromExplicitlyExportInstantiatedTemplate : public ExplicitlyExportInstantiatedTemplate<int> {}; + +// Base class already instantiated with import attribute. +struct __declspec(dllimport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate<int> {}; |