Index: clang/include/clang/Basic/TargetInfo.h =================================================================== --- clang/include/clang/Basic/TargetInfo.h +++ clang/include/clang/Basic/TargetInfo.h @@ -1092,6 +1092,13 @@ /// either; the entire thing is pretty badly mangled. virtual bool hasProtectedVisibility() const { return true; } + /// Does this target aim for semantic compatibility with + /// Microsoft C++ code using dllimport/export attributes? + virtual bool shouldDLLImportComdatSymbols() const { + return getTriple().isWindowsMSVCEnvironment() || + getTriple().isWindowsItaniumEnvironment() || getTriple().isPS4CPU(); + } + /// An optional hook that targets can implement to perform semantic /// checking on attribute((section("foo"))) specifiers. /// Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -6510,9 +6510,7 @@ // special MSVC extension: in the last case, the declaration is treated as if // it were marked dllexport. bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false; - bool IsMicrosoft = - S.Context.getTargetInfo().getCXXABI().isMicrosoft() || - S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment(); + bool IsMicrosoft = S.Context.getTargetInfo().shouldDLLImportComdatSymbols(); if (const auto *VD = dyn_cast(NewDecl)) { // Ignore static data because out-of-line definitions are diagnosed // separately. Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -6775,16 +6775,14 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (isa(D) && - (S.Context.getTargetInfo().getCXXABI().isMicrosoft() || - S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) { + (S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) { S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) << A; return; } if (const auto *FD = dyn_cast(D)) { if (FD->isInlined() && A.getKind() == ParsedAttr::AT_DLLImport && - !(S.Context.getTargetInfo().getCXXABI().isMicrosoft() || - S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) { + !(S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) { // MinGW doesn't allow dllimport on inline functions. S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline) << A; @@ -6793,8 +6791,7 @@ } if (const auto *MD = dyn_cast(D)) { - if ((S.Context.getTargetInfo().getCXXABI().isMicrosoft() || - S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) && + if ((S.Context.getTargetInfo().shouldDLLImportComdatSymbols()) && MD->getParent()->isLambda()) { S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A; return; Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -6082,8 +6082,7 @@ Attr *ClassAttr = getDLLAttr(Class); // MSVC inherits DLL attributes to partial class template specializations. - if ((Context.getTargetInfo().getCXXABI().isMicrosoft() || - Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) && !ClassAttr) { + if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr) { if (auto *Spec = dyn_cast(Class)) { if (Attr *TemplateAttr = getDLLAttr(Spec->getSpecializedTemplate()->getTemplatedDecl())) { @@ -6103,8 +6102,7 @@ return; } - if ((Context.getTargetInfo().getCXXABI().isMicrosoft() || - Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) && + if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr->isInherited()) { // Diagnose dll attributes on members of class with dll attribute. for (Decl *Member : Class->decls()) { @@ -6169,8 +6167,7 @@ if (MD->isInlined()) { // MinGW does not import or export inline methods. But do it for // template instantiations. - if (!Context.getTargetInfo().getCXXABI().isMicrosoft() && - !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() && + if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() && TSK != TSK_ExplicitInstantiationDeclaration && TSK != TSK_ExplicitInstantiationDefinition) continue; Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -9759,8 +9759,8 @@ Def->setTemplateSpecializationKind(TSK); if (!getDLLAttr(Def) && getDLLAttr(Specialization) && - (Context.getTargetInfo().getCXXABI().isMicrosoft() || - Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) { + (Context.getTargetInfo().shouldDLLImportComdatSymbols() && + !Context.getTargetInfo().getTriple().isPS4CPU())) { // In the MS ABI, an explicit instantiation definition can add a dll // attribute to a template with a previous instantiation declaration. // MinGW doesn't allow this. @@ -9777,8 +9777,8 @@ bool NewlyDLLExported = !PreviouslyDLLExported && Specialization->hasAttr(); if (Old_TSK == TSK_ImplicitInstantiation && NewlyDLLExported && - (Context.getTargetInfo().getCXXABI().isMicrosoft() || - Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) { + (Context.getTargetInfo().shouldDLLImportComdatSymbols() && + !Context.getTargetInfo().getTriple().isPS4CPU())) { // In the MS ABI, an explicit instantiation definition can add a dll // attribute to a template with a previous implicit instantiation. // MinGW doesn't allow this. We limit clang to only adding dllexport, to Index: clang/test/CodeGenCXX/dllexport-vtable-thunks.cpp =================================================================== --- clang/test/CodeGenCXX/dllexport-vtable-thunks.cpp +++ clang/test/CodeGenCXX/dllexport-vtable-thunks.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-windows-gnu -fdeclspec -emit-llvm -o - %s | FileCheck %s -// RUN: %clang_cc1 -triple x86_64-windows-itanium -fdeclspec -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-windows-gnu -fdeclspec -emit-llvm -o - %s | FileCheck %s -DDSO_ATTRS="dso_local dllexport" +// RUN: %clang_cc1 -triple x86_64-windows-itanium -fdeclspec -emit-llvm -o - %s | FileCheck %s -DDSO_ATTRS="dso_local dllexport" +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fdeclspec -emit-llvm -o - %s | FileCheck %s -DDSO_ATTRS=dllexport struct __declspec(dllexport) A { virtual void m(); @@ -11,7 +12,7 @@ virtual void m(); }; void C::m() {} -// CHECK: define dso_local dllexport void @_ZThn8_N1C1mEv +// CHECK: define [[DSO_ATTRS]] void @_ZThn8_N1C1mEv struct Base { virtual void m(); @@ -20,4 +21,4 @@ virtual void m(); }; void Derived::m() {} -// CHECK: define dso_local dllexport void @_ZTv0_n24_N7Derived1mEv +// CHECK: define [[DSO_ATTRS]] void @_ZTv0_n24_N7Derived1mEv Index: clang/test/CodeGenCXX/windows-implicit-dllexport-template-specialization.cpp =================================================================== --- clang/test/CodeGenCXX/windows-implicit-dllexport-template-specialization.cpp +++ clang/test/CodeGenCXX/windows-implicit-dllexport-template-specialization.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -std=c++11 -triple i686-windows -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MS +// RUN: %clang_cc1 -std=c++11 -triple i686-windows -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MS // RUN: %clang_cc1 -std=c++11 -triple i686-windows-itanium -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-IA +// RUN: %clang_cc1 -std=c++11 -triple x86_64-scei-ps4 -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-PS4 template struct s {}; @@ -16,3 +17,5 @@ // CHECK-IA: dllexport {{.*}} @_ZN1tIcEaSERKS0_ // CHECK-IA: dllexport {{.*}} @_ZN1sIcEaSERKS0_ +// CHECK-PS4-NOT: @_ZN1tIcEaSERKS0_ +// CHECK-PS4-NOT: @_ZN1sIcEaSERKS0_ Index: clang/test/CodeGenCXX/windows-itanium-dllexport.cpp =================================================================== --- clang/test/CodeGenCXX/windows-itanium-dllexport.cpp +++ clang/test/CodeGenCXX/windows-itanium-dllexport.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -emit-llvm -triple i686-windows-itanium -fdeclspec %s -o - | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -triple i686-windows-itanium -fdeclspec %s -o - | FileCheck %s --check-prefixes=CHECK,WI +// RUN: %clang_cc1 -emit-llvm -triple x86_64-scei-ps4 -fdeclspec %s -o - | FileCheck %s --check-prefixes=CHECK,PS4 #define JOIN2(x, y) x##y #define JOIN(x, y) JOIN2(x, y) @@ -25,14 +26,18 @@ extern template class c; template class __declspec(dllexport) c; -// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcEaSERKS0_ -// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv +// WI: define {{.*}} dllexport {{.*}} @_ZN1cIcEaSERKS0_ +// WI: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv +// PS4-NOT: @_ZN1cIcEaSERKS0_ +// PS4: define weak_odr void @_ZN1cIcE1fEv c g; template class __declspec(dllexport) c; -// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_ -// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv +// WI: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_ +// WI: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv +// PS4-NOT: @_ZN1cIdEaSERKS0_ +// PS4: define weak_odr void @_ZN1cIdE1fEv template struct outer { @@ -51,5 +56,6 @@ USEMEMFUNC(outer, f) USEMEMFUNC(outer::inner, f) -// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv -// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv +// CHECK-DAG: declare dllimport {{.*}} @_ZN5outerIcE1fEv +// WI-DAG: define {{.*}} @_ZN5outerIcE5inner1fEv +// PS4-DAG: declare {{.*}} @_ZN5outerIcE5inner1fEv Index: clang/test/Sema/dllimport.c =================================================================== --- clang/test/Sema/dllimport.c +++ clang/test/Sema/dllimport.c @@ -5,6 +5,8 @@ // RUN: %clang_cc1 -triple aarch64-win32 -fsyntax-only -fms-extensions -verify -std=c99 -DMS %s // RUN: %clang_cc1 -triple i686-windows-itanium -fsyntax-only -fms-extensions -verify -std=c99 -DWI %s // RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c11 -DWI %s +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fms-extensions -verify -std=c11 -DWI %s +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fms-extensions -verify -std=c99 -DWI %s // Invalid usage. __declspec(dllimport) typedef int typedef1; Index: clang/test/SemaCXX/dllexport.cpp =================================================================== --- clang/test/SemaCXX/dllexport.cpp +++ clang/test/SemaCXX/dllexport.cpp @@ -4,6 +4,7 @@ // RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template %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++1y -Wunsupported-dll-base-class-template -DWI %s // Helper structs to make templates more expressive. struct ImplicitInst_Exported {}; Index: clang/test/SemaCXX/dllimport.cpp =================================================================== --- clang/test/SemaCXX/dllimport.cpp +++ clang/test/SemaCXX/dllimport.cpp @@ -5,6 +5,8 @@ // 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 %s +// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI %s // Helper structs to make templates more expressive. struct ImplicitInst_Imported {};