Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -34,6 +34,7 @@ def BitFieldConstantConversion : DiagGroup<"bitfield-constant-conversion">; def ConstantConversion : DiagGroup<"constant-conversion", [ BitFieldConstantConversion ] >; +def DLLBaseClassTemplate : DiagGroup<"unsupported-dll-base-class-template">; def LiteralConversion : DiagGroup<"literal-conversion">; def StringConversion : DiagGroup<"string-conversion">; def SignConversion : DiagGroup<"sign-conversion">; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2130,6 +2130,13 @@ 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 already instantiated base class template " + "%select{without dll attribute|with different dll attribute}0 is unsupported">, + InGroup; +def warn_attribute_dll_templated_base_class_mismatch : Warning< + "propagating dll attribute to templated base class with different dll attribute 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,8 +3412,12 @@ "%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_instantiation_here : Note< "in instantiation of template class %0 requested here">; +def note_template_class_declaration_attr_here : Note< + "class template %0 was declared '%1' here">; def note_template_member_class_here : Note< "in instantiation of member class %0 requested here">; def note_template_member_function_here : Note< Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -1296,6 +1296,46 @@ return false; } +static void propagateDLLAttrToBaseClassTemplate( + Sema &S, CXXRecordDecl *Class, Attr *ClassAttr, + ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc) { + if (Attr *BaseTemplateAttr = getDLLAttr( + BaseTemplateSpec->getSpecializedTemplate()->getTemplatedDecl())) { + if (BaseTemplateAttr->getKind() == ClassAttr->getKind()) + return; + + S.Diag(BaseLoc, diag::warn_attribute_dll_templated_base_class_mismatch); + S.Diag(ClassAttr->getLocation(), diag::note_attribute); + S.Diag(BaseTemplateAttr->getLocation(), + diag::note_template_class_declaration_attr_here) + << BaseTemplateSpec->getSpecializedTemplate()->getTemplatedDecl() + << BaseTemplateAttr->getSpelling(); + return; + } + + if (BaseTemplateSpec->getSpecializationKind() != TSK_Undeclared) { + bool DifferentAttribute = false; + if (Attr *SpecializationAttr = getDLLAttr(BaseTemplateSpec)) { + if (SpecializationAttr->getKind() == ClassAttr->getKind()) { + return; + } + DifferentAttribute = true; + } + + S.Diag(BaseLoc, diag::warn_attribute_dll_instantiated_base_class) + << DifferentAttribute; + S.Diag(ClassAttr->getLocation(), diag::note_attribute); + S.Diag(BaseTemplateSpec->getPointOfInstantiation(), + diag::note_template_class_instantiation_was_here) + << BaseTemplateSpec; + + return; + } + auto *NewAttr = cast(ClassAttr->clone(S.getASTContext())); + NewAttr->setInherited(true); + BaseTemplateSpec->addAttr(NewAttr); +} + /// \brief Check the validity of a C++ base class specifier. /// /// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics @@ -1362,6 +1402,17 @@ 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 +4412,6 @@ // 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 +4433,7 @@ 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; Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -20,6 +20,7 @@ #define UNIQ(name) JOIN(name, __LINE__) #define USEVAR(var) int UNIQ(use)() { return var; } #define USE(func) void UNIQ(use)() { func(); } +#define USEMEMFUNC(class, func) void (class::*UNIQ(use)())() { return &class::func; } #define INSTVAR(var) template int var; #define INST(func) template void func(); @@ -568,3 +569,46 @@ // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?foo@S@ReferencedInlineMethodInNestedClass@@QAEXXZ" // M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?bar@T@S@ReferencedInlineMethodInNestedClass@@QAEXXZ" } + +template struct ClassTemplate { void func() {} }; +template struct __declspec(dllexport) ExportedClassTemplate { void func() {} }; +template struct __declspec(dllimport) ImportedClassTemplate { void func() {} }; + +// 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 already 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 + +// Base class template has different attribute. +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 + +// 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 Index: test/CodeGenCXX/dllimport.cpp =================================================================== --- test/CodeGenCXX/dllimport.cpp +++ test/CodeGenCXX/dllimport.cpp @@ -649,3 +649,47 @@ // MSC-DAG: @"\01?x@?$D@$0CK@@PR19933@@2HA" = available_externally dllimport global i32 43 // MSC-DAG: @"\01?y@?$D@$0CK@@PR19933@@2HA" = available_externally dllimport global i32 0 } + +template struct ClassTemplate { void func() {} }; +template struct __declspec(dllexport) ExportedClassTemplate { void func() {} }; +template struct __declspec(dllimport) ImportedClassTemplate { void func() {} }; + +// 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 already 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 + +// Base class template has different attribute. +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 + +// 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 Index: test/SemaCXX/dllexport.cpp =================================================================== --- test/SemaCXX/dllexport.cpp +++ test/SemaCXX/dllexport.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c++11 %s -// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c++1y %s +// RUN: %clang_cc1 -triple i686-win32 -fsyntax-only -verify -std=c++11 -DMS %s +// RUN: %clang_cc1 -triple x86_64-win32 -fsyntax-only -verify -std=c++1y -DMS %s // RUN: %clang_cc1 -triple i686-mingw32 -fsyntax-only -verify -std=c++1y %s // RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -verify -std=c++11 %s @@ -316,7 +316,48 @@ class __declspec(dllexport) ClassDecl; -class __declspec(dllexport) ClassDef { }; +class __declspec(dllexport) ClassDef {}; + +template class ClassTemplate {}; + +template class __declspec(dllexport) ExportedClassTemplate {}; + +#ifdef MS +// expected-note@+2{{class template 'ImportedClassTemplate' was declared 'dllimport' here}} +#endif +template class __declspec(dllimport) ImportedClassTemplate {}; + +// ClassTemplate gets exported. +class __declspec(dllexport) DerivedFromTemplate : public ClassTemplate {}; + +// ClassTemplate is already exported. +class __declspec(dllexport) DerivedFromTemplate2 : public ClassTemplate {}; + +// ExportedTemplate is already exported. +class __declspec(dllexport) DerivedFromExportedTemplate : public ExportedClassTemplate {}; + +#ifdef MS +// expected-warning@+3{{propagating dll attribute to templated base class with different dll attribute is unsupported}} +// expected-note@+2{{attribute is here}} +#endif +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 {}; + //===----------------------------------------------------------------------===// // Precedence Index: test/SemaCXX/dllimport.cpp =================================================================== --- test/SemaCXX/dllimport.cpp +++ test/SemaCXX/dllimport.cpp @@ -955,6 +955,46 @@ class __declspec(dllimport) ClassDef { }; +template class ClassTemplate {}; + +#ifdef MS +// expected-note@+2{{class template 'ExportedClassTemplate' was declared 'dllexport' here}} +#endif +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 {}; + +// ImportedTemplate is already imported. +class __declspec(dllimport) DerivedFromImportedTemplate : public ImportedClassTemplate {}; + +#ifdef MS +// expected-warning@+3{{propagating dll attribute to templated base class with different dll attribute is unsupported}} +// expected-note@+2{{attribute is here}} +#endif +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 {}; + #ifdef MS // expected-note@+5{{previous attribute is here}} // expected-note@+4{{previous attribute is here}}