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@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

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@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

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@+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@+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>;
@@ -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@+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
@@ -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@+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@+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@+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@+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@+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 @@ int ExternGlobalDeclInit = 1;
 // 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 @@ int GlobalDeclInit = 1;
 // 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 @@ int *GlobalDeclChunkAttrInit = 0;
 // 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 @@ 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@+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 @@ 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@+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 @@ __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@+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 @@ 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@+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 @@ 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@+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@+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 @@ 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@+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 @@ 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@+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 @@ 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@+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 @@ __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@+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 @@ 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@+4{{previous declaration is here}}
   // expected-note@+4{{previous declaration is here}}
   // expected-note@+4{{previous declaration is here}}
@@ -829,7 +829,7 @@ __declspec(dllimport)        void MemberRedecl::staticDef() 
{}         // expect
                                                                        // 
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 @@ __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@+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();
@@ -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@+3{{previous declaration is here}}
 // expected-note@+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@-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@-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@+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 @@ 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@+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 @@ 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@+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 @@ 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@+4{{previous declaration is here}}
 // expected-note@+4{{previous declaration is here}}
 // expected-note@+4{{previous declaration is here}}
@@ -1276,7 +1276,7 @@ template<typename T> __declspec(dllimport)        void 
CTMR<T>::staticDef() {}
                                                                                
        // 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}}
@@ -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@+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();
@@ -1358,12 +1358,12 @@ struct ImportClsTmplMemTmpl {
   // 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();
@@ -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@+3{{previous declaration is here}}
   // expected-note@+3{{previous declaration is here}}
 #endif
@@ -1440,7 +1440,7 @@ template<typename T> template<typename U> 
__declspec(dllimport)        void CTMT
                                                                                
                              // 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
@@ -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@+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 @@ class __declspec(dllimport) ImportClassWithDllMember {
   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 @@ template <typename> struct __declspec(dllimport) S {
 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 {};
@@ -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@+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@+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}}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to