wolfgangp created this revision.
wolfgangp added reviewers: hans, probinson, mstorsjo.
Herald added a project: All.
wolfgangp requested review of this revision.

This replaces D145271 <https://reviews.llvm.org/D145271>.

Rather than coercing classes with UniqueExternalLInkage to ExternalLinkage as 
proposed in D145271 <https://reviews.llvm.org/D145271>, this patch suggests to 
simply allow the dllexport/dllimport attributes for classes that exhibit 
UniqueExternalLinkage, which includes instantiations of template classes where 
the template parameters are local classes or classes in anonymous namespaces:

  template <typename T>
  class __declspec(dllimport) A {};
  
  void func()
  {
    class B : public A<B> {};
  }
  
  namespace {
    class C : public A<C> {};
  }

In D145271 <https://reviews.llvm.org/D145271> it was suggested that we drop the 
attribute in such contexts, and this is effectively what happens. The compiler 
does not produce any exported definitions (or import any symbols) for such 
classes. The patch is simply to suppress the diagnostic for MSVC mode and 
Playstation.

I have not changed the behavior of the Windows/Itanium triple since I wasn't 
sure if this was desirable.


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
@@ -6348,9 +6348,13 @@
     return;
 
   if (!Class->isExternallyVisible()) {
-    Diag(Class->getLocation(), diag::err_attribute_dll_not_extern)
-        << Class << ClassAttr;
-    return;
+    if (!(Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+          Context.getTargetInfo().getTriple().isPS()) ||
+        !Class->hasExternalFormalLinkage()) {
+      Diag(Class->getLocation(), diag::err_attribute_dll_not_extern)
+          << Class << ClassAttr;
+      return;
+    }
   }
 
   if (Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to