Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -6351,6 +6351,18 @@ if (!ClassAttr) return; + // MSVC allows imported or exported template classes that have UniqueExternal + // linkage. This occurs when the template class has been instantiated with + // a template parameter which itself has internal linkage. + // We drop the attribute to avoid exporting or importing any members. + if ((Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isPS()) && + (!Class->isExternallyVisible() && Class->hasExternalFormalLinkage())) { + Class->dropAttr(); + Class->dropAttr(); + return; + } + if (!Class->isExternallyVisible()) { Diag(Class->getLocation(), diag::err_attribute_dll_not_extern) << Class << ClassAttr; Index: clang/test/CodeGenCXX/dllexport-unique-external.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/dllexport-unique-external.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple i686-windows-msvc -emit-llvm -std=c++1y -fno-threadsafe-statics -fms-extensions -O0 -disable-llvm-passes -o - %s | FileCheck --check-prefix=MSC %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-scei-ps4 -emit-llvm -std=c++1y -fno-threadsafe-statics -fms-extensions -O0 -o - %s | FileCheck --check-prefix=PS %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-sie-ps5 -emit-llvm -std=c++1y -fno-threadsafe-statics -fms-extensions -O0 -o - %s | FileCheck --check-prefix=PS %s + +template struct __declspec(dllexport) ExportedClassTemplate { void func(); }; + +// Make sure that we do not export classes with unique external linkage. +// Note that MSVC does indeed export the symbols in the MSC check string. +void func1() { + class LocalCRTP : public ExportedClassTemplate {}; + LocalCRTP lc; + lc.func(); +} + +namespace { + class AnonNSCRTP : public ExportedClassTemplate {}; + AnonNSCRTP ac; +} + +void func2() { + ac.func(); +} + +// MSC-NOT: declare {{.*}}dllexport +// MSC: call {{.*}}@"?func@?$ExportedClassTemplate@VLocalCRTP@?1??func1@@{{.*}}" +// MSC-NOT: declare {{.*}}dllexport +// MSC: call {{.*}}@"?func@?$ExportedClassTemplate@VAnonNSCRTP@?{{.*}}" +// MSC-NOT: declare {{.*}}dllexport + +// PS-NOT: declare {{.*}}dllexport +// PS: call {{.*}}@_ZN21ExportedClassTemplateIZ5func1vE9LocalCRTPE4funcEv +// PS-NOT: declare {{.*}}dllexport +// PS: call {{.*}}@_ZN21ExportedClassTemplateIN12_GLOBAL__N_110AnonNSCRTPEE4funcEv +// PS-NOT: declare {{.*}}dllexport Index: clang/test/CodeGenCXX/dllimport-unique-external.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/dllimport-unique-external.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple i686-windows-msvc -emit-llvm -std=c++1y -fno-threadsafe-statics -fms-extensions -O0 -disable-llvm-passes -o - %s | FileCheck --check-prefix=MSC %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-scei-ps4 -emit-llvm -std=c++1y -fno-threadsafe-statics -fms-extensions -O0 -o - %s | FileCheck --check-prefix=PS %s +// RUN: %clang_cc1 -no-enable-noundef-analysis -triple x86_64-sie-ps5 -emit-llvm -std=c++1y -fno-threadsafe-statics -fms-extensions -O0 -o - %s | FileCheck --check-prefix=PS %s + +template struct __declspec(dllimport) ImportedClassTemplate { void func(); }; + +// Make sure that we do not import classes with unique external linkage. +// Note that MSVC does indeed expect the called function to be defined elsewhere. +void func1() { + class LocalCRTP : public ImportedClassTemplate {}; + LocalCRTP lc; + lc.func(); +} + +namespace { + class AnonNSCRTP : public ImportedClassTemplate {}; + AnonNSCRTP ac; +} + +void func2() { + ac.func(); +} + +// MSC-NOT: declare {{.*}}dllimport +// MSC: call {{.*}}@"?func@?$ImportedClassTemplate@VLocalCRTP@?1??func1{{.*}}" +// MSC-NOT: declare {{.*}}dllimport +// MSC: call {{.*}}@"?func@?$ImportedClassTemplate@VAnonNSCRTP@?{{.*}}" +// MSC-NOT: declare {{.*}}dllimport + +// PS-NOT: declare {{.*}}dllimport +// PS: call {{.*}}@_ZN21ImportedClassTemplateIZ5func1vE9LocalCRTPE4funcEv +// PS-NOT: declare {{.*}}dllimport +// PS: call {{.*}}@_ZN21ImportedClassTemplateIN12_GLOBAL__N_110AnonNSCRTPEE4funcEv +// PS-NOT: declare {{.*}}dllimport Index: clang/test/SemaCXX/dllexport.cpp =================================================================== --- clang/test/SemaCXX/dllexport.cpp +++ clang/test/SemaCXX/dllexport.cpp @@ -4,8 +4,8 @@ // RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DGNU %s // RUN: %clang_cc1 -triple i686-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI %s // RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++1y -Wunsupported-dll-base-class-template -DWI %s -// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI -DPS %s -// RUN: %clang_cc1 -triple x86_64-sie-ps5 -fsyntax-only -fdeclspec -verify -std=c++1y -Wunsupported-dll-base-class-template -DWI -DPS %s +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++11 -Wunsupported-dll-base-class-template -DPS %s +// RUN: %clang_cc1 -triple x86_64-sie-ps5 -fsyntax-only -fdeclspec -verify -std=c++1y -Wunsupported-dll-base-class-template -DPS %s // Helper structs to make templates more expressive. struct ImplicitInst_Exported {}; @@ -353,7 +353,7 @@ class __declspec(dllexport) ClassDef {}; -#if defined(MS) || defined (WI) +#if defined(MS) || defined (WI) || defined(PS) // expected-warning@+3{{'dllexport' attribute ignored}} #endif template struct PartiallySpecializedClassTemplate {}; @@ -371,13 +371,13 @@ // Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported. struct IncompleteType2; -#if defined(MS) || defined (WI) +#if defined(MS) || defined (WI) || defined(PS) // expected-note@+2{{attribute is here}} #endif template struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl { int f() { return sizeof(T); } // no-error }; -#if defined(MS) || defined (WI) +#if defined(MS) || defined (WI) || defined(PS) // expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}} #endif extern template struct ExportedTemplateWithExplicitInstantiationDecl; @@ -412,13 +412,13 @@ // Warn about explicit instantiation declarations of dllexport classes. template struct ExplicitInstantiationDeclTemplate {}; -#if defined(MS) || defined (WI) +#if defined(MS) || defined (WI) || defined(PS) // 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 {}; -#if defined(MS) || defined (WI) +#if defined(MS) || defined (WI) || defined(PS) // expected-note@-2{{attribute is here}} // expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}} #endif @@ -434,7 +434,13 @@ // Classes with template base classes //===----------------------------------------------------------------------===// +class __declspec(dllexport) ExportedClass {}; +class __declspec(dllimport) ImportedClass {}; + template class ClassTemplate {}; +#if not defined(MS) && not defined(PS) +// expected-error@+2{{'ExportedClassTemplate' must have external linkage when declared 'dllexport'}} +#endif template class __declspec(dllexport) ExportedClassTemplate {}; template class __declspec(dllimport) ImportedClassTemplate {}; @@ -457,7 +463,7 @@ template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate; template struct ExplicitlyExportDeclaredInstantiatedTemplate { void func() {} }; extern template struct ExplicitlyExportDeclaredInstantiatedTemplate; -#if not defined(MS) && not defined (WI) +#if not defined(MS) && not defined (WI) && not defined(PS) // expected-warning@+2{{'dllexport' attribute ignored on explicit instantiation definition}} #endif template struct __declspec(dllexport) ExplicitlyExportDeclaredInstantiatedTemplate; @@ -516,6 +522,15 @@ extern template struct ExplicitInstantiationDeclTemplateBase; struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase {}; +void func() { + // MSVC allows deriving from exported template classes in local contexts. + class LocalDerivedFromExportedClass : public ExportedClass {}; + class LocalDerivedFromExportedTemplate : public ExportedClassTemplate {}; +#if not defined(MS) && not defined (PS) + // expected-note@+2{{in instantiation of template class 'ExportedClassTemplate' requested here}} +#endif + class LocalCRTP : public ExportedClassTemplate {}; +} //===----------------------------------------------------------------------===// // Precedence @@ -1180,7 +1195,7 @@ // Lambdas //===----------------------------------------------------------------------===// // The MS ABI doesn't provide a stable mangling for lambdas, so they can't be imported or exported. -#if defined(MS) || defined (WI) +#if defined(MS) || defined (WI) || defined(PS) // expected-error@+2{{lambda cannot be declared 'dllexport'}} #endif auto Lambda = []() __declspec(dllexport) -> bool { return true; }; Index: clang/test/SemaCXX/dllimport.cpp =================================================================== --- clang/test/SemaCXX/dllimport.cpp +++ clang/test/SemaCXX/dllimport.cpp @@ -5,9 +5,9 @@ // RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions -verify -std=c++17 -Wunsupported-dll-base-class-template -DGNU %s // RUN: %clang_cc1 -triple i686-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI %s // RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI %s -// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI -DPS %s -// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI -DPS %s -// RUN: %clang_cc1 -triple x86_64-sie-ps5 -fsyntax-only -fdeclspec -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI -DPS %s +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++11 -Wunsupported-dll-base-class-template -DPS %s +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++17 -Wunsupported-dll-base-class-template -DPS %s +// RUN: %clang_cc1 -triple x86_64-sie-ps5 -fsyntax-only -fdeclspec -verify -std=c++17 -Wunsupported-dll-base-class-template -DPS %s // Helper structs to make templates more expressive. struct ImplicitInst_Imported {}; @@ -60,7 +60,7 @@ // expected-note@+2{{previous attribute is here}} #endif __declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -71,7 +71,7 @@ // expected-note@+2{{previous attribute is here}} #endif __declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'GlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -82,7 +82,7 @@ // expected-note@+2{{previous attribute is here}} #endif int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -93,7 +93,7 @@ // expected-note@+2{{previous attribute is here}} #endif int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -184,7 +184,7 @@ #endif template __declspec(dllimport) extern int ExternVarTmplDeclInit; // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+5{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+3{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -197,7 +197,7 @@ #endif template __declspec(dllimport) int VarTmplDeclInit; // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+5{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+3{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -312,7 +312,7 @@ #endif __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}} // NB: Both MSVC and Clang issue a warning and make redecl3 dllexport. -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'redecl3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -327,7 +327,7 @@ __declspec(dllimport) void redecl5(); // expected-warning{{redeclaration of 'redecl5' should not add 'dllimport' attribute}} } -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) void redecl6(); // expected-note{{previous declaration is here}} __declspec(dllimport) inline void redecl6() {} // expected-warning{{redeclaration of 'redecl6' should not add 'dllimport' attribute}} #else @@ -344,21 +344,21 @@ #endif friend __declspec(dllimport) void friend3(); // expected-note{{previous declaration is here}} friend void friend4(); // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+2{{previous declaration is here}} #endif friend void friend5(); }; __declspec(dllimport) void friend1(); void friend2(); // expected-warning{{'friend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'friend3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'friend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} #endif void friend3() {} __declspec(dllimport) void friend4(); // expected-warning{{redeclaration of 'friend4' should not add 'dllimport' attribute}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) __declspec(dllimport) inline void friend5() {} // expected-warning{{redeclaration of 'friend5' should not add 'dllimport' attribute}} #else __declspec(dllimport) inline void friend5() {} // expected-warning{{'dllimport' attribute ignored on inline function}} @@ -386,7 +386,7 @@ // here which is irrelevant. But because the delete keyword is parsed later // there is currently no straight-forward way to avoid this diagnostic. __declspec(dllimport) void deletedFunc() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}} expected-error{{dllimport cannot be applied to non-inline function definition}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) __declspec(dllimport) inline void deletedInlineFunc() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}} #else __declspec(dllimport) inline void deletedInlineFunc() = delete; // expected-warning{{'dllimport' attribute ignored on inline function}} @@ -464,7 +464,7 @@ template void funcTmplFriend2(); // expected-warning{{'funcTmplFriend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} template void funcTmplFriend3() {} // expected-warning{{'funcTmplFriend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} template __declspec(dllimport) void funcTmplFriend4(); // expected-error{{redeclaration of 'funcTmplFriend4' cannot add 'dllimport' attribute}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+2{{'funcTmplFriend5' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} #endif template inline void funcTmplFriend5() {} @@ -598,13 +598,13 @@ __declspec(dllimport) constexpr static int ConstexprFieldDef = 1; }; -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} #endif void ImportMembers::Nested::normalDef() {} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -615,7 +615,7 @@ #endif inline void ImportMembers::normalInlineDef() {} void ImportMembers::normalInlineDecl() {} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -626,7 +626,7 @@ #endif inline void ImportMembers::virtualInlineDef() {} void ImportMembers::virtualInlineDecl() {} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -699,7 +699,7 @@ // Import deleted member functions. struct ImportDeleted { -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) __declspec(dllimport) ImportDeleted() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}} __declspec(dllimport) ~ImportDeleted() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}} __declspec(dllimport) ImportDeleted(const ImportDeleted&) = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}} @@ -772,7 +772,7 @@ // Not allowed on definitions. __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs() = default; // expected-error{{dllimport cannot be applied to non-inline function definition}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+5{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+3{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -789,7 +789,7 @@ inline ImportDefaultedDefs& ImportDefaultedDefs::operator=(const ImportDefaultedDefs&) = default; __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs(ImportDefaultedDefs&&) = default; // expected-error{{dllimport cannot be applied to non-inline function definition}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+4{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+2{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -805,7 +805,7 @@ static void staticDef(); // expected-note{{previous declaration is here}} static inline void staticInlineDecl(); // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+4{{previous declaration is here}} // expected-note@+4{{previous declaration is here}} // expected-note@+4{{previous declaration is here}} @@ -829,7 +829,7 @@ // expected-error@-1{{dllimport cannot be applied to non-inline function definition}} __declspec(dllimport) void MemberRedecl::staticInlineDecl() {} // expected-error{{redeclaration of 'MemberRedecl::staticInlineDecl' cannot add 'dllimport' attribute}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) __declspec(dllimport) inline void MemberRedecl::normalInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::normalInlineDef' cannot add 'dllimport' attribute}} __declspec(dllimport) inline void MemberRedecl::virtualInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::virtualInlineDef' cannot add 'dllimport' attribute}} __declspec(dllimport) inline void MemberRedecl::staticInlineDef() {} // expected-error{{redeclaration of 'MemberRedecl::staticInlineDef' cannot add 'dllimport' attribute}} @@ -866,13 +866,13 @@ struct ImportMemberTmpl { template __declspec(dllimport) void normalDecl(); template __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} #endif template __declspec(dllimport) void normalInlineDef(); template __declspec(dllimport) static void staticDecl(); template __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} #endif template __declspec(dllimport) static void staticInlineDef(); @@ -935,7 +935,7 @@ template static void staticDef(); // expected-note{{previous declaration is here}} template static inline void staticInlineDecl(); // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+3{{previous declaration is here}} // expected-note@+3{{previous declaration is here}} #endif @@ -953,7 +953,7 @@ template __declspec(dllimport) void MemTmplRedecl::normalDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalDef' cannot add 'dllimport' attribute}} // expected-error@-1{{dllimport cannot be applied to non-inline function definition}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) template __declspec(dllimport) inline void MemTmplRedecl::normalInlineDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalInlineDef' cannot add 'dllimport' attribute}} #else template __declspec(dllimport) inline void MemTmplRedecl::normalInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}} @@ -961,7 +961,7 @@ template __declspec(dllimport) void MemTmplRedecl::normalInlineDecl() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalInlineDecl' cannot add 'dllimport' attribute}} template __declspec(dllimport) void MemTmplRedecl::staticDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::staticDef' cannot add 'dllimport' attribute}} // expected-error@-1{{dllimport cannot be applied to non-inline function definition}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) template __declspec(dllimport) inline void MemTmplRedecl::staticInlineDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::staticInlineDef' cannot add 'dllimport' attribute}} #else template __declspec(dllimport) inline void MemTmplRedecl::staticInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}} @@ -1197,7 +1197,7 @@ // NB: MSVC is inconsistent here and disallows *InlineDef on class templates, // but allows it on classes. We allow both. -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+5{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+3{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -1209,7 +1209,7 @@ #endif template inline void ImportClassTmplMembers::normalInlineDef() {} template void ImportClassTmplMembers::normalInlineDecl() {} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+5{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+3{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -1221,7 +1221,7 @@ #endif template inline void ImportClassTmplMembers::virtualInlineDef() {} template void ImportClassTmplMembers::virtualInlineDecl() {} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+5{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}} #else // expected-warning@+3{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}} @@ -1252,7 +1252,7 @@ static void staticDef(); // expected-note{{previous declaration is here}} static inline void staticInlineDecl(); // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+4{{previous declaration is here}} // expected-note@+4{{previous declaration is here}} // expected-note@+4{{previous declaration is here}} @@ -1276,7 +1276,7 @@ // expected-error@-1{{dllimport cannot be applied to non-inline function definition}} template __declspec(dllimport) void CTMR::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMR::staticInlineDecl' cannot add 'dllimport' attribute}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) template __declspec(dllimport) inline void CTMR::normalInlineDef() {} // expected-error{{redeclaration of 'CTMR::normalInlineDef' cannot add 'dllimport' attribute}} template __declspec(dllimport) inline void CTMR::virtualInlineDef() {} // expected-error{{redeclaration of 'CTMR::virtualInlineDef' cannot add 'dllimport' attribute}} template __declspec(dllimport) inline void CTMR::staticInlineDef() {} // expected-error{{redeclaration of 'CTMR::staticInlineDef' cannot add 'dllimport' attribute}} @@ -1340,13 +1340,13 @@ struct ImportClsTmplMemTmpl { template __declspec(dllimport) void normalDecl(); template __declspec(dllimport) void normalDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} #endif template __declspec(dllimport) void normalInlineDef(); template __declspec(dllimport) static void staticDecl(); template __declspec(dllimport) static void staticDef(); // expected-note{{previous declaration is here}} expected-note{{previous attribute is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} #endif template __declspec(dllimport) static void staticInlineDef(); @@ -1358,12 +1358,12 @@ // expected-warning@+11{{'dllimport' attribute ignored on inline function}} #endif template __declspec(dllimport) void normalInclass() {} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} #endif template __declspec(dllimport) inline void normalInlineDecl(); template __declspec(dllimport) static void staticInclass() {} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+2{{previous declaration is here}} expected-note@+2{{previous attribute is here}} #endif template __declspec(dllimport) static inline void staticInlineDecl(); @@ -1417,7 +1417,7 @@ template static void staticDef(); // expected-note{{previous declaration is here}} template static inline void staticInlineDecl(); // expected-note{{previous declaration is here}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+3{{previous declaration is here}} // expected-note@+3{{previous declaration is here}} #endif @@ -1440,7 +1440,7 @@ // expected-error@-1{{dllimport cannot be applied to non-inline function definition}} template template __declspec(dllimport) void CTMTR::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDecl' cannot add 'dllimport' attribute}} -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) template template __declspec(dllimport) inline void CTMTR::normalInlineDef() {} // expected-error{{redeclaration of 'CTMTR::normalInlineDef' cannot add 'dllimport' attribute}} template template __declspec(dllimport) inline void CTMTR::staticInlineDef() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDef' cannot add 'dllimport' attribute}} #else @@ -1477,7 +1477,7 @@ template class ClassTemplate {}; -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+5{{previous attribute is here}} // expected-note@+4{{previous attribute is here}} // expected-error@+4{{attribute 'dllexport' cannot be applied to member of 'dllimport' class}} @@ -1488,7 +1488,7 @@ void __declspec(dllimport) bar(); }; -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-note@+5{{previous attribute is here}} // expected-note@+4{{previous attribute is here}} // expected-error@+4{{attribute 'dllimport' cannot be applied to member of 'dllexport' class}} @@ -1514,7 +1514,7 @@ S s; } -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-warning@+3{{'dllimport' attribute ignored}} #endif template struct PartiallySpecializedClassTemplate {}; @@ -1528,8 +1528,14 @@ // Classes with template base classes //===----------------------------------------------------------------------===// +class __declspec(dllexport) ExportedClass {}; +class __declspec(dllimport) ImportedClass {}; + template class __declspec(dllexport) ExportedClassTemplate {}; +#if !defined(MS) && !defined(PS) +// expected-error@+2{{'ImportedClassTemplate' must have external linkage when declared 'dllimport'}} +#endif template class __declspec(dllimport) ImportedClassTemplate {}; // ClassTemplate gets imported. @@ -1604,11 +1610,21 @@ 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 {}; +#if defined(GNU) || defined(WI) + // expected-note@+2{{in instantiation of template class 'ImportedClassTemplate' requested here}} +#endif + class LocalCRTP : public ImportedClassTemplate {}; +} + //===----------------------------------------------------------------------===// // Lambdas //===----------------------------------------------------------------------===// // The MS ABI doesn't provide a stable mangling for lambdas, so they can't be imported or exported. -#if defined(MS) || defined(WI) +#if defined(MS) || defined(WI) || defined(PS) // expected-error@+4{{lambda cannot be declared 'dllimport'}} #else // expected-warning@+2{{'dllimport' attribute ignored on inline function}}