Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -2863,6 +2863,9 @@ def warn_attribute_dllexport_explicit_instantiation_decl : Warning< "explicit instantiation declaration should not be 'dllexport'">, InGroup>; +def warn_attribute_dllexport_explicit_instantiation_def : Warning< + "'dllexport' attribute ignored on explicit instantiation definition">, + InGroup; def warn_invalid_initializer_from_system_header : Warning< "invalid constructor form class in system header, should not be explicit">, InGroup>; Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp @@ -5697,9 +5697,11 @@ TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); - // Ignore explicit dllexport on explicit class template instantiation declarations. + // Ignore explicit dllexport on explicit class template instantiation + // declarations, except in MinGW mode. if (ClassExported && !ClassAttr->isInherited() && - TSK == TSK_ExplicitInstantiationDeclaration) { + TSK == TSK_ExplicitInstantiationDeclaration && + !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { Class->dropAttr(); return; } Index: cfe/trunk/lib/Sema/SemaTemplate.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp +++ cfe/trunk/lib/Sema/SemaTemplate.cpp @@ -8732,8 +8732,10 @@ ? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - if (TSK == TSK_ExplicitInstantiationDeclaration) { - // Check for dllexport class template instantiation declarations. + if (TSK == TSK_ExplicitInstantiationDeclaration && + !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { + // Check for dllexport class template instantiation declarations, + // except for MinGW mode. for (const ParsedAttr &AL : Attr) { if (AL.getKind() == ParsedAttr::AT_DLLExport) { Diag(ExternLoc, @@ -8793,6 +8795,19 @@ TemplateSpecializationKind PrevDecl_TSK = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared; + if (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl != nullptr && + Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { + // Check for dllexport class template instantiation definitions in MinGW + // mode, if a previous declaration of the instantiation was seen. + for (const ParsedAttr &AL : Attr) { + if (AL.getKind() == ParsedAttr::AT_DLLExport) { + Diag(AL.getLoc(), + diag::warn_attribute_dllexport_explicit_instantiation_def); + break; + } + } + } + if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc, SS.isSet(), TSK)) return true; @@ -8949,6 +8964,14 @@ dllExportImportClassTemplateSpecialization(*this, Def); } + // In MinGW mode, export the template instantiation if the declaration + // was marked dllexport. + if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration && + Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() && + PrevDecl->hasAttr()) { + dllExportImportClassTemplateSpecialization(*this, Def); + } + // Set the template specialization kind. Make sure it is set before // instantiating the members which will trigger ASTConsumer callbacks. Specialization->setTemplateSpecializationKind(TSK); Index: cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp +++ cfe/trunk/test/CodeGenCXX/mingw-template-dllexport.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -emit-llvm -triple i686-mingw32 %s -o - | FileCheck %s + +template +class c { + void f(); +}; + +template void c::f() {} + +template class __declspec(dllexport) c; + +// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv + +extern template class __declspec(dllexport) c; +template class c; + +// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv + +extern template class c; +template class __declspec(dllexport) c; + +// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv + +template +struct outer { + void f(); + struct inner { + void f(); + }; +}; + +template void outer::f() {} +template void outer::inner::f() {} + +template class __declspec(dllexport) outer; + +// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv +// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv Index: cfe/trunk/test/SemaCXX/dllexport.cpp =================================================================== --- cfe/trunk/test/SemaCXX/dllexport.cpp +++ cfe/trunk/test/SemaCXX/dllexport.cpp @@ -367,10 +367,16 @@ // Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported. struct IncompleteType2; -template struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl { // expected-note{{attribute is here}} +#ifdef MS +// expected-note@+2{{attribute is here}} +#endif +template struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl { int f() { return sizeof(T); } // no-error }; -extern template struct ExportedTemplateWithExplicitInstantiationDecl; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}} +#ifdef MS +// expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}} +#endif +extern template struct ExportedTemplateWithExplicitInstantiationDecl; // Instantiate class members for explicitly instantiated exported templates. struct IncompleteType3; // expected-note{{forward declaration of 'IncompleteType3'}} @@ -402,10 +408,17 @@ // Warn about explicit instantiation declarations of dllexport classes. template struct ExplicitInstantiationDeclTemplate {}; -extern template struct __declspec(dllexport) ExplicitInstantiationDeclTemplate; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}} expected-note{{attribute is here}} +#ifdef MS +// expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}} expected-note@+2{{attribute is here}} +#endif +extern template struct __declspec(dllexport) ExplicitInstantiationDeclTemplate; -template struct __declspec(dllexport) ExplicitInstantiationDeclExportedTemplate {}; // expected-note{{attribute is here}} -extern template struct ExplicitInstantiationDeclExportedTemplate; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}} +template struct __declspec(dllexport) ExplicitInstantiationDeclExportedTemplate {}; +#ifdef MS +// expected-note@-2{{attribute is here}} +// expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}} +#endif +extern template struct ExplicitInstantiationDeclExportedTemplate; namespace { struct InternalLinkageType {}; } struct __declspec(dllexport) PR23308 { @@ -438,6 +451,12 @@ template struct ExplicitlyInstantiatedTemplate; template struct ExplicitlyExportInstantiatedTemplate { void func() {} }; template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate; +template struct ExplicitlyExportDeclaredInstantiatedTemplate { void func() {} }; +extern template struct ExplicitlyExportDeclaredInstantiatedTemplate; +#ifndef MS +// expected-warning@+2{{'dllexport' attribute ignored on explicit instantiation definition}} +#endif +template struct __declspec(dllexport) ExplicitlyExportDeclaredInstantiatedTemplate; template struct ExplicitlyImportInstantiatedTemplate { void func() {} }; template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate;