summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2014-06-25 18:25:57 +0000
committerHans Wennborg <hans@hanshq.net>2014-06-25 18:25:57 +0000
commite5fdb78baffc29df6c772dbe80c113bc22bd72c6 (patch)
tree58027e501f90d4c522627694a29d701b6e5e0b64
parentccaf37e1c9c5e4bf74224ef779d62b3ba05e3615 (diff)
downloadclang-e5fdb78baffc29df6c772dbe80c113bc22bd72c6.tar.gz
clang-e5fdb78baffc29df6c772dbe80c113bc22bd72c6.tar.bz2
clang-e5fdb78baffc29df6c772dbe80c113bc22bd72c6.tar.xz
MS ABI: Propagate class-level DLL attributes to class template specialization bases (PR11170)
Consider the following code: template <typename T> class Base {}; class __declspec(dllexport) class Derived : public Base<int> {} 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<int> 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
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td9
-rw-r--r--lib/Sema/SemaDeclCXX.cpp67
-rw-r--r--test/CodeGenCXX/dllexport.cpp98
-rw-r--r--test/CodeGenCXX/dllimport.cpp99
-rw-r--r--test/SemaCXX/dllexport.cpp82
-rw-r--r--test/SemaCXX/dllimport.cpp83
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> {};