wolfgangp updated this revision to Diff 507428.
wolfgangp added a comment.

Instead of suppressing the error message we drop the dllimport/dllexport 
attribute when we see that a class has UniqueExternal linkage. This will 
suppress exporting or importing any members, which could not be accessed 
outside the TU anyway.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146338/new/

https://reviews.llvm.org/D146338

Files:
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/dllexport.cpp
  clang/test/SemaCXX/dllimport.cpp

Index: clang/test/SemaCXX/dllimport.cpp
===================================================================
--- clang/test/SemaCXX/dllimport.cpp
+++ clang/test/SemaCXX/dllimport.cpp
@@ -5,9 +5,9 @@
 // RUN: %clang_cc1 -triple x86_64-mingw32         -fsyntax-only -fms-extensions -verify -std=c++17 -Wunsupported-dll-base-class-template -DGNU %s
 // RUN: %clang_cc1 -triple i686-windows-itanium   -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI %s
 // RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI %s
-// RUN: %clang_cc1 -triple x86_64-scei-ps4        -fsyntax-only -fdeclspec      -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI -DPS %s
-// RUN: %clang_cc1 -triple x86_64-scei-ps4        -fsyntax-only -fdeclspec      -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI -DPS %s
-// RUN: %clang_cc1 -triple x86_64-sie-ps5         -fsyntax-only -fdeclspec      -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI -DPS %s
+// RUN: %clang_cc1 -triple x86_64-scei-ps4        -fsyntax-only -fdeclspec      -verify -std=c++11 -Wunsupported-dll-base-class-template -DPS %s
+// RUN: %clang_cc1 -triple x86_64-scei-ps4        -fsyntax-only -fdeclspec      -verify -std=c++17 -Wunsupported-dll-base-class-template -DPS %s
+// RUN: %clang_cc1 -triple x86_64-sie-ps5         -fsyntax-only -fdeclspec      -verify -std=c++17 -Wunsupported-dll-base-class-template -DPS %s
 
 // Helper structs to make templates more expressive.
 struct ImplicitInst_Imported {};
@@ -60,7 +60,7 @@
 // expected-note@+2{{previous attribute is here}}
 #endif
 __declspec(dllimport) extern int ExternGlobalDeclInit; // expected-note{{previous declaration is here}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+4{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
 // expected-warning@+2{{'ExternGlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -71,7 +71,7 @@
 // expected-note@+2{{previous attribute is here}}
 #endif
 __declspec(dllimport) int GlobalDeclInit; // expected-note{{previous declaration is here}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+4{{'GlobalDeclInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
 // expected-warning@+2{{'GlobalDeclInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -82,7 +82,7 @@
 // expected-note@+2{{previous attribute is here}}
 #endif
 int *__attribute__((dllimport)) GlobalDeclChunkAttrInit; // expected-note{{previous declaration is here}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+4{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
 // expected-warning@+2{{'GlobalDeclChunkAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -93,7 +93,7 @@
 // expected-note@+2{{previous attribute is here}}
 #endif
 int GlobalDeclAttrInit __attribute__((dllimport)); // expected-note{{previous declaration is here}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+4{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
 // expected-warning@+2{{'GlobalDeclAttrInit' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -184,7 +184,7 @@
 #endif
 template <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 @@
 #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 @@
 #endif
                       __declspec(dllimport) void redecl3(); // expected-note{{previous declaration is here}}
                       // NB: Both MSVC and Clang issue a warning and make redecl3 dllexport.
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
                       // expected-warning@+4{{'redecl3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
                       // expected-warning@+2{{'redecl3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -327,7 +327,7 @@
 __declspec(dllimport) void redecl5(); // expected-warning{{redeclaration of 'redecl5' should not add 'dllimport' attribute}}
 }
 
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
                       void redecl6(); // expected-note{{previous declaration is here}}
 __declspec(dllimport) inline void redecl6() {} // expected-warning{{redeclaration of 'redecl6' should not add 'dllimport' attribute}}
 #else
@@ -344,21 +344,21 @@
 #endif
   friend __declspec(dllimport) void friend3(); // expected-note{{previous declaration is here}}
   friend                       void friend4(); // expected-note{{previous declaration is here}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-note@+2{{previous declaration is here}}
 #endif
   friend                       void friend5();
 };
 __declspec(dllimport) void friend1();
                       void friend2(); // expected-warning{{'friend2' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
                       // expected-warning@+4{{'friend3' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
                       // expected-warning@+2{{'friend3' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
 #endif
                       void friend3() {}
 __declspec(dllimport) void friend4(); // expected-warning{{redeclaration of 'friend4' should not add 'dllimport' attribute}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 __declspec(dllimport) inline void friend5() {} // expected-warning{{redeclaration of 'friend5' should not add 'dllimport' attribute}}
 #else
 __declspec(dllimport) inline void friend5() {} // expected-warning{{'dllimport' attribute ignored on inline function}}
