// 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 {};
class __declspec(dllexport) ClassDef {};
-#if defined(MS) || defined (WI)
+#if defined(MS) || defined (WI) || defined(PS)
// expected-warning@+3{{'dllexport' attribute ignored}}
#endif
template <typename T> struct PartiallySpecializedClassTemplate {};
// 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 <typename T> 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<IncompleteType2>;
// Warn about explicit instantiation declarations of dllexport classes.
template <typename T> 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<int>;
template <typename T> 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
// Classes with template base classes
//===----------------------------------------------------------------------===//
+class __declspec(dllexport) ExportedClass {};
+class __declspec(dllimport) ImportedClass {};
+
template <typename T> class ClassTemplate {};
+#if not defined(MS) && not defined(PS)
+// expected-error@+2{{'ExportedClassTemplate<LocalCRTP>' must have external linkage when declared 'dllexport'}}
+#endif
template <typename T> class __declspec(dllexport) ExportedClassTemplate {};
template <typename T> class __declspec(dllimport) ImportedClassTemplate {};
template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>;
template <typename T> struct ExplicitlyExportDeclaredInstantiatedTemplate { void func() {} };
extern template struct ExplicitlyExportDeclaredInstantiatedTemplate<int>;
-#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<int>;
extern template struct ExplicitInstantiationDeclTemplateBase<int>;
struct __declspec(dllexport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase<int> {};
+void func() {
+ // MSVC allows deriving from exported template classes in local contexts.
+ class LocalDerivedFromExportedClass : public ExportedClass {};
+ class LocalDerivedFromExportedTemplate : public ExportedClassTemplate<int> {};
+#if not defined(MS) && not defined (PS)
+ // expected-note@+2{{in instantiation of template class 'ExportedClassTemplate<LocalCRTP>' requested here}}
+#endif
+ class LocalCRTP : public ExportedClassTemplate<LocalCRTP> {};
+}
//===----------------------------------------------------------------------===//
// Precedence
// 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; };
// 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 {};
// 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}}
// 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}}
// 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}}
// 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}}
#endif
template <typename T>
__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}}
#endif
template <typename T>
__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}}
#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}}
__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
#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}}
// 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}}
template<typename T> void funcTmplFriend2(); // expected-warning{{'funcTmplFriend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
template<typename T> void funcTmplFriend3() {} // expected-warning{{'funcTmplFriend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
template<typename T> __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<typename T> inline void funcTmplFriend5() {}
__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}}
#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}}
#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}}
// 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}}
// 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}}
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}}
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}}
// 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}}
struct ImportMemberTmpl {
template<typename T> __declspec(dllimport) void normalDecl();
template<typename T> __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<typename T> __declspec(dllimport) void normalInlineDef();
template<typename T> __declspec(dllimport) static void staticDecl();
template<typename T> __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<typename T> __declspec(dllimport) static void staticInlineDef();
template<typename T> static void staticDef(); // expected-note{{previous declaration is here}}
template<typename T> 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
template<typename T> __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<typename T> __declspec(dllimport) inline void MemTmplRedecl::normalInlineDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalInlineDef' cannot add 'dllimport' attribute}}
#else
template<typename T> __declspec(dllimport) inline void MemTmplRedecl::normalInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
template<typename T> __declspec(dllimport) void MemTmplRedecl::normalInlineDecl() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalInlineDecl' cannot add 'dllimport' attribute}}
template<typename T> __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<typename T> __declspec(dllimport) inline void MemTmplRedecl::staticInlineDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::staticInlineDef' cannot add 'dllimport' attribute}}
#else
template<typename T> __declspec(dllimport) inline void MemTmplRedecl::staticInlineDef() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
// 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}}
#endif
template<typename T> inline void ImportClassTmplMembers<T>::normalInlineDef() {}
template<typename T> void ImportClassTmplMembers<T>::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}}
#endif
template<typename T> inline void ImportClassTmplMembers<T>::virtualInlineDef() {}
template<typename T> void ImportClassTmplMembers<T>::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}}
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}}
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
template<typename T> __declspec(dllimport) void CTMR<T>::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMR::staticInlineDecl' cannot add 'dllimport' attribute}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
template<typename T> __declspec(dllimport) inline void CTMR<T>::normalInlineDef() {} // expected-error{{redeclaration of 'CTMR::normalInlineDef' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) inline void CTMR<T>::virtualInlineDef() {} // expected-error{{redeclaration of 'CTMR::virtualInlineDef' cannot add 'dllimport' attribute}}
template<typename T> __declspec(dllimport) inline void CTMR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMR::staticInlineDef' cannot add 'dllimport' attribute}}
struct ImportClsTmplMemTmpl {
template<typename U> __declspec(dllimport) void normalDecl();
template<typename U> __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<typename U> __declspec(dllimport) void normalInlineDef();
template<typename U> __declspec(dllimport) static void staticDecl();
template<typename U> __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<typename U> __declspec(dllimport) static void staticInlineDef();
// expected-warning@+11{{'dllimport' attribute ignored on inline function}}
#endif
template<typename U> __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<typename U> __declspec(dllimport) inline void normalInlineDecl();
template<typename U> __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<typename U> __declspec(dllimport) static inline void staticInlineDecl();
template<typename U> static void staticDef(); // expected-note{{previous declaration is here}}
template<typename U> 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
// expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
template<typename T> template<typename U> __declspec(dllimport) void CTMTR<T>::staticInlineDecl() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDecl' cannot add 'dllimport' attribute}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::normalInlineDef() {} // expected-error{{redeclaration of 'CTMTR::normalInlineDef' cannot add 'dllimport' attribute}}
template<typename T> template<typename U> __declspec(dllimport) inline void CTMTR<T>::staticInlineDef() {} // expected-error{{redeclaration of 'CTMTR::staticInlineDef' cannot add 'dllimport' attribute}}
#else
template <typename T> 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}}
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}}
S<int> s;
}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
// expected-warning@+3{{'dllimport' attribute ignored}}
#endif
template <typename T> struct PartiallySpecializedClassTemplate {};
// Classes with template base classes
//===----------------------------------------------------------------------===//
+class __declspec(dllexport) ExportedClass {};
+class __declspec(dllimport) ImportedClass {};
+
template <typename T> class __declspec(dllexport) ExportedClassTemplate {};
+#if !defined(MS) && !defined(PS)
+// expected-error@+2{{'ImportedClassTemplate<LocalCRTP>' must have external linkage when declared 'dllimport'}}
+#endif
template <typename T> class __declspec(dllimport) ImportedClassTemplate {};
// ClassTemplate<int> gets imported.
extern template struct ExplicitInstantiationDeclTemplateBase<int>;
struct __declspec(dllimport) DerivedFromExplicitInstantiationDeclTemplateBase : public ExplicitInstantiationDeclTemplateBase<int> {};
+void func() {
+ // MSVC propagates dllimport to derived classes even if they don't have external linkage.
+ class LocalDerivedFromImportedClass : public ImportedClass {};
+ class LocalDerivedFromImportedTemplate : public ImportedClassTemplate<int> {};
+#if defined(GNU) || defined(WI)
+ // expected-note@+2{{in instantiation of template class 'ImportedClassTemplate<LocalCRTP>' requested here}}
+#endif
+ class LocalCRTP : public ImportedClassTemplate<LocalCRTP> {};
+}
+
//===----------------------------------------------------------------------===//
// 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}}