[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