@@ -386,7 +386,7 @@
 // here which is irrelevant. But because the delete keyword is parsed later
 // there is currently no straight-forward way to avoid this diagnostic.
 __declspec(dllimport) void deletedFunc() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}} expected-error{{dllimport cannot be applied to non-inline function definition}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 __declspec(dllimport) inline void deletedInlineFunc() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
 #else
 __declspec(dllimport) inline void deletedInlineFunc() = delete; // expected-warning{{'dllimport' attribute ignored on inline function}}
@@ -464,7 +464,7 @@
 template<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 @@
   __declspec(dllimport) constexpr static int ConstexprFieldDef = 1;
 };
 
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+4{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
                                                                                  // expected-warning@+2{{'ImportMembers::Nested::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
 #endif
 void ImportMembers::Nested::normalDef() {}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+4{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
                                                                                  // expected-warning@+2{{'ImportMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -615,7 +615,7 @@
 #endif
 inline void ImportMembers::normalInlineDef() {}
        void ImportMembers::normalInlineDecl() {}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
        // expected-warning@+4{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
                                                                                  // expected-warning@+2{{'ImportMembers::virtualDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -626,7 +626,7 @@
 #endif
 inline void ImportMembers::virtualInlineDef() {}
        void ImportMembers::virtualInlineDecl() {}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
        // expected-warning@+4{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
                                                                                  // expected-warning@+2{{'ImportMembers::staticDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -699,7 +699,7 @@
 
 // Import deleted member functions.
 struct ImportDeleted {
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
   __declspec(dllimport) ImportDeleted() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
   __declspec(dllimport) ~ImportDeleted() = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
   __declspec(dllimport) ImportDeleted(const ImportDeleted&) = delete; // expected-error{{attribute 'dllimport' cannot be applied to a deleted function}}
@@ -772,7 +772,7 @@
 // Not allowed on definitions.
 __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs() = default; // expected-error{{dllimport cannot be applied to non-inline function definition}}
 
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+5{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
 // expected-warning@+3{{'ImportDefaultedDefs::~ImportDefaultedDefs' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -789,7 +789,7 @@
 inline ImportDefaultedDefs& ImportDefaultedDefs::operator=(const ImportDefaultedDefs&) = default;
 
 __declspec(dllimport) ImportDefaultedDefs::ImportDefaultedDefs(ImportDefaultedDefs&&) = default; // expected-error{{dllimport cannot be applied to non-inline function definition}}
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+4{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
 // expected-warning@+2{{'ImportDefaultedDefs::operator=' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -805,7 +805,7 @@
   static         void staticDef();         // expected-note{{previous declaration is here}}
   static  inline void staticInlineDecl();  // expected-note{{previous declaration is here}}
 
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
   // expected-note@+4{{previous declaration is here}}
   // expected-note@+4{{previous declaration is here}}
   // expected-note@+4{{previous declaration is here}}
@@ -829,7 +829,7 @@
                                                                        // expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
 __declspec(dllimport)        void MemberRedecl::staticInlineDecl() {}  // expected-error{{redeclaration of 'MemberRedecl::staticInlineDecl' cannot add 'dllimport' attribute}}
 
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 __declspec(dllimport) inline void MemberRedecl::normalInlineDef() {}   // expected-error{{redeclaration of 'MemberRedecl::normalInlineDef' cannot add 'dllimport' attribute}}
 __declspec(dllimport) inline void MemberRedecl::virtualInlineDef() {}  // expected-error{{redeclaration of 'MemberRedecl::virtualInlineDef' cannot add 'dllimport' attribute}}
 __declspec(dllimport) inline void MemberRedecl::staticInlineDef() {}   // expected-error{{redeclaration of 'MemberRedecl::staticInlineDef' cannot add 'dllimport' attribute}}
@@ -866,13 +866,13 @@
 struct ImportMemberTmpl {
   template<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 @@
   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 @@
 
 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)        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 @@
 
 // NB: MSVC is inconsistent here and disallows *InlineDef on class templates,
 // but allows it on classes. We allow both.
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-warning@+5{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: 'dllexport' attribute added}}
 #else
 // expected-warning@+3{{'ImportClassTmplMembers::normalDef' redeclared without 'dllimport' attribute: previous 'dllimport' ignored}}
@@ -1209,7 +1209,7 @@
 #endif
 template<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 @@
 #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 @@
   static         void staticDef();         // expected-note{{previous declaration is here}}
   static  inline void staticInlineDecl();  // expected-note{{previous declaration is here}}
 
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-note@+4{{previous declaration is here}}
 // expected-note@+4{{previous declaration is here}}
 // expected-note@+4{{previous declaration is here}}
@@ -1276,7 +1276,7 @@
                                                                                        // expected-error@-1{{dllimport cannot be applied to non-inline function definition}}
 template<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 @@
 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 @@
   // 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 @@
   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 @@
                                                                                                              // 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 @@
 
 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 @@
   void __declspec(dllimport) bar();
 };
 
-#if defined(MS) || defined(WI)
+#if defined(MS) || defined(WI) || defined(PS)
 // expected-note@+5{{previous attribute is here}}
 // expected-note@+4{{previous attribute is here}}
 // expected-error@+4{{attribute 'dllimport' cannot be applied to member of 'dllexport' class}}
@@ -1514,7 +1514,7 @@
 S<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,15 @@
 // Classes with template base classes
 //===----------------------------------------------------------------------===//
 
+class Base {};
+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 +1611,21 @@
 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}}
Index: clang/test/SemaCXX/dllexport.cpp
===================================================================
--- clang/test/SemaCXX/dllexport.cpp
+++ clang/test/SemaCXX/dllexport.cpp
@@ -4,8 +4,8 @@
 // RUN: %clang_cc1 -triple x86_64-mingw32         -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DGNU %s
 // RUN: %clang_cc1 -triple i686-windows-itanium   -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI  %s
 // RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++1y -Wunsupported-dll-base-class-template -DWI  %s
-// RUN: %clang_cc1 -triple x86_64-scei-ps4        -fsyntax-only -fdeclspec      -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI -DPS %s
-// RUN: %clang_cc1 -triple x86_64-sie-ps5         -fsyntax-only -fdeclspec      -verify -std=c++1y -Wunsupported-dll-base-class-template -DWI -DPS %s
+// RUN: %clang_cc1 -triple x86_64-scei-ps4        -fsyntax-only -fdeclspec      -verify -std=c++11 -Wunsupported-dll-base-class-template -DPS  %s
+// RUN: %clang_cc1 -triple x86_64-sie-ps5         -fsyntax-only -fdeclspec      -verify -std=c++1y -Wunsupported-dll-base-class-template -DPS  %s
 
 // Helper structs to make templates more expressive.
 struct ImplicitInst_Exported {};
@@ -353,7 +353,7 @@
 
 class __declspec(dllexport) ClassDef {};
 
-#if defined(MS) || defined (WI)
+#if defined(MS) || defined (WI) || defined(PS)
 // expected-warning@+3{{'dllexport' attribute ignored}}
 #endif
 template <typename T> struct PartiallySpecializedClassTemplate {};
@@ -371,13 +371,13 @@
 
 // Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported.
 struct IncompleteType2;
-#if defined(MS) || defined (WI)
+#if defined(MS) || defined (WI) || defined(PS)
 // expected-note@+2{{attribute is here}}
 #endif
 template <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 @@
 
 // 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,14 @@
 // Classes with template base classes
 //===----------------------------------------------------------------------===//
 
+class Base {};
+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 +464,7 @@
 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 +523,15 @@
 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 +1196,7 @@
 // Lambdas
 //===----------------------------------------------------------------------===//
 // The MS ABI doesn't provide a stable mangling for lambdas, so they can't be imported or exported.
-#if defined(MS) || defined (WI)
+#if defined(MS) || defined (WI) || defined(PS)
 // expected-error@+2{{lambda cannot be declared 'dllexport'}}
 #endif
 auto Lambda = []() __declspec(dllexport) -> bool { return true; };
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -6351,6 +6351,18 @@
   if (!ClassAttr)
     return;
 
+  // MSVC allows imported or exported template classes that have UniqueExternal
+  // linkage. This occurs when the template class has been instantiated with
+  // a template parameter which itself has internal linkage.
+  // We drop the attribute to avoid exporting or importing any members.
+  if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+       Context.getTargetInfo().getTriple().isPS()) &&
+      (!Class->isExternallyVisible() && Class->hasExternalFormalLinkage())) {
+    Class->dropAttr<DLLExportAttr>();
+    Class->dropAttr<DLLImportAttr>();
+    return;
+  }
+
   if (!Class->isExternallyVisible()) {
     Diag(Class->getLocation(), diag::err_attribute_dll_not_extern)
         << Class << ClassAttr;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to