https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/215859

Fixes #207963
[clang] Inconsistent attributes for `dllexport __cxxabiv1:: 
__fundamental_type_info with -fvisibility=hidden

The issue is `__declspec(dllexport)` and `hidden` visibility cannot be used 
together. LLVM rejects `globals` that have both attributes.

For normal globals, `CodeGenModule::setGlobalVisibility` already handles this 
by giving `dllexport` priority over the visibility implied by 
`-fvisibility=hidden`. RTTI follows a different code path, though. 
`ItaniumRTTIBuilder::BuildTypeInfo` applies the visibility and DLL storage 
class separately to the generated `_ZTI*` and `_ZTS*` globals, so the conflict 
was not resolved.

As a result, marking `__cxxabiv1::__fundamental_type_info` as `dllexport` while 
compiling with `-fvisibility=hidden` could generate RTTI globals with both 
hidden visibility and `dllexport`, causing LLVM to fail verification with 
Broken module found. The same problem can occur for `dllexport`-ed polymorphic 
classes when targeting Windows with the Itanium ABI.

Resolve the conflict directly in `BuildTypeInfo`, where both attributes are 
applied. When `dllexport` is present, only hidden visibility is changed to 
default; protected visibility is left unchanged because protected with 
`dllexport` is valid LLVM IR. Explicit `visibility("hidden")` on a 
`dllexport`-ed class continues to produce the existing diagnostic. I tested the 
changes locally, and all tests are passed. 


>From 097c9ff11ee398118dcb499af75638a7da5ef77f Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Wed, 12 Aug 2026 23:34:24 +0530
Subject: [PATCH] [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

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to