Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -486,6 +486,12 @@ if (considerVisibility) LV.mergeVisibility(argsLV); LV.mergeExternalVisibility(argsLV); + + // MSVC forces external linkage for explicit instantiations of template + // classes with dllexport/dllimport attributes. + if (spec->getASTContext().getTargetInfo().shouldDLLImportComdatSymbols()) + if (spec->hasAttr() || spec->hasAttr()) + LV.setLinkage(Linkage::ExternalLinkage); } /// Should we consider visibility associated with the template @@ -1346,6 +1352,15 @@ } ASTContext &Context = D->getASTContext(); + + // MSVC allows dllexport/llimport on local classes and imparts external + // linkage to them. + if (Context.getTargetInfo().shouldDLLImportComdatSymbols()) { + if (const auto *Record = dyn_cast(D)) + if (Record->hasAttr() || Record->hasAttr()) + return LinkageInfo(); + } + if (!Context.getLangOpts().CPlusPlus) return LinkageInfo::none(); Index: clang/test/SemaCXX/dllexport.cpp =================================================================== --- clang/test/SemaCXX/dllexport.cpp +++ clang/test/SemaCXX/dllexport.cpp @@ -434,7 +434,16 @@ // Classes with template base classes //===----------------------------------------------------------------------===// +class Base {}; +class __declspec(dllexport) ExportedClass {}; +class __declspec(dllimport) ImportedClass {}; + template class ClassTemplate {}; +#if not defined(MS) && not defined(WI) +// expected-error@+4{{'ExportedClassTemplate' must have external linkage when declared 'dllexport'}} +// expected-error@+3{{'ExportedClassTemplate' must have external linkage when declared 'dllexport'}} +// expected-error@+3{{'ImportedClassTemplate' must have external linkage when declared 'dllimport'}} +#endif template class __declspec(dllexport) ExportedClassTemplate {}; template class __declspec(dllimport) ImportedClassTemplate {}; @@ -516,6 +525,44 @@ extern template struct ExplicitInstantiationDeclTemplateBase; struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase {}; +void func() { + // MSVC propagates dllexport to derived classes even if they don't have external linkage. + class LocalDerivedFromExportedClass : public ExportedClass {}; + class LocalDerivedFromExportedTemplate : public ExportedClassTemplate {}; +#if not defined(MS) && not defined (WI) + // expected-note@+2{{in instantiation of template class 'ExportedClassTemplate' requested here}} +#endif + class LocalCRTP : public ExportedClassTemplate {}; + // MSVC allows exported classes in a local context. +#if not defined(MS) && not defined (WI) + // expected-error@+10{{'ExportedLocalDerivedFromBase' must have external linkage when declared 'dllexport'}} + // expected-error@+10{{'ExportedLocalDerivedFromTemplate' must have external linkage when declared 'dllexport'}} + // expected-error@+10{{'ExportedLocalDerivedFromExportedClass' must have external linkage when declared 'dllexport'}} + // expected-error@+10{{'ExportedLocalDerivedFromImportedClass' must have external linkage when declared 'dllexport'}} + // expected-error@+10{{'ExportedLocalDerivedFromExportedTemplate' must have external linkage when declared 'dllexport'}} + // expected-error@+10{{'ExportedLocalDerivedFromImportedTemplate' must have external linkage when declared 'dllexport'}} + // expected-error@+10{{'ExportedLocalCRTP' must have external linkage when declared 'dllexport'}} + // expected-error@+10{{'ExportedLocalDerivedFromExportedTemplateCRTP' must have external linkage when declared 'dllexport'}} + // expected-error@+14{{'ExportedLocalDerivedFromImportedTemplateCRTP' must have external linkage when declared 'dllexport'}} +#endif + class __declspec(dllexport) ExportedLocalDerivedFromBase : public Base {}; + class __declspec(dllexport) ExportedLocalDerivedFromTemplate : public ClassTemplate {}; + class __declspec(dllexport) ExportedLocalDerivedFromExportedClass : public ExportedClass {}; + class __declspec(dllexport) ExportedLocalDerivedFromImportedClass : public ImportedClass {}; + class __declspec(dllexport) ExportedLocalDerivedFromExportedTemplate : public ExportedClassTemplate {}; + class __declspec(dllexport) ExportedLocalDerivedFromImportedTemplate : public ImportedClassTemplate {}; + class __declspec(dllexport) ExportedLocalCRTP : public ClassTemplate {}; + class __declspec(dllexport) ExportedLocalDerivedFromExportedTemplateCRTP : +#if not defined(MS) && not defined (WI) + // expected-note@+2{{in instantiation of template class 'ExportedClassTemplate' requested here}} +#endif + public ExportedClassTemplate {}; + class __declspec(dllexport) ExportedLocalDerivedFromImportedTemplateCRTP : +#if not defined(MS) && not defined (WI) + // expected-note@+2{{in instantiation of template class 'ImportedClassTemplate' requested here}} +#endif + public ImportedClassTemplate {}; +} //===----------------------------------------------------------------------===// // Precedence Index: clang/test/SemaCXX/dllimport.cpp =================================================================== --- clang/test/SemaCXX/dllimport.cpp +++ clang/test/SemaCXX/dllimport.cpp @@ -228,7 +228,6 @@ template __declspec(dllimport) auto InternalAutoTypeVarTmpl = Internal(); // expected-error{{definition of dllimport data}} // expected-error{{'InternalAutoTypeVarTmpl' must have external linkage when declared 'dllimport'}} - template int VarTmpl; template __declspec(dllimport) int ImportedVarTmpl; @@ -1528,8 +1527,19 @@ // Classes with template base classes //===----------------------------------------------------------------------===// +class Base {}; +class __declspec(dllexport) ExportedClass {}; +class __declspec(dllimport) ImportedClass {}; + +#ifdef GNU +// expected-error@+2{{'ExportedClassTemplate' must have external linkage when declared 'dllexport'}} +#endif template class __declspec(dllexport) ExportedClassTemplate {}; +#ifdef GNU +// expected-error@+3{{'ImportedClassTemplate' must have external linkage when declared 'dllimport'}} +// expected-error@+2{{'ImportedClassTemplate' must have external linkage when declared 'dllimport'}} +#endif template class __declspec(dllimport) ImportedClassTemplate {}; // ClassTemplate gets imported. @@ -1604,6 +1614,41 @@ extern template struct ExplicitInstantiationDeclTemplateBase; struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase {}; +void func() { + // MSVC propagates dllimport to derived classes even if they don't have external linkage. + class LocalDerivedFromImportedClass : public ImportedClass {}; + class LocalDerivedFromImportedTemplate : public ImportedClassTemplate {}; +#ifdef GNU + // expected-note@+2{{in instantiation of template class 'ImportedClassTemplate' requested here}} +#endif + class LocalCRTP : public ImportedClassTemplate {}; + // MSVC allows imported classes in a local context. +#ifdef GNU + // expected-error@+12{{'ImportedLocalDerivedFromBase' must have external linkage when declared 'dllimport'}} + // expected-error@+12{{'ImportedLocalDerivedFromTemplate' must have external linkage when declared 'dllimport'}} + // expected-error@+12{{'ImportedLocalDerivedFromExportedClass' must have external linkage when declared 'dllimport'}} + // expected-error@+12{{'ImportedLocalDerivedFromImportedClass' must have external linkage when declared 'dllimport'}} + // expected-error@+12{{'ImportedLocalDerivedFromExportedTemplate' must have external linkage when declared 'dllimport'}} + // expected-error@+12{{'ImportedLocalDerivedFromImportedTemplate' must have external linkage when declared 'dllimport'}} + // expected-error@+12{{'ImportedLocalCRTP' must have external linkage when declared 'dllimport'}} + // expected-error@+12{{'ImportedLocalDerivedFromExportedTemplateCRTP' must have external linkage when declared 'dllimport'}} + // expected-error@+13{{'ImportedLocalDerivedFromImportedTemplateCRTP' must have external linkage when declared 'dllimport'}} + // expected-note@+11{{in instantiation of template class 'ExportedClassTemplate' requested here}} + // expected-note@+12{{in instantiation of template class 'ImportedClassTemplate' requested here}} +#endif + class __declspec(dllimport) ImportedLocalDerivedFromBase : public Base {}; + class __declspec(dllimport) ImportedLocalDerivedFromTemplate : public ClassTemplate {}; + class __declspec(dllimport) ImportedLocalDerivedFromExportedClass : public ExportedClass {}; + class __declspec(dllimport) ImportedLocalDerivedFromImportedClass : public ImportedClass {}; + class __declspec(dllimport) ImportedLocalDerivedFromExportedTemplate : public ExportedClassTemplate {}; + class __declspec(dllimport) ImportedLocalDerivedFromImportedTemplate : public ImportedClassTemplate {}; + class __declspec(dllimport) ImportedLocalCRTP : public ClassTemplate {}; + class __declspec(dllimport) ImportedLocalDerivedFromExportedTemplateCRTP : + public ExportedClassTemplate {}; + class __declspec(dllimport) ImportedLocalDerivedFromImportedTemplateCRTP : + public ImportedClassTemplate {}; +} + //===----------------------------------------------------------------------===// // Lambdas //===----------------------------------------------------------------------===//