Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7663,20 +7663,31 @@ Specialization->getDefinition()); if (Def) { TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind(); - // Fix a TSK_ExplicitInstantiationDeclaration followed by a - // TSK_ExplicitInstantiationDefinition - if (Old_TSK == TSK_ExplicitInstantiationDeclaration && - (TSK == TSK_ExplicitInstantiationDefinition || - DLLImportExplicitInstantiationDef)) { + // Fix a TSK_ExplicitInstantiationDeclaration or a TSK_ImplicitInstantiation + // followed by a TSK_ExplicitInstantiationDefinition + if ((Old_TSK == TSK_ExplicitInstantiationDeclaration && + (TSK == TSK_ExplicitInstantiationDefinition || + DLLImportExplicitInstantiationDef)) || + (Old_TSK == TSK_ImplicitInstantiation && + TSK == TSK_ExplicitInstantiationDefinition)) { // FIXME: Need to notify the ASTMutationListener that we did this. Def->setTemplateSpecializationKind(TSK); - if (!getDLLAttr(Def) && getDLLAttr(Specialization) && + if (((!getDLLAttr(Def) && getDLLAttr(Specialization)) || + (Old_TSK == TSK_ImplicitInstantiation && + Specialization->hasAttr())) && (Context.getTargetInfo().getCXXABI().isMicrosoft() || Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) { // In the MS ABI, an explicit instantiation definition can add a dll - // attribute to a template with a previous instantiation declaration. - // MinGW doesn't allow this. + // attribute to a template with a previous instantiation declaration + // or implicit instantiation. MinGW doesn't allow this. In the implicit + // instantiation case, we limit clang to only adding dllexport, to avoid + // potentially strange codegen behavior. For example, if we extend this + // conditional to dllimport, and we have a source file calling a method + // on an implicitly instantiated template class instance and then + // declaring a dllimport explicit instantiation definition for the same + // template class, the codegen for the method call will not respect the + // dllimport, while it will with cl. auto *A = cast( getDLLAttr(Specialization)->clone(getASTContext())); A->setInherited(true); Index: test/CodeGenCXX/dllexport.cpp =================================================================== --- test/CodeGenCXX/dllexport.cpp +++ test/CodeGenCXX/dllexport.cpp @@ -771,6 +771,13 @@ // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.ExplicitInstantiationDeclExportedDefTemplate* @"\01??0?$ExplicitInstantiationDeclExportedDefTemplate@H@@QAE@XZ" // G32-DAG: define weak_odr x86_thiscallcc void @_ZN44ExplicitInstantiationDeclExportedDefTemplateIiE1fEv +template struct ImplicitInstantiationExplicitInstantiationDefExportedTemplate { void f() {} }; +ImplicitInstantiationExplicitInstantiationDefExportedTemplate ImplicitInstantiationExplicitInstantiationDefExportedTemplateInstance; +template class __declspec(dllexport) ImplicitInstantiationExplicitInstantiationDefExportedTemplate; +USEMEMFUNC(ImplicitInstantiationExplicitInstantiationDefExportedTemplate, f); +// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$ImplicitInstantiationExplicitInstantiationDefExportedTemplate@H@@QAEXXZ" +// G32-DAG: define weak_odr x86_thiscallcc void @_ZN61ImplicitInstantiationExplicitInstantiationDefExportedTemplateIiE1fEv + namespace { struct InternalLinkageType {}; } struct __declspec(dllexport) PR23308 { void f(InternalLinkageType*); Index: test/CodeGenCXX/windows-itanium-dllexport.cpp =================================================================== --- test/CodeGenCXX/windows-itanium-dllexport.cpp +++ test/CodeGenCXX/windows-itanium-dllexport.cpp @@ -23,3 +23,8 @@ // CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcEaSERKS0_ // CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv +c g; +template class __declspec(dllexport) c; + +// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_ +// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv