Skip to content

Commit d5aaf60

Browse files
committed
[windows-itanium] handle dllimport/export code paths separately and share with PS4
Similar to Windows Itanium, PS4 is also an Itanium C++ ABI variant which shares the goal of semantic compatibility with Microsoft C++ code that uses dllimport/export. This change introduces a new function to determine from the triple if an environment aims for compatibility with MS C++ code w.r.t to these attributes and guards the relevant code paths using that function. Differential Revision: https://reviews.llvm.org/D90299
1 parent c0e4020 commit d5aaf60

File tree

11 files changed

+62
-48
lines changed

11 files changed

+62
-48
lines changed

clang/include/clang/Basic/TargetInfo.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,13 @@ class TargetInfo : public virtual TransferrableTargetInfo,
10981098
/// either; the entire thing is pretty badly mangled.
10991099
virtual bool hasProtectedVisibility() const { return true; }
11001100

1101+
/// Does this target aim for semantic compatibility with
1102+
/// Microsoft C++ code using dllimport/export attributes?
1103+
virtual bool shouldDLLImportComdatSymbols() const {
1104+
return getTriple().isWindowsMSVCEnvironment() ||
1105+
getTriple().isWindowsItaniumEnvironment() || getTriple().isPS4CPU();
1106+
}
1107+
11011108
/// An optional hook that targets can implement to perform semantic
11021109
/// checking on attribute((section("foo"))) specifiers.
11031110
///

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6510,9 +6510,7 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
65106510
// special MSVC extension: in the last case, the declaration is treated as if
65116511
// it were marked dllexport.
65126512
bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false;
6513-
bool IsMicrosoft =
6514-
S.Context.getTargetInfo().getCXXABI().isMicrosoft() ||
6515-
S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment();
6513+
bool IsMicrosoftABI = S.Context.getTargetInfo().shouldDLLImportComdatSymbols();
65166514
if (const auto *VD = dyn_cast<VarDecl>(NewDecl)) {
65176515
// Ignore static data because out-of-line definitions are diagnosed
65186516
// separately.
@@ -6526,9 +6524,9 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
65266524
}
65276525

