[libcxx-commits] [libcxxabi] [llvm] [ItaniumDemangle] Fix conversion operators failing to demangle types with substitutions (PR #197420)

Iris Shi via libcxx-commits libcxx-commits at lists.llvm.org
Thu Aug 27 19:12:38 PDT 2026


https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/197420

>From f6dbeb95796f2506f8e8faf3311190a911c4770e Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Wed, 26 Aug 2026 13:41:24 +0800
Subject: [PATCH] [ItaniumDemangle] Fix conversion operators failing to
 demangle types with substitutions

---
 libcxxabi/src/demangle/ItaniumDemangle.h                 | 4 ++++
 libcxxabi/test/DemangleTestCases.inc                     | 5 +++++
 llvm/include/llvm/Demangle/ItaniumDemangle.h             | 4 ++++
 llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc | 5 +++++
 llvm/unittests/Demangle/DemangleTest.cpp                 | 9 +++++++++
 5 files changed, 27 insertions(+)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 842b9614d9ff7..b9d635880cde6 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -6152,6 +6152,10 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
   if (!consumeIf('I'))
     return nullptr;
 
+  // Subtypes within template args are complete, so they can always parse their
+  // own template args.
+  ScopedOverride<bool> SaveTryToParseTemplateArgs(TryToParseTemplateArgs, true);
+
   // <template-params> refer to the innermost <template-args>. Clear out any
   // outer args that we may have inserted into TemplateParams.
   if (TagTemplates) {
diff --git a/libcxxabi/test/DemangleTestCases.inc b/libcxxabi/test/DemangleTestCases.inc
index 6b7a99d849a94..59fe3bc64fcec 100644
--- a/libcxxabi/test/DemangleTestCases.inc
+++ b/libcxxabi/test/DemangleTestCases.inc
@@ -30234,4 +30234,9 @@
 {"__alloc_token_123__ZnwmRKSt9nothrow_t", "operator new(unsigned long, std::nothrow_t const&) (.alloc_token)"},
 {"__alloc_token__Znwm.llvm.1234", "operator new(unsigned long) (.llvm.1234) (.alloc_token)"},
 {"__alloc_token_123__Z3foov", "foo() (.alloc_token)"},
+
+// Conversion operators with substitutions that have template args
+// (https://github.com/llvm/llvm-project/issues/109130)
+{"_ZN3foocvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEv", "foo::operator std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>()"},
+{"_ZN1XcvSt6vectorIiSaIiEEEv", "X::operator std::vector<int, std::allocator<int>>()"},
     // clang-format on
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 83c76c6088339..36a789b7c80e1 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -6152,6 +6152,10 @@ AbstractManglingParser<Derived, Alloc>::parseTemplateArgs(bool TagTemplates) {
   if (!consumeIf('I'))
     return nullptr;
 
+  // Subtypes within template args are complete, so they can always parse their
+  // own template args.
+  ScopedOverride<bool> SaveTryToParseTemplateArgs(TryToParseTemplateArgs, true);
+
   // <template-params> refer to the innermost <template-args>. Clear out any
   // outer args that we may have inserted into TemplateParams.
   if (TagTemplates) {
diff --git a/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc b/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
index 6b7a99d849a94..59fe3bc64fcec 100644
--- a/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
+++ b/llvm/include/llvm/Testing/Demangle/DemangleTestCases.inc
@@ -30234,4 +30234,9 @@
 {"__alloc_token_123__ZnwmRKSt9nothrow_t", "operator new(unsigned long, std::nothrow_t const&) (.alloc_token)"},
 {"__alloc_token__Znwm.llvm.1234", "operator new(unsigned long) (.llvm.1234) (.alloc_token)"},
 {"__alloc_token_123__Z3foov", "foo() (.alloc_token)"},
+
+// Conversion operators with substitutions that have template args
+// (https://github.com/llvm/llvm-project/issues/109130)
+{"_ZN3foocvNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEv", "foo::operator std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>()"},
+{"_ZN1XcvSt6vectorIiSaIiEEEv", "X::operator std::vector<int, std::allocator<int>>()"},
     // clang-format on
diff --git a/llvm/unittests/Demangle/DemangleTest.cpp b/llvm/unittests/Demangle/DemangleTest.cpp
index e60a75ecd76da..d3b3099bbbb1c 100644
--- a/llvm/unittests/Demangle/DemangleTest.cpp
+++ b/llvm/unittests/Demangle/DemangleTest.cpp
@@ -29,4 +29,13 @@ TEST(Demangle, demangleTest) {
   // extended type qualifier (https://bugs.llvm.org/show_bug.cgi?id=48009)
   EXPECT_EQ(demangle("_Z3fooILi79EEbU7_ExtIntIXT_EEi"),
             "bool foo<79>(int _ExtInt<79>)");
+
+  // Conversion operators with substitutions that have template args
+  // (https://github.com/llvm/llvm-project/issues/109130)
+  EXPECT_EQ(demangle("_ZN3foocvNSt7__cxx1112basic_stringIcSt11char_"
+                     "traitsIcESaIcEEEEv"),
+            "foo::operator std::__cxx11::basic_string<char, "
+            "std::char_traits<char>, std::allocator<char>>()");
+  EXPECT_EQ(demangle("_ZN1XcvSt6vectorIiSaIiEEEv"),
+            "X::operator std::vector<int, std::allocator<int>>()");
 }



More information about the libcxx-commits mailing list