[clang] [clang] Avoid MS RTTI type_info name explosion (PR #206317)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 28 04:54:46 PDT 2026
https://github.com/poretga99 updated https://github.com/llvm/llvm-project/pull/206317
>From e0dd8911833fa5271104a9183cac07414a3732f9 Mon Sep 17 00:00:00 2001
From: mzukovec <martin.zukovec at xlab.si>
Date: Sun, 28 Jun 2026 09:51:02 +0200
Subject: [PATCH] [clang] Avoid MS RTTI type_info name explosion
---
clang/include/clang/AST/Mangle.h | 3 +-
clang/lib/AST/ItaniumMangle.cpp | 9 +--
clang/lib/AST/MicrosoftMangle.cpp | 63 +++++++++++--------
clang/lib/CodeGen/MicrosoftCXXABI.cpp | 4 +-
clang/test/CodeGenCXX/mangle-ms-md5.cpp | 17 +++++
.../test/CodeGenCXX/mangle-ms-rtti-lambda.cpp | 58 +++++++++++++++++
6 files changed, 122 insertions(+), 32 deletions(-)
create mode 100644 clang/test/CodeGenCXX/mangle-ms-rtti-lambda.cpp
diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h
index d62495095c7e4..09766d828af57 100644
--- a/clang/include/clang/AST/Mangle.h
+++ b/clang/include/clang/AST/Mangle.h
@@ -157,7 +157,8 @@ class MangleContext {
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &,
- bool NormalizeIntegers = false) = 0;
+ bool NormalizeIntegers = false,
+ bool ShortenRTTINames = false) = 0;
virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0;
virtual void mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream &) const;
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index e5cdd6f31c507..d7ecd705dc11e 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -111,8 +111,8 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type, raw_ostream &) override;
void mangleCXXRTTI(QualType T, raw_ostream &) override;
- void mangleCXXRTTIName(QualType T, raw_ostream &,
- bool NormalizeIntegers) override;
+ void mangleCXXRTTIName(QualType T, raw_ostream &, bool NormalizeIntegers,
+ bool ShortenRTTINames) override;
void mangleCanonicalTypeName(QualType T, raw_ostream &,
bool NormalizeIntegers) override;
@@ -7584,8 +7584,9 @@ void ItaniumMangleContextImpl::mangleCXXRTTI(QualType Ty, raw_ostream &Out) {
Mangler.mangleType(Ty);
}
-void ItaniumMangleContextImpl::mangleCXXRTTIName(
- QualType Ty, raw_ostream &Out, bool NormalizeIntegers = false) {
+void ItaniumMangleContextImpl::mangleCXXRTTIName(QualType Ty, raw_ostream &Out,
+ bool NormalizeIntegers = false,
+ bool = false) {
// <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
CXXNameMangler Mangler(*this, Out, NormalizeIntegers);
Mangler.getStream() << "_ZTS";
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index adfe260a0d091..b2373932bf0a0 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -180,8 +180,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
int32_t VBPtrOffset, uint32_t VBIndex,
raw_ostream &Out) override;
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
- void mangleCXXRTTIName(QualType T, raw_ostream &Out,
- bool NormalizeIntegers) override;
+ void mangleCXXRTTIName(QualType T, raw_ostream &Out, bool NormalizeIntegers,
+ bool ShortenRTTINames) override;
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags,
@@ -332,6 +332,7 @@ class MicrosoftCXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
const bool PointersAre64Bit;
+ const bool ShortenRTTINames;
DiagnosticBuilder Error(SourceLocation, StringRef, StringRef);
DiagnosticBuilder Error(SourceLocation, StringRef);
@@ -341,25 +342,31 @@ class MicrosoftCXXNameMangler {
enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result };
enum class TplArgKind { ClassNTTP, StructuralValue };
- MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_)
+ MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
+ bool ShortenRTTINamesIn = false)
: Context(C), Out(Out_), Structor(nullptr), StructorType(-1),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
- LangAS::Default) == 64) {}
+ LangAS::Default) == 64),
+ ShortenRTTINames(ShortenRTTINamesIn) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
- const CXXConstructorDecl *D, CXXCtorType Type)
+ const CXXConstructorDecl *D, CXXCtorType Type,
+ bool ShortenRTTINamesIn = false)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
- LangAS::Default) == 64) {}
+ LangAS::Default) == 64),
+ ShortenRTTINames(ShortenRTTINamesIn) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
- const CXXDestructorDecl *D, CXXDtorType Type)
+ const CXXDestructorDecl *D, CXXDtorType Type,
+ bool ShortenRTTINamesIn = false)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
- LangAS::Default) == 64) {}
+ LangAS::Default) == 64),
+ ShortenRTTINames(ShortenRTTINamesIn) {}
raw_ostream &getStream() const { return Out; }
@@ -963,7 +970,9 @@ void MicrosoftCXXNameMangler::mangleName(GlobalDecl GD) {
// Always start with the unqualified name.
mangleUnqualifiedName(GD);
- mangleNestedName(GD);
+ const auto *RD = dyn_cast<CXXRecordDecl>(GD.getDecl());
+ if (!ShortenRTTINames || !RD || !RD->isLambda())
+ mangleNestedName(GD);
// Terminate the whole name with an '@'.
Out << '@';
@@ -1119,7 +1128,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
// Mangle full template name into temporary buffer.
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Extra.mangleTemplateInstantiationName(TD, *TemplateArgs);
// Use the string backref vector to possibly get a back reference.
@@ -1267,7 +1276,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(GlobalDecl GD,
// If the context is a variable or a class member and not a parameter,
// it is encoded in a qualified name.
- if (LambdaManglingNumber && LambdaContextDecl) {
+ if (!ShortenRTTINames && LambdaManglingNumber && LambdaContextDecl) {
if ((isa<VarDecl>(LambdaContextDecl) ||
isa<FieldDecl>(LambdaContextDecl)) &&
!isa<ParmVarDecl>(LambdaContextDecl)) {
@@ -2173,7 +2182,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
void MicrosoftCXXNameMangler::mangleObjCProtocol(const ObjCProtocolDecl *PD) {
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
Extra.mangleSourceName("Protocol");
@@ -2187,7 +2196,7 @@ void MicrosoftCXXNameMangler::mangleObjCLifetime(const QualType Type,
SourceRange Range) {
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
switch (Quals.getObjCLifetime()) {
@@ -2216,7 +2225,7 @@ void MicrosoftCXXNameMangler::mangleObjCKindOfType(const ObjCObjectType *T,
SourceRange Range) {
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
Extra.mangleSourceName("KindOf");
@@ -2468,7 +2477,7 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T,
assert(Quals.hasAddressSpace() && "Not valid without address space");
llvm::SmallString<32> ASMangling;
llvm::raw_svector_ostream Stream(ASMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
LangAS AS = Quals.getAddressSpace();
@@ -3658,7 +3667,7 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, Qualifiers,
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
Extra.mangleSourceName("_Complex");
Extra.mangleType(ElementType, Range, QMM_Escape);
@@ -3723,7 +3732,7 @@ void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
Extra.mangleSourceName("__vector");
Extra.mangleType(QualType(ET ? static_cast<const Type *>(ET) : BitIntTy, 0),
@@ -3755,7 +3764,7 @@ void MicrosoftCXXNameMangler::mangleType(const ConstantMatrixType *T,
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
@@ -3905,7 +3914,7 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers,
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
Extra.mangleSourceName("_Atomic");
Extra.mangleType(ValueType, Range, QMM_Escape);
@@ -3919,7 +3928,7 @@ void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers,
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
Extra.mangleSourceName("ocl_pipe");
Extra.mangleType(ElementType, Range, QMM_Escape);
@@ -3957,7 +3966,7 @@ void MicrosoftCXXNameMangler::mangleType(const BitIntType *T, Qualifiers,
SourceRange Range) {
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
if (T->isUnsigned())
Extra.mangleSourceName("_UBitInt");
@@ -3989,7 +3998,7 @@ void MicrosoftCXXNameMangler::mangleType(const OverflowBehaviorType *T,
llvm::SmallString<64> TemplateMangling;
llvm::raw_svector_ostream Stream(TemplateMangling);
- MicrosoftCXXNameMangler Extra(Context, Stream);
+ MicrosoftCXXNameMangler Extra(Context, Stream, ShortenRTTINames);
Stream << "?$";
if (T->isWrapKind()) {
Extra.mangleSourceName("ObtWrap_");
@@ -4185,16 +4194,18 @@ void MicrosoftMangleContextImpl::mangleCXXVBTable(
void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
- MicrosoftCXXNameMangler Mangler(*this, MHO);
+ MicrosoftCXXNameMangler Mangler(*this, MHO, /*ShortenRTTINames=*/true);
Mangler.getStream() << "??_R0";
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
Mangler.getStream() << "@8";
}
void MicrosoftMangleContextImpl::mangleCXXRTTIName(
- QualType T, raw_ostream &Out, bool NormalizeIntegers = false) {
- MicrosoftCXXNameMangler Mangler(*this, Out);
- Mangler.getStream() << '.';
+ QualType T, raw_ostream &Out, bool NormalizeIntegers = false,
+ bool ShortenRTTINames = false) {
+ Out << '.';
+ msvc_hashing_ostream MHO(Out);
+ MicrosoftCXXNameMangler Mangler(*this, MHO, ShortenRTTINames);
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
}
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 40c7c00d85395..0ab18d00b7659 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -4057,7 +4057,9 @@ llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
SmallString<256> TypeInfoString;
{
llvm::raw_svector_ostream Out(TypeInfoString);
- getMangleContext().mangleCXXRTTIName(Type, Out);
+ getMangleContext().mangleCXXRTTIName(Type, Out,
+ /*NormalizeIntegers=*/false,
+ /*ShortenRTTINames=*/true);
}
// Declare and initialize the TypeDescriptor.
diff --git a/clang/test/CodeGenCXX/mangle-ms-md5.cpp b/clang/test/CodeGenCXX/mangle-ms-md5.cpp
index 6cd145d9166b6..bfc41156e64d8 100644
--- a/clang/test/CodeGenCXX/mangle-ms-md5.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-md5.cpp
@@ -34,6 +34,7 @@ struct Y4095 {
Y4095::Y4095() {}
// CHECK-DAG: @"??@a6a285da2eea70dba6b578022be61d81@??_R4@" = linkonce_odr constant %rtti.CompleteObjectLocator
// CHECK-DAG: @"??@a6a285da2eea70dba6b578022be61d81@" = alias
+// CHECK-DAG: @"??@c14087f0ec22b387aea7c59083f4f546@" = linkonce_odr global %rtti.TypeDescriptor37 { ptr @"??_7type_info@@6B@", ptr null, [38 x i8] c".??@5ca87b4c7c2322ca1e21f8b01a23e135@\00" }, comdat
// RUN: %clang_cc1 -DTHROW -fcxx-exceptions -fms-compatibility-version=18.0 -emit-llvm -o - -triple i686-pc-win32 %s | FileCheck --check-prefix=HAVECTOR %s
// RUN: %clang_cc1 -DTHROW -fcxx-exceptions -fms-compatibility-version=19.0 -emit-llvm -o - -triple i686-pc-win32 %s | FileCheck --check-prefix=OMITCTOR %s
@@ -71,3 +72,19 @@ int X4088(z) = 1515;
// Use initialization to verify mangled name association in the il
int X4089(z) = 1717;
// CHECK-DAG: @"??@0269945400a3474730d6880df0967d8f@" = dso_local global i32 1717, align 4
+
+#define R4090 X4089(r)
+struct R4090 {
+ R4090();
+ virtual void f();
+};
+R4090::R4090() {}
+// CHECK-DAG: @"??@{{[0-9a-f]+}}@" = linkonce_odr global %rtti.TypeDescriptor4096 { ptr @"??_7type_info@@6B@", ptr null, [4097 x i8] c".?AU{{r+}}@@\00" }, comdat
+
+#define R4091 C2(X4089(s), s)
+struct R4091 {
+ R4091();
+ virtual void f();
+};
+R4091::R4091() {}
+// CHECK-DAG: @"??@{{[0-9a-f]+}}@" = linkonce_odr global %rtti.TypeDescriptor37 { ptr @"??_7type_info@@6B@", ptr null, [38 x i8] c".??@c9d63594821ede4ea693d109deaa7a17@\00" }, comdat
diff --git a/clang/test/CodeGenCXX/mangle-ms-rtti-lambda.cpp b/clang/test/CodeGenCXX/mangle-ms-rtti-lambda.cpp
new file mode 100644
index 0000000000000..a6a7e4b9e1ee1
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-ms-rtti-lambda.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc -std=c++17 -fms-compatibility -fms-extensions -emit-llvm -o - %s | FileCheck --implicit-check-not='?$make_layer' %s
+
+namespace std {
+class type_info {
+public:
+ const char *name() const;
+};
+}
+
+using size_t = decltype(sizeof(0));
+
+template <typename... Ts> struct pack {};
+
+template <typename A, typename B> struct pair_like {
+ using first = A;
+ using second = B;
+};
+
+template <typename A, typename B, typename C, typename D> struct quad_like {
+ using a = A;
+ using b = B;
+ using c = C;
+ using d = D;
+};
+
+template <typename T> struct holder {
+ T *value;
+};
+
+template <typename T> auto make_layer() {
+ auto local_lambda = [](const T *, size_t) noexcept { return sizeof(T); };
+ using L = decltype(local_lambda);
+ using PairTL = pair_like<T, L>;
+ using PairLT = pair_like<L, T>;
+ using Quad = quad_like<PairTL, PairLT, holder<T>, holder<L>>;
+ return pack<T, L, PairTL, PairLT, Quad, holder<Quad>>{};
+}
+
+struct seed {
+ int value;
+};
+
+using t01 = decltype(make_layer<seed>());
+using t02 = decltype(make_layer<t01>());
+using t03 = decltype(make_layer<t02>());
+
+extern "C" const std::type_info *repro_type_infos[] = {
+ &typeid(t01),
+ &typeid(t02),
+ &typeid(t03),
+};
+
+extern "C" const char *repro_last_name() {
+ return typeid(t03).name();
+}
+
+// CHECK-DAG: global %rtti.TypeDescriptor{{[0-9]+}} { ptr @"??_7type_info@@6B@", ptr null, [{{[0-9]+}} x i8] c".?AU?$pack at Useed@@V<lambda_1>@@U?$pair_like at Useed@@V<lambda_1>@@@@
+// CHECK-DAG: global %rtti.TypeDescriptor37 { ptr @"??_7type_info@@6B@", ptr null, [38 x i8] c".??@{{[0-9a-f]+}}@\00" }, comdat
More information about the cfe-commits
mailing list