/// 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.
///
// 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 IsMicrosoftABI = S.Context.getTargetInfo().shouldDLLImportComdatSymbols();
if (const auto *VD = dyn_cast<VarDecl>(NewDecl)) {
// Ignore static data because out-of-line definitions are diagnosed
// separately.
}
if (OldImportAttr && !HasNewAttr &&
- (!IsInline || (IsMicrosoft && IsTemplate)) && !IsStaticDataMember &&
+ (!IsInline || (IsMicrosoftABI && IsTemplate)) && !IsStaticDataMember &&
!NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
- if (IsMicrosoft && IsDefinition) {
+ if (IsMicrosoftABI && IsDefinition) {
S.Diag(NewDecl->getLocation(),
diag::warn_redeclaration_without_import_attribute)
<< NewDecl;
OldDecl->dropAttr<DLLImportAttr>();
NewDecl->dropAttr<DLLImportAttr>();
}
- } else if (IsInline && OldImportAttr && !IsMicrosoft) {
+ } else if (IsInline && OldImportAttr && !IsMicrosoftABI) {
// In MinGW, seeing a function declared inline drops the dllimport
// attribute.
OldDecl->dropAttr<DLLImportAttr>();
static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
if (isa<ClassTemplatePartialSpecializationDecl>(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<FunctionDecl>(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;
}
if (const auto *MD = dyn_cast<CXXMethodDecl>(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;
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<ClassTemplatePartialSpecializationDecl>(Class)) {
if (Attr *TemplateAttr =
getDLLAttr(Spec->getSpecializedTemplate()->getTemplatedDecl())) {
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()) {
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;
Def->setTemplateSpecializationKind(TSK);
if (!getDLLAttr(Def) && getDLLAttr(Specialization) &&
- (Context.getTargetInfo().getCXXABI().isMicrosoft() ||
- Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) {
- // 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.
+ (Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
+ !Context.getTargetInfo().getTriple().isPS4CPU())) {
+ // An explicit instantiation definition can add a dll attribute to a
+ // template with a previous instantiation declaration. MinGW doesn't
+ // allow this.
auto *A = cast<InheritableAttr>(
getDLLAttr(Specialization)->clone(getASTContext()));
A->setInherited(true);
bool NewlyDLLExported =
!PreviouslyDLLExported && Specialization->hasAttr<DLLExportAttr>();
if (Old_TSK == TSK_ImplicitInstantiation && NewlyDLLExported &&
- (Context.getTargetInfo().getCXXABI().isMicrosoft() ||
- Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) {
- // 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
- // avoid potentially strange codegen behavior. For example, if we extend
- // this conditional to dllimport, and we have a source file calling a
- // method on an implicitly instantiated template class instance and then
- // declaring a dllimport explicit instantiation definition for the same
- // template class, the codegen for the method call will not respect the
- // dllimport, while it will with cl. The Def will already have the DLL
- // attribute, since the Def and Specialization will be the same in the
- // case of Old_TSK == TSK_ImplicitInstantiation, and we already added the
+ (Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
+ !Context.getTargetInfo().getTriple().isPS4CPU())) {
+ // 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 avoid potentially
+ // strange codegen behavior. For example, if we extend this conditional
+ // to dllimport, and we have a source file calling a method on an
+ // implicitly instantiated template class instance and then declaring a
+ // dllimport explicit instantiation definition for the same template
+ // class, the codegen for the method call will not respect the dllimport,
+ // while it will with cl. The Def will already have the DLL attribute,
+ // since the Def and Specialization will be the same in the case of
+ // Old_TSK == TSK_ImplicitInstantiation, and we already added the
// attribute to the Specialization; we just need to make it take effect.
assert(Def == Specialization &&
"Def and Specialization should match for implicit instantiation");
-// 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();
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();
virtual void m();
};
void Derived::m() {}
-// CHECK: define dso_local dllexport void @_ZTv0_n24_N7Derived1mEv
+// CHECK: define [[DSO_ATTRS]] void @_ZTv0_n24_N7Derived1mEv
-// 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 <typename>
struct s {};
// CHECK-IA: dllexport {{.*}} @_ZN1tIcEaSERKS0_
// CHECK-IA: dllexport {{.*}} @_ZN1sIcEaSERKS0_
+// CHECK-PS4-NOT: @_ZN1tIcEaSERKS0_
+// CHECK-PS4-NOT: @_ZN1sIcEaSERKS0_
-// 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)
extern template class c<char>;
template class __declspec(dllexport) c<char>;
-// 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<double> g;
template class __declspec(dllexport) c<double>;
-// 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 <class T>
struct outer {
USEMEMFUNC(outer<char>, f)
USEMEMFUNC(outer<char>::inner, f)
-// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv
-// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv
+// CHECK-DAG: declare dllimport {{.*}} @_ZN5outerIcE1fEv
+// WI-DAG: define {{.*}} @_ZN5outerIcE5inner1fEv
+// PS4-DAG: declare {{.*}} @_ZN5outerIcE5inner1fEv
// 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;
// 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 {};
// 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 {};