[clang] 477f9ce - [MSCV][dllexport/dllimport][PS] Allow UniqueExternal linkage classes with dllexport/dllimport
Wolfgang Pieb via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 29 11:15:29 PDT 2023
Author: Wolfgang Pieb
Date: 2023-03-29T18:15:04Z
New Revision: 477f9cea77e6d55ecddaafbedccd418750c40dbd
URL: https://github.com/llvm/llvm-project/commit/477f9cea77e6d55ecddaafbedccd418750c40dbd
DIFF: https://github.com/llvm/llvm-project/commit/477f9cea77e6d55ecddaafbedccd418750c40dbd.diff
LOG: [MSCV][dllexport/dllimport][PS] Allow UniqueExternal linkage classes with dllexport/dllimport
MSVC allows instantiations of exported or imported template classes with template
parameters that have internal linkage. Clang now allows it in Microsoft mode and for
the Playstation platform. This partially addresses issue 56068.
Note that MSVC also allows explicit dllexport/dllimport attributes on classes
with internal linkage (e.g. local classes or classes declared in anonymous name spaces).
Clang continues to reject such declarations.
Reviewed By: hans
Differential Revision: https://reviews.llvm.org/D146338
Added:
clang/test/CodeGenCXX/dllexport-unique-external.cpp
clang/test/CodeGenCXX/dllimport-unique-external.cpp
Modified:
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/SemaCXX/dllexport.cpp
clang/test/SemaCXX/dllimport.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3dcc08f797811..e28c44f97f1fe 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -6351,6 +6351,18 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
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<DLLExportAttr>();
+ Class->dropAttr<DLLImportAttr>();
+ return;
+ }
+
if (!Class->isExternallyVisible()) {
Diag(Class->getLocation(), diag::err_attribute_dll_not_extern)
<< Class << ClassAttr;
diff --git a/clang/test/CodeGenCXX/dllexport-unique-external.cpp b/clang/test/CodeGenCXX/dllexport-unique-external.cpp
new file mode 100644
index 0000000000000..192438c6bfeba
--- /dev/null
+++ b/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 <typename T> 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> {};
+ LocalCRTP lc;
+ lc.func();
+}
+
+namespace {
+ class AnonNSCRTP : public ExportedClassTemplate<AnonNSCRTP> {};
+ AnonNSCRTP ac;
+}
+
+void func2() {
+ ac.func();
+}
+
+// MSC-NOT: declare {{.*}}dllexport
+// MSC: call {{.*}}@"?func@?$ExportedClassTemplate at VLocalCRTP@?1??func1@@{{.*}}"
+// MSC-NOT: declare {{.*}}dllexport
+// MSC: call {{.*}}@"?func@?$ExportedClassTemplate at 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
diff --git a/clang/test/CodeGenCXX/dllimport-unique-external.cpp b/clang/test/CodeGenCXX/dllimport-unique-external.cpp
new file mode 100644
index 0000000000000..8c0d5d37dfe8f
--- /dev/null
+++ b/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 <typename T> 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> {};
+ LocalCRTP lc;
+ lc.func();
+}
+
+namespace {
+ class AnonNSCRTP : public ImportedClassTemplate<AnonNSCRTP> {};
+ AnonNSCRTP ac;
+}
+
+void func2() {
+ ac.func();
+}
+
+// MSC-NOT: declare {{.*}}dllimport
+// MSC: call {{.*}}@"?func@?$ImportedClassTemplate at VLocalCRTP@?1??func1{{.*}}"
+// MSC-NOT: declare {{.*}}dllimport
+// MSC: call {{.*}}@"?func@?$ImportedClassTemplate at 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
diff --git a/clang/test/SemaCXX/dllexport.cpp b/clang/test/SemaCXX/dllexport.cpp
index 8035ea5b61a7f..22d92c30954e8 100644
--- a/clang/test/SemaCXX/dllexport.cpp
+++ b/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) ClassDecl;
class __declspec(dllexport) ClassDef {};
-#if defined(MS) || defined (WI)
+#if defined(MS) || defined (WI) || defined(PS)
// expected-warning at +3{{'dllexport' attribute ignored}}
#endif
template <typename T> struct PartiallySpecializedClassTemplate {};
@@ -371,13 +371,13 @@ ImplicitlyInstantiatedExportedTemplate<IncompleteType> implicitlyInstantiatedExp
// 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 at +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 at +2{{explicit instantiation declaration should not be 'dllexport'}}
#endif
extern template struct ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>;
@@ -412,13 +412,13 @@ struct __declspec(dllexport) ExportedBaseClass2 : public ExportedBaseClassTempla
// 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 at +2{{explicit instantiation declaration should not be 'dllexport'}} expected-note at +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 at -2{{attribute is here}}
// expected-warning at +2{{explicit instantiation declaration should not be 'dllexport'}}
#endif
@@ -434,7 +434,13 @@ void PR23308::f(InternalLinkageType*) {} // No error; we don't try to export f b
// 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 at +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 {};
@@ -457,7 +463,7 @@ template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func()
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 at +2{{'dllexport' attribute ignored on explicit instantiation definition}}
#endif
template struct __declspec(dllexport) ExplicitlyExportDeclaredInstantiatedTemplate<int>;
@@ -516,6 +522,15 @@ template <typename T> struct ExplicitInstantiationDeclTemplateBase { void func()
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 at +2{{in instantiation of template class 'ExportedClassTemplate<LocalCRTP>' requested here}}
+#endif
+ class LocalCRTP : public ExportedClassTemplate<LocalCRTP> {};
+}
//===----------------------------------------------------------------------===//
// Precedence
@@ -1180,7 +1195,7 @@ template<typename T> template<typename U> __declspec(dllexport) constexpr int CT
// 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 at +2{{lambda cannot be declared 'dllexport'}}
#endif
auto Lambda = []() __declspec(dllexport) -> bool { return true; };
diff --git a/clang/test/SemaCXX/dllimport.cpp b/clang/test/SemaCXX/dllimport.cpp
index a48d3786e1d8a..996e92f611d3f 100644
--- a/clang/test/SemaCXX/dllimport.cpp
+++ b/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 @@ int __declspec(dllimport) GlobalInit2 = 1; // expected-error{{definition of dlli
// expected-note at +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 at +4{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -71,7 +71,7 @@ int ExternGlobalDeclInit = 1;
// expected-note at +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 at +4{{'GlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -82,7 +82,7 @@ int GlobalDeclInit = 1;
// expected-note at +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 at +4{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -93,7 +93,7 @@ int *GlobalDeclChunkAttrInit = 0;
// expected-note at +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 at +4{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -184,7 +184,7 @@ template<typename T> int __declspec(dllimport) VarTmplInit2 = 1; // expected-err
#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 at +5{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +3{{'ExternVarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -197,7 +197,7 @@ int ExternVarTmplDeclInit = 1;
#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 at +5{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +3{{'VarTmplDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -312,7 +312,7 @@ __declspec(dllimport) void redecl2(); // expected-note{{previous declaration is
#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 at +4{{'redecl3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -327,7 +327,7 @@ extern "C" {
__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 @@ struct FuncFriend {
#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 at +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 at +4{{'friend3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +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 @@ namespace ns { __declspec(dllimport) void externalFunc(); }
// 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<typename T> __declspec(dllimport) void funcTmplFriend1();
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 at +2{{'funcTmplFriend5' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
#endif
template<typename T> inline void funcTmplFriend5() {}
@@ -598,13 +598,13 @@ struct ImportMembers {
__declspec(dllimport) constexpr static int ConstexprFieldDef = 1;
};
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
// expected-warning at +4{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +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 at +4{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -615,7 +615,7 @@ void ImportMembers::normalDef() {}
#endif
inline void ImportMembers::normalInlineDef() {}
void ImportMembers::normalInlineDecl() {}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
// expected-warning at +4{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -626,7 +626,7 @@ inline void ImportMembers::normalInlineDef() {}
#endif
inline void ImportMembers::virtualInlineDef() {}
void ImportMembers::virtualInlineDecl() {}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
// expected-warning at +4{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -699,7 +699,7 @@ struct ImportSpecials {
// 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 @@ struct ImportDefaultedDefs {
// 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 at +5{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +3{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -789,7 +789,7 @@ __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs(const ImportDefau
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 at +4{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +2{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -805,7 +805,7 @@ struct MemberRedecl {
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 at +4{{previous declaration is here}}
// expected-note at +4{{previous declaration is here}}
// expected-note at +4{{previous declaration is here}}
@@ -829,7 +829,7 @@ __declspec(dllimport) void MemberRedecl::staticDef() {} // expect
// expected-error at -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 @@ __declspec(dllimport) constexpr int MemberRedecl::ConstexprField;
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 at +2{{previous declaration is here}} expected-note at +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 at +2{{previous declaration is here}} expected-note at +2{{previous attribute is here}}
#endif
template<typename T> __declspec(dllimport) static void staticInlineDef();
@@ -935,7 +935,7 @@ struct MemTmplRedecl {
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 at +3{{previous declaration is here}}
// expected-note at +3{{previous declaration is here}}
#endif
@@ -953,7 +953,7 @@ struct MemTmplRedecl {
template<typename T> __declspec(dllimport) void MemTmplRedecl::normalDef() {} // expected-error{{redeclaration of 'MemTmplRedecl::normalDef' cannot add 'dllimport' attribute}}
// expected-error at -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}}
@@ -961,7 +961,7 @@ template<typename T> __declspec(dllimport) inline void MemTmplRedecl::normalInli
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 at -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}}
@@ -1197,7 +1197,7 @@ struct ImportClassTmplMembers {
// 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 at +5{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +3{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -1209,7 +1209,7 @@ void ImportClassTmplMembers<T>::normalDef() {}
#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 at +5{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +3{{'ImportClassTmplMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -1221,7 +1221,7 @@ void ImportClassTmplMembers<T>::virtualDef() {}
#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 at +5{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
#else
// expected-warning at +3{{'ImportClassTmplMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -1252,7 +1252,7 @@ struct CTMR /*ClassTmplMemberRedecl*/ {
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 at +4{{previous declaration is here}}
// expected-note at +4{{previous declaration is here}}
// expected-note at +4{{previous declaration is here}}
@@ -1276,7 +1276,7 @@ template<typename T> __declspec(dllimport) void CTMR<T>::staticDef() {}
// expected-error at -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}}
@@ -1340,13 +1340,13 @@ template<typename T>
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 at +2{{previous declaration is here}} expected-note at +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 at +2{{previous declaration is here}} expected-note at +2{{previous attribute is here}}
#endif
template<typename U> __declspec(dllimport) static void staticInlineDef();
@@ -1358,12 +1358,12 @@ struct ImportClsTmplMemTmpl {
// expected-warning at +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 at +2{{previous declaration is here}} expected-note at +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 at +2{{previous declaration is here}} expected-note at +2{{previous attribute is here}}
#endif
template<typename U> __declspec(dllimport) static inline void staticInlineDecl();
@@ -1417,7 +1417,7 @@ struct CTMTR /*ClassTmplMemberTmplRedecl*/ {
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 at +3{{previous declaration is here}}
// expected-note at +3{{previous declaration is here}}
#endif
@@ -1440,7 +1440,7 @@ template<typename T> template<typename U> __declspec(dllimport) void CTMT
// expected-error at -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
@@ -1477,7 +1477,7 @@ class __declspec(dllimport) ClassDef { };
template <typename T> class ClassTemplate {};
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
// expected-note at +5{{previous attribute is here}}
// expected-note at +4{{previous attribute is here}}
// expected-error at +4{{attribute 'dllexport' cannot be applied to member of 'dllimport' class}}
@@ -1488,7 +1488,7 @@ class __declspec(dllimport) ImportClassWithDllMember {
void __declspec(dllimport) bar();
};
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
// expected-note at +5{{previous attribute is here}}
// expected-note at +4{{previous attribute is here}}
// expected-error at +4{{attribute 'dllimport' cannot be applied to member of 'dllexport' class}}
@@ -1514,7 +1514,7 @@ template <typename> struct __declspec(dllimport) S {
S<int> s;
}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
// expected-warning at +3{{'dllimport' attribute ignored}}
#endif
template <typename T> struct PartiallySpecializedClassTemplate {};
@@ -1528,8 +1528,14 @@ template <> struct __declspec(dllimport) ExpliciallySpecializedClassTemplate<int
// 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 at +2{{'ImportedClassTemplate<LocalCRTP>' must have external linkage when declared 'dllimport'}}
+#endif
template <typename T> class __declspec(dllimport) ImportedClassTemplate {};
// ClassTemplate<int> gets imported.
@@ -1604,11 +1610,21 @@ template <typename T> struct ExplicitInstantiationDeclTemplateBase { void func()
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 at +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 at +4{{lambda cannot be declared 'dllimport'}}
#else
// expected-warning at +2{{'dllimport' attribute ignored on inline function}}
More information about the cfe-commits
mailing list