[clang] [clang] Inconsistent attributes for `dllexport __cxxabiv1:: __fundamental_type_info` with `-fvisibility=hidden` (PR #215859)
Akash Manna via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 9 20:50:18 PDT 2026
https://github.com/akash-manna-sky updated https://github.com/llvm/llvm-project/pull/215859
>From 04406300c9c4bf0b56a95904918a4c8e210d61a5 Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Wed, 12 Aug 2026 23:34:24 +0530
Subject: [PATCH 1/3] [clang][CodeGen] Don't emit hidden dllexport RTTI
---
clang/lib/CodeGen/ItaniumCXXABI.cpp | 16 +++++-
.../CodeGenCXX/dllexport-rtti-visibility.cpp | 50 +++++++++++++++++++
2 files changed, 64 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index c17813140b10f..41913e1891f39 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -4237,6 +4237,18 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {
return BuildTypeInfo(Ty, Linkage, llvmVisibility, DLLStorageClass);
}
+/// Returns the visibility to use for an RTTI global. A dllexported global must
+/// not be hidden, so dllexport takes precedence over the visibility implied by
+/// -fvisibility=hidden, as CodeGenModule::setGlobalVisibility does elsewhere.
+static llvm::GlobalValue::VisibilityTypes
+getRTTIVisibility(llvm::GlobalValue::VisibilityTypes Visibility,
+ llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {
+ if (DLLStorageClass == llvm::GlobalValue::DLLExportStorageClass &&
+ Visibility == llvm::GlobalValue::HiddenVisibility)
+ return llvm::GlobalValue::DefaultVisibility;
+ return Visibility;
+}
+
llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
QualType Ty,
llvm::GlobalVariable::LinkageTypes Linkage,
@@ -4419,10 +4431,10 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
// All of this is to say that it's important that both the type_info
// object and the type_info name be uniqued when weakly emitted.
- TypeName->setVisibility(Visibility);
+ TypeName->setVisibility(getRTTIVisibility(Visibility, DLLStorageClass));
CGM.setDSOLocal(TypeName);
- GV->setVisibility(Visibility);
+ GV->setVisibility(getRTTIVisibility(Visibility, GVDLLStorageClass));
CGM.setDSOLocal(GV);
TypeName->setDLLStorageClass(DLLStorageClass);
diff --git a/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp b/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
new file mode 100644
index 0000000000000..0081a8f8cac3b
--- /dev/null
+++ b/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
@@ -0,0 +1,50 @@
+/// dllexport expresses non-hidden intention and takes precedence over the
+/// visibility implied by -fvisibility=hidden. Check that this holds for RTTI.
+
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-gnu -fdeclspec -fvisibility=hidden -o - %s | FileCheck %s --check-prefixes=CHECK,GNU
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-itanium -fdeclspec -fvisibility=hidden -o - %s | FileCheck %s --check-prefixes=CHECK,ITANIUM
+
+// GNU-DAG: @_ZTI5plain = linkonce_odr hidden constant
+// GNU-DAG: @_ZTS5plain = linkonce_odr hidden constant
+// ITANIUM-DAG: @_ZTI5plain = hidden constant
+// ITANIUM-DAG: @_ZTS5plain = hidden constant
+struct plain {
+ virtual ~plain();
+};
+plain::~plain() {}
+
+/// RTTI is only dllexported for Windows Itanium.
+// GNU-DAG: @_ZTI8exported = linkonce_odr hidden constant
+// GNU-DAG: @_ZTS8exported = linkonce_odr hidden constant
+// ITANIUM-DAG: @_ZTI8exported = dso_local dllexport constant
+// ITANIUM-DAG: @_ZTS8exported = dso_local dllexport constant
+struct __declspec(dllexport) exported {
+ virtual ~exported();
+};
+exported::~exported() {}
+
+/// Defining __cxxabiv1::__fundamental_type_info makes Clang implicitly emit the
+/// RTTI descriptors for the fundamental types, with the class' storage class.
+// GNU-DAG: @_ZTIN10__cxxabiv123__fundamental_type_infoE = linkonce_odr hidden constant
+// GNU-DAG: @_ZTSN10__cxxabiv123__fundamental_type_infoE = linkonce_odr hidden constant
+// ITANIUM-DAG: @_ZTIN10__cxxabiv123__fundamental_type_infoE = dso_local dllexport constant
+// ITANIUM-DAG: @_ZTSN10__cxxabiv123__fundamental_type_infoE = dso_local dllexport constant
+
+// CHECK-DAG: @_ZTIv = dso_local dllexport constant
+// CHECK-DAG: @_ZTSv = dso_local dllexport constant
+// CHECK-DAG: @_ZTIPv = dso_local dllexport constant
+// CHECK-DAG: @_ZTSPv = dso_local dllexport constant
+// CHECK-DAG: @_ZTIPKv = dso_local dllexport constant
+// CHECK-DAG: @_ZTSPKv = dso_local dllexport constant
+// CHECK-DAG: @_ZTIi = dso_local dllexport constant
+// CHECK-DAG: @_ZTSi = dso_local dllexport constant
+// CHECK-DAG: @_ZTIPi = dso_local dllexport constant
+// CHECK-DAG: @_ZTSPi = dso_local dllexport constant
+// CHECK-DAG: @_ZTIPKi = dso_local dllexport constant
+// CHECK-DAG: @_ZTSPKi = dso_local dllexport constant
+namespace __cxxabiv1 {
+struct __declspec(dllexport) __fundamental_type_info {
+ virtual ~__fundamental_type_info();
+};
+__fundamental_type_info::~__fundamental_type_info() {}
+} // namespace __cxxabiv1
>From f5faf0986e0166518d6febc64eaf469ec090d6fd Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Thu, 13 Aug 2026 00:41:30 +0530
Subject: [PATCH 2/3] [clang][CodeGen] Reconcile RTTI visibility where the DLL
storage class is computed
---
clang/lib/CodeGen/ItaniumCXXABI.cpp | 40 +++++++++++--------
.../CodeGenCXX/dllexport-rtti-visibility.cpp | 14 ++++++-
2 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 41913e1891f39..e5e4b102ba92b 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -4187,6 +4187,19 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
llvm_unreachable("Invalid linkage!");
}
+/// Returns the visibility to use for an RTTI global with the given DLL storage
+/// class. A dllexported global must not be hidden, so dllexport takes
+/// precedence over the visibility implied by -fvisibility=hidden, as
+/// CodeGenModule::setGlobalVisibility does for other globals.
+static llvm::GlobalValue::VisibilityTypes
+getRTTIVisibility(llvm::GlobalValue::VisibilityTypes Visibility,
+ llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {
+ if (DLLStorageClass == llvm::GlobalValue::DLLExportStorageClass &&
+ Visibility == llvm::GlobalValue::HiddenVisibility)
+ return llvm::GlobalValue::DefaultVisibility;
+ return Visibility;
+}
+
llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {
// We want to operate on the canonical type.
Ty = Ty.getCanonicalType();
@@ -4234,19 +4247,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {
llvmVisibility == llvm::GlobalValue::DefaultVisibility))
DLLStorageClass = llvm::GlobalValue::DLLExportStorageClass;
}
- return BuildTypeInfo(Ty, Linkage, llvmVisibility, DLLStorageClass);
-}
+ llvmVisibility = getRTTIVisibility(llvmVisibility, DLLStorageClass);
-/// Returns the visibility to use for an RTTI global. A dllexported global must
-/// not be hidden, so dllexport takes precedence over the visibility implied by
-/// -fvisibility=hidden, as CodeGenModule::setGlobalVisibility does elsewhere.
-static llvm::GlobalValue::VisibilityTypes
-getRTTIVisibility(llvm::GlobalValue::VisibilityTypes Visibility,
- llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {
- if (DLLStorageClass == llvm::GlobalValue::DLLExportStorageClass &&
- Visibility == llvm::GlobalValue::HiddenVisibility)
- return llvm::GlobalValue::DefaultVisibility;
- return Visibility;
+ return BuildTypeInfo(Ty, Linkage, llvmVisibility, DLLStorageClass);
}
llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
@@ -4391,14 +4394,17 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
// Export the typeinfo in the same circumstances as the vtable is exported.
auto GVDLLStorageClass = DLLStorageClass;
+ auto GVVisibility = Visibility;
if (CGM.getTarget().hasPS4DLLImportExport() &&
GVDLLStorageClass != llvm::GlobalVariable::DLLExportStorageClass) {
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
const auto *RD =
cast<CXXRecordDecl>(RecordTy->getDecl())->getDefinitionOrSelf();
if (RD->hasAttr<DLLExportAttr>() ||
- CXXRecordNonInlineHasAttr<DLLExportAttr>(RD))
+ CXXRecordNonInlineHasAttr<DLLExportAttr>(RD)) {
GVDLLStorageClass = llvm::GlobalVariable::DLLExportStorageClass;
+ GVVisibility = getRTTIVisibility(GVVisibility, GVDLLStorageClass);
+ }
}
}
@@ -4431,10 +4437,10 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
// All of this is to say that it's important that both the type_info
// object and the type_info name be uniqued when weakly emitted.
- TypeName->setVisibility(getRTTIVisibility(Visibility, DLLStorageClass));
+ TypeName->setVisibility(Visibility);
CGM.setDSOLocal(TypeName);
- GV->setVisibility(getRTTIVisibility(Visibility, GVDLLStorageClass));
+ GV->setVisibility(GVVisibility);
CGM.setDSOLocal(GV);
TypeName->setDLLStorageClass(DLLStorageClass);
@@ -4734,8 +4740,8 @@ void ItaniumCXXABI::EmitFundamentalRTTIDescriptors(const CXXRecordDecl *RD) {
RD->hasAttr<DLLExportAttr>() || CGM.shouldMapVisibilityToDLLExport(RD)
? llvm::GlobalValue::DLLExportStorageClass
: llvm::GlobalValue::DefaultStorageClass;
- llvm::GlobalValue::VisibilityTypes Visibility =
- CodeGenModule::GetLLVMVisibility(RD->getVisibility());
+ llvm::GlobalValue::VisibilityTypes Visibility = getRTTIVisibility(
+ CodeGenModule::GetLLVMVisibility(RD->getVisibility()), DLLStorageClass);
for (const QualType &FundamentalType : FundamentalTypes) {
QualType PointerType = getContext().getPointerType(FundamentalType);
QualType PointerTypeConst = getContext().getPointerType(
diff --git a/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp b/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
index 0081a8f8cac3b..ff0bb9b139678 100644
--- a/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
+++ b/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
@@ -3,21 +3,28 @@
// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-gnu -fdeclspec -fvisibility=hidden -o - %s | FileCheck %s --check-prefixes=CHECK,GNU
// RUN: %clang_cc1 -emit-llvm -triple x86_64-windows-itanium -fdeclspec -fvisibility=hidden -o - %s | FileCheck %s --check-prefixes=CHECK,ITANIUM
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-scei-ps4 -fdeclspec -fvisibility=hidden -o - %s | FileCheck %s --check-prefix=PS
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-sie-ps5 -fdeclspec -fvisibility=hidden -o - %s | FileCheck %s --check-prefix=PS
// GNU-DAG: @_ZTI5plain = linkonce_odr hidden constant
// GNU-DAG: @_ZTS5plain = linkonce_odr hidden constant
// ITANIUM-DAG: @_ZTI5plain = hidden constant
// ITANIUM-DAG: @_ZTS5plain = hidden constant
+// PS-DAG: @_ZTI5plain = {{(linkonce_odr )?}}hidden constant
+// PS-DAG: @_ZTS5plain = {{(linkonce_odr )?}}hidden constant
struct plain {
virtual ~plain();
};
plain::~plain() {}
-/// RTTI is only dllexported for Windows Itanium.
+/// RTTI is only dllexported for Windows Itanium; PS4/PS5 export the type info
+/// but not the type name.
// GNU-DAG: @_ZTI8exported = linkonce_odr hidden constant
// GNU-DAG: @_ZTS8exported = linkonce_odr hidden constant
// ITANIUM-DAG: @_ZTI8exported = dso_local dllexport constant
// ITANIUM-DAG: @_ZTS8exported = dso_local dllexport constant
+// PS-DAG: @_ZTI8exported = {{(dso_local )?}}dllexport constant
+// PS-DAG: @_ZTS8exported = {{(linkonce_odr )?}}hidden constant
struct __declspec(dllexport) exported {
virtual ~exported();
};
@@ -29,6 +36,11 @@ exported::~exported() {}
// GNU-DAG: @_ZTSN10__cxxabiv123__fundamental_type_infoE = linkonce_odr hidden constant
// ITANIUM-DAG: @_ZTIN10__cxxabiv123__fundamental_type_infoE = dso_local dllexport constant
// ITANIUM-DAG: @_ZTSN10__cxxabiv123__fundamental_type_infoE = dso_local dllexport constant
+// PS-DAG: @_ZTIN10__cxxabiv123__fundamental_type_infoE = {{(dso_local )?}}dllexport constant
+// PS-DAG: @_ZTSN10__cxxabiv123__fundamental_type_infoE = {{(linkonce_odr )?}}hidden constant
+
+// PS-DAG: @_ZTIv = {{(dso_local )?}}dllexport constant
+// PS-DAG: @_ZTSv = {{(dso_local )?}}dllexport constant
// CHECK-DAG: @_ZTIv = dso_local dllexport constant
// CHECK-DAG: @_ZTSv = dso_local dllexport constant
>From 91c7b1c688b0414eeacef00171f0cbdb7aeb65d4 Mon Sep 17 00:00:00 2001
From: Akash Manna <akash.manna.mymail at gmail.com>
Date: Sat, 29 Aug 2026 23:06:03 +0530
Subject: [PATCH 3/3] [clang][CodeGen] Move PS4 RTTI export decision to
BuildTypeInfo(QualType)
---
clang/docs/ReleaseNotes.md | 1 +
clang/lib/CodeGen/ItaniumCXXABI.cpp | 64 +++++++++----------
.../CodeGenCXX/dllexport-rtti-visibility.cpp | 13 ++++
3 files changed, 46 insertions(+), 32 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 332e0bfdb3a8b..3bcd66d8113d8 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -443,6 +443,7 @@ features cannot lower the translation-unit ABI level;
- Fixed a crash when declaring a member template within a local class inside an OpenMP region. (#GH216052)
- Fixed a bug where repeated #imports of modular headers in non-modular compilation were translated to #pragma clang module import. (#GH216924)
- Fixed an assertion when `#pragma omp declare simd` or `#pragma omp declare variant` is followed by another OpenMP declarative directive containing a qualified identifier. (#GH217204)
+- Fixed a crash when emitting RTTI for a `dllexport` class, or the fundamental type descriptors for `__cxxabiv1::__fundamental_type_info`, under `-fvisibility=hidden`. (#GH207963)
#### Bug Fixes to Compiler Builtins
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index e5e4b102ba92b..7060d30c7d899 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3641,12 +3641,14 @@ class ItaniumRTTIBuilder {
/// link to an existing RTTI descriptor if one already exists.
llvm::Constant *BuildTypeInfo(QualType Ty);
- /// BuildTypeInfo - Build the RTTI type info struct for the given type.
+ /// BuildTypeInfo - Build the RTTI type info struct for the given type. The
+ /// TypeInfo* properties apply to the type info, the others to the type name.
llvm::Constant *BuildTypeInfo(
- QualType Ty,
- llvm::GlobalVariable::LinkageTypes Linkage,
+ QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage,
llvm::GlobalValue::VisibilityTypes Visibility,
- llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass);
+ llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass,
+ llvm::GlobalValue::VisibilityTypes TypeInfoVisibility,
+ llvm::GlobalValue::DLLStorageClassTypes TypeInfoDLLStorageClass);
};
}
@@ -4187,10 +4189,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM,
llvm_unreachable("Invalid linkage!");
}
-/// Returns the visibility to use for an RTTI global with the given DLL storage
-/// class. A dllexported global must not be hidden, so dllexport takes
-/// precedence over the visibility implied by -fvisibility=hidden, as
-/// CodeGenModule::setGlobalVisibility does for other globals.
+/// A dllexported global must not be hidden, so dllexport takes precedence over
+/// the visibility implied by -fvisibility=hidden, as elsewhere in CodeGen.
static llvm::GlobalValue::VisibilityTypes
getRTTIVisibility(llvm::GlobalValue::VisibilityTypes Visibility,
llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {
@@ -4249,14 +4249,30 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty) {
}
llvmVisibility = getRTTIVisibility(llvmVisibility, DLLStorageClass);
- return BuildTypeInfo(Ty, Linkage, llvmVisibility, DLLStorageClass);
+ // Export the typeinfo in the same circumstances as the vtable is exported.
+ llvm::GlobalValue::DLLStorageClassTypes TypeInfoDLLStorageClass =
+ DLLStorageClass;
+ if (CGM.getTarget().hasPS4DLLImportExport() &&
+ TypeInfoDLLStorageClass != llvm::GlobalValue::DLLExportStorageClass) {
+ if (auto RD = Ty->getAsCXXRecordDecl()) {
+ if (RD->hasAttr<DLLExportAttr>() ||
+ CXXRecordNonInlineHasAttr<DLLExportAttr>(RD))
+ TypeInfoDLLStorageClass = llvm::GlobalValue::DLLExportStorageClass;
+ }
+ }
+ llvm::GlobalValue::VisibilityTypes TypeInfoVisibility =
+ getRTTIVisibility(llvmVisibility, TypeInfoDLLStorageClass);
+
+ return BuildTypeInfo(Ty, Linkage, llvmVisibility, DLLStorageClass,
+ TypeInfoVisibility, TypeInfoDLLStorageClass);
}
llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
- QualType Ty,
- llvm::GlobalVariable::LinkageTypes Linkage,
- llvm::GlobalValue::VisibilityTypes Visibility,
- llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {
+ QualType Ty, llvm::GlobalVariable::LinkageTypes Linkage,
+ llvm::GlobalValue::VisibilityTypes Visibility,
+ llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass,
+ llvm::GlobalValue::VisibilityTypes TypeInfoVisibility,
+ llvm::GlobalValue::DLLStorageClassTypes TypeInfoDLLStorageClass) {
SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
@@ -4392,22 +4408,6 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
GV->replaceInitializer(llvm::ConstantStruct::getAnon(Fields));
- // Export the typeinfo in the same circumstances as the vtable is exported.
- auto GVDLLStorageClass = DLLStorageClass;
- auto GVVisibility = Visibility;
- if (CGM.getTarget().hasPS4DLLImportExport() &&
- GVDLLStorageClass != llvm::GlobalVariable::DLLExportStorageClass) {
- if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
- const auto *RD =
- cast<CXXRecordDecl>(RecordTy->getDecl())->getDefinitionOrSelf();
- if (RD->hasAttr<DLLExportAttr>() ||
- CXXRecordNonInlineHasAttr<DLLExportAttr>(RD)) {
- GVDLLStorageClass = llvm::GlobalVariable::DLLExportStorageClass;
- GVVisibility = getRTTIVisibility(GVVisibility, GVDLLStorageClass);
- }
- }
- }
-
// If there's already an old global variable, replace it with the new one.
if (OldGV) {
GV->takeName(OldGV);
@@ -4440,11 +4440,11 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
TypeName->setVisibility(Visibility);
CGM.setDSOLocal(TypeName);
- GV->setVisibility(GVVisibility);
+ GV->setVisibility(TypeInfoVisibility);
CGM.setDSOLocal(GV);
TypeName->setDLLStorageClass(DLLStorageClass);
- GV->setDLLStorageClass(GVDLLStorageClass);
+ GV->setDLLStorageClass(TypeInfoDLLStorageClass);
TypeName->setPartition(CGM.getCodeGenOpts().SymbolPartition);
GV->setPartition(CGM.getCodeGenOpts().SymbolPartition);
@@ -4748,7 +4748,7 @@ void ItaniumCXXABI::EmitFundamentalRTTIDescriptors(const CXXRecordDecl *RD) {
FundamentalType.withConst());
for (QualType Type : {FundamentalType, PointerType, PointerTypeConst})
ItaniumRTTIBuilder(*this).BuildTypeInfo(
- Type, llvm::GlobalValue::ExternalLinkage,
+ Type, llvm::GlobalValue::ExternalLinkage, Visibility, DLLStorageClass,
Visibility, DLLStorageClass);
}
}
diff --git a/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp b/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
index ff0bb9b139678..89685716380aa 100644
--- a/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
+++ b/clang/test/CodeGenCXX/dllexport-rtti-visibility.cpp
@@ -30,6 +30,19 @@ struct __declspec(dllexport) exported {
};
exported::~exported() {}
+/// PS4/PS5 also export the type info when a non-inline method is dllexported.
+// GNU-DAG: @_ZTI10partExport = linkonce_odr hidden constant
+// GNU-DAG: @_ZTS10partExport = linkonce_odr hidden constant
+// ITANIUM-DAG: @_ZTI10partExport = hidden constant
+// ITANIUM-DAG: @_ZTS10partExport = hidden constant
+// PS-DAG: @_ZTI10partExport = {{(dso_local )?}}dllexport constant
+// PS-DAG: @_ZTS10partExport = {{(linkonce_odr )?}}hidden constant
+struct partExport {
+ virtual ~partExport();
+ __declspec(dllexport) void f();
+};
+partExport::~partExport() {}
+
/// Defining __cxxabiv1::__fundamental_type_info makes Clang implicitly emit the
/// RTTI descriptors for the fundamental types, with the class' storage class.
// GNU-DAG: @_ZTIN10__cxxabiv123__fundamental_type_infoE = linkonce_odr hidden constant
More information about the cfe-commits
mailing list