65286526
if (OldImportAttr && !HasNewAttr &&
6529-
(!IsInline || (IsMicrosoft && IsTemplate)) && !IsStaticDataMember &&
6527+
(!IsInline || (IsMicrosoftABI && IsTemplate)) && !IsStaticDataMember &&
65306528
!NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
6531-
if (IsMicrosoft && IsDefinition) {
6529+
if (IsMicrosoftABI && IsDefinition) {
65326530
S.Diag(NewDecl->getLocation(),
65336531
diag::warn_redeclaration_without_import_attribute)
65346532
<< NewDecl;
@@ -6545,7 +6543,7 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
65456543
OldDecl->dropAttr<DLLImportAttr>();
65466544
NewDecl->dropAttr<DLLImportAttr>();
65476545
}
6548-
} else if (IsInline && OldImportAttr && !IsMicrosoft) {
6546+
} else if (IsInline && OldImportAttr && !IsMicrosoftABI) {
65496547
// In MinGW, seeing a function declared inline drops the dllimport
65506548
// attribute.
65516549
OldDecl->dropAttr<DLLImportAttr>();

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6791,16 +6791,14 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D,
67916791

67926792
static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
67936793
if (isa<ClassTemplatePartialSpecializationDecl>(D) &&
6794-
(S.Context.getTargetInfo().getCXXABI().isMicrosoft() ||
6795-
S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) {
6794+
(S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) {
67966795
S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) << A;
67976796
return;
67986797
}
67996798

68006799
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
68016800
if (FD->isInlined() && A.getKind() == ParsedAttr::AT_DLLImport &&
6802-
!(S.Context.getTargetInfo().getCXXABI().isMicrosoft() ||
6803-
S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) {
6801+
!(S.Context.getTargetInfo().shouldDLLImportComdatSymbols())) {
68046802
// MinGW doesn't allow dllimport on inline functions.
68056803
S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline)
68066804
<< A;
@@ -6809,8 +6807,7 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
68096807
}
68106808

68116809
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
6812-
if ((S.Context.getTargetInfo().getCXXABI().isMicrosoft() ||
6813-
S.Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
6810+
if ((S.Context.getTargetInfo().shouldDLLImportComdatSymbols()) &&
68146811
MD->getParent()->isLambda()) {
68156812
S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A;
68166813
return;

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6092,8 +6092,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
60926092
Attr *ClassAttr = getDLLAttr(Class);
60936093

60946094
// MSVC inherits DLL attributes to partial class template specializations.
6095-
if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
6096-
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) && !ClassAttr) {
6095+
if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr) {
60976096
if (auto *Spec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Class)) {
60986097
if (Attr *TemplateAttr =
60996098
getDLLAttr(Spec->getSpecializedTemplate()->getTemplatedDecl())) {
@@ -6113,8 +6112,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
61136112
return;
61146113
}
61156114

6116-
if ((Context.getTargetInfo().getCXXABI().isMicrosoft() ||
6117-
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) &&
6115+
if (Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
61186116
!ClassAttr->isInherited()) {
61196117
// Diagnose dll attributes on members of class with dll attribute.
61206118
for (Decl *Member : Class->decls()) {
@@ -6179,8 +6177,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
61796177
if (MD->isInlined()) {
61806178
// MinGW does not import or export inline methods. But do it for
61816179
// template instantiations.
6182-
if (!Context.getTargetInfo().getCXXABI().isMicrosoft() &&
6183-
!Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() &&
6180+
if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
61846181
TSK != TSK_ExplicitInstantiationDeclaration &&
61856182
TSK != TSK_ExplicitInstantiationDefinition)
61866183
continue;

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9759,11 +9759,11 @@ DeclResult Sema::ActOnExplicitInstantiation(
97599759
Def->setTemplateSpecializationKind(TSK);
97609760

97619761
if (!getDLLAttr(Def) && getDLLAttr(Specialization) &&
9762-
(Context.getTargetInfo().getCXXABI().isMicrosoft() ||
9763-
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) {
9764-
// In the MS ABI, an explicit instantiation definition can add a dll
9765-
// attribute to a template with a previous instantiation declaration.
9766-
// MinGW doesn't allow this.
9762+
(Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
9763+
!Context.getTargetInfo().getTriple().isPS4CPU())) {
9764+
// An explicit instantiation definition can add a dll attribute to a
9765+
// template with a previous instantiation declaration. MinGW doesn't
9766+
// allow this.
97679767
auto *A = cast<InheritableAttr>(
97689768
getDLLAttr(Specialization)->clone(getASTContext()));
97699769
A->setInherited(true);
@@ -9777,19 +9777,19 @@ DeclResult Sema::ActOnExplicitInstantiation(
97779777
bool NewlyDLLExported =
97789778
!PreviouslyDLLExported && Specialization->hasAttr<DLLExportAttr>();
97799779
if (Old_TSK == TSK_ImplicitInstantiation && NewlyDLLExported &&
9780-
(Context.getTargetInfo().getCXXABI().isMicrosoft() ||
9781-
Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) {
9782-
// In the MS ABI, an explicit instantiation definition can add a dll
9783-
// attribute to a template with a previous implicit instantiation.
9784-
// MinGW doesn't allow this. We limit clang to only adding dllexport, to
9785-
// avoid potentially strange codegen behavior. For example, if we extend
9786-
// this conditional to dllimport, and we have a source file calling a
9787-
// method on an implicitly instantiated template class instance and then
9788-
// declaring a dllimport explicit instantiation definition for the same
9789-
// template class, the codegen for the method call will not respect the
9790-
// dllimport, while it will with cl. The Def will already have the DLL
9791-
// attribute, since the Def and Specialization will be the same in the
9792-
// case of Old_TSK == TSK_ImplicitInstantiation, and we already added the
9780+
(Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
9781+
!Context.getTargetInfo().getTriple().isPS4CPU())) {
9782+
// An explicit instantiation definition can add a dll attribute to a
9783+
// template with a previous implicit instantiation. MinGW doesn't allow
9784+
// this. We limit clang to only adding dllexport, to avoid potentially
9785+
// strange codegen behavior. For example, if we extend this conditional
9786+
// to dllimport, and we have a source file calling a method on an
9787+
// implicitly instantiated template class instance and then declaring a
9788+
// dllimport explicit instantiation definition for the same template
9789+
// class, the codegen for the method call will not respect the dllimport,
9790+
// while it will with cl. The Def will already have the DLL attribute,
9791+
// since the Def and Specialization will be the same in the case of
9792+
// Old_TSK == TSK_ImplicitInstantiation, and we already added the
97939793
// attribute to the Specialization; we just need to make it take effect.
97949794
assert(Def == Specialization &&
97959795
"Def and Specialization should match for implicit instantiation");

clang/test/CodeGenCXX/dllexport-vtable-thunks.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %clang_cc1 -triple x86_64-windows-gnu -fdeclspec -emit-llvm -o - %s | FileCheck %s
2-
// RUN: %clang_cc1 -triple x86_64-windows-itanium -fdeclspec -emit-llvm -o - %s | FileCheck %s
1+
// RUN: %clang_cc1 -triple x86_64-windows-gnu -fdeclspec -emit-llvm -o - %s | FileCheck %s -DDSO_ATTRS="dso_local dllexport"
2+
// RUN: %clang_cc1 -triple x86_64-windows-itanium -fdeclspec -emit-llvm -o - %s | FileCheck %s -DDSO_ATTRS="dso_local dllexport"
3+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fdeclspec -emit-llvm -o - %s | FileCheck %s -DDSO_ATTRS=dllexport
34

45
struct __declspec(dllexport) A {
56
virtual void m();
@@ -11,7 +12,7 @@ struct __declspec(dllexport) C : A, B {
1112
virtual void m();
1213
};
1314
void C::m() {}
14-
// CHECK: define dso_local dllexport void @_ZThn8_N1C1mEv
15+
// CHECK: define [[DSO_ATTRS]] void @_ZThn8_N1C1mEv
1516

1617
struct Base {
1718
virtual void m();
@@ -20,4 +21,4 @@ struct __declspec(dllexport) Derived : virtual Base {
2021
virtual void m();
2122
};
2223
void Derived::m() {}
23-
// CHECK: define dso_local dllexport void @_ZTv0_n24_N7Derived1mEv
24+
// CHECK: define [[DSO_ATTRS]] void @_ZTv0_n24_N7Derived1mEv

clang/test/CodeGenCXX/windows-implicit-dllexport-template-specialization.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %clang_cc1 -std=c++11 -triple i686-windows -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MS
1+
// RUN: %clang_cc1 -std=c++11 -triple i686-windows -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-MS
22
// RUN: %clang_cc1 -std=c++11 -triple i686-windows-itanium -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-IA
3+
// RUN: %clang_cc1 -std=c++11 -triple x86_64-scei-ps4 -fdeclspec -emit-llvm %s -o - | FileCheck %s -check-prefix CHECK-PS4
34

45
template <typename>
56
struct s {};
@@ -16,3 +17,5 @@ template class __declspec(dllexport) t<char>;
1617
// CHECK-IA: dllexport {{.*}} @_ZN1tIcEaSERKS0_
1718
// CHECK-IA: dllexport {{.*}} @_ZN1sIcEaSERKS0_
1819

20+
// CHECK-PS4-NOT: @_ZN1tIcEaSERKS0_
21+
// CHECK-PS4-NOT: @_ZN1sIcEaSERKS0_

clang/test/CodeGenCXX/windows-itanium-dllexport.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_cc1 -emit-llvm -triple i686-windows-itanium -fdeclspec %s -o - | FileCheck %s
1+
// RUN: %clang_cc1 -emit-llvm -triple i686-windows-itanium -fdeclspec %s -o - | FileCheck %s --check-prefixes=CHECK,WI
2+
// RUN: %clang_cc1 -emit-llvm -triple x86_64-scei-ps4 -fdeclspec %s -o - | FileCheck %s --check-prefixes=CHECK,PS4
23

34
#define JOIN2(x, y) x##y
45
#define JOIN(x, y) JOIN2(x, y)
@@ -25,14 +26,18 @@ template class __declspec(dllexport) c<int>;
2526
extern template class c<char>;
2627
template class __declspec(dllexport) c<char>;
2728

28-
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcEaSERKS0_
29-
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
29+
// WI: define {{.*}} dllexport {{.*}} @_ZN1cIcEaSERKS0_
30+
// WI: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
31+
// PS4-NOT: @_ZN1cIcEaSERKS0_
32+
// PS4: define weak_odr void @_ZN1cIcE1fEv
3033

3134
c<double> g;
3235
template class __declspec(dllexport) c<double>;
3336

34-
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_
35-
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
37+
// WI: define {{.*}} dllexport {{.*}} @_ZN1cIdEaSERKS0_
38+
// WI: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
39+
// PS4-NOT: @_ZN1cIdEaSERKS0_
40+
// PS4: define weak_odr void @_ZN1cIdE1fEv
3641

3742
template <class T>
3843
struct outer {
@@ -51,5 +56,6 @@ extern template class __declspec(dllimport) outer<char>;
5156
USEMEMFUNC(outer<char>, f)
5257
USEMEMFUNC(outer<char>::inner, f)
5358

54-
// CHECK: declare dllimport {{.*}} @_ZN5outerIcE1fEv
55-
// CHECK: define {{.*}} @_ZN5outerIcE5inner1fEv
59+
// CHECK-DAG: declare dllimport {{.*}} @_ZN5outerIcE1fEv
60+
// WI-DAG: define {{.*}} @_ZN5outerIcE5inner1fEv
61+
// PS4-DAG: declare {{.*}} @_ZN5outerIcE5inner1fEv

clang/test/Sema/dllimport.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// RUN: %clang_cc1 -triple aarch64-win32 -fsyntax-only -fms-extensions -verify -std=c99 -DMS %s
66
// RUN: %clang_cc1 -triple i686-windows-itanium -fsyntax-only -fms-extensions -verify -std=c99 -DWI %s
77
// RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c11 -DWI %s
8+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fms-extensions -verify -std=c11 -DWI %s
9+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fms-extensions -verify -std=c99 -DWI %s
810

911
// Invalid usage.
1012
__declspec(dllimport) typedef int typedef1;

clang/test/SemaCXX/dllexport.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template %s
55
// RUN: %clang_cc1 -triple i686-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI %s
66
// RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++1y -Wunsupported-dll-base-class-template -DWI %s
7+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++1y -Wunsupported-dll-base-class-template -DWI %s
78

89
// Helper structs to make templates more expressive.
910
struct ImplicitInst_Exported {};

clang/test/SemaCXX/dllimport.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions -verify -std=c++17 -Wunsupported-dll-base-class-template -DGNU %s
66
// RUN: %clang_cc1 -triple i686-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI %s
77
// RUN: %clang_cc1 -triple x86_64-windows-itanium -fsyntax-only -fms-extensions -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI %s
8+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++11 -Wunsupported-dll-base-class-template -DWI %s
9+
// RUN: %clang_cc1 -triple x86_64-scei-ps4 -fsyntax-only -fdeclspec -verify -std=c++17 -Wunsupported-dll-base-class-template -DWI %s
810

911
// Helper structs to make templates more expressive.
1012
struct ImplicitInst_Imported {};

0 commit comments

Comments
 (0)