[llvm] Fix MSVC Demangling with auto NTTP mangled names for function pointer, pointer to data and integral types (PR #96590)

Max Winkler via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 24 23:33:28 PDT 2024


https://github.com/MaxEW707 updated https://github.com/llvm/llvm-project/pull/96590

>From 6bd70bb27894c7f24d82f238f97f8ca18653a30c Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Sat, 22 Jun 2024 22:59:23 -0700
Subject: [PATCH 1/4] Fix MSVC Demangling with auto NTTP mangled names for
 function pointers and pointers to variables

---
 llvm/lib/Demangle/MicrosoftDemangle.cpp   | 17 +++++++++-
 llvm/test/Demangle/ms-auto-templates.test | 39 +++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/Demangle/ms-auto-templates.test

diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index cd7ff40d63a49..1c90c8553fb54 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -2269,12 +2269,27 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
     } else if (llvm::itanium_demangle::starts_with(MangledName, "$1") ||
                llvm::itanium_demangle::starts_with(MangledName, "$H") ||
                llvm::itanium_demangle::starts_with(MangledName, "$I") ||
-               llvm::itanium_demangle::starts_with(MangledName, "$J")) {
+               llvm::itanium_demangle::starts_with(MangledName, "$J") ||
+               llvm::itanium_demangle::starts_with(MangledName, "$M")) {
       // Pointer to member
       TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
       TPRN->IsMemberPointer = true;
 
       MangledName.remove_prefix(1);
+
+      // <auto-nttp> ::= $ M <type> 1? <mangled-name>
+      if (llvm::itanium_demangle::starts_with(MangledName, 'M')) {
+        MangledName.remove_prefix(1);
+
+        // The deduced type of the auto NTTP parameter isn't printed so
+        // we want to ignore the AST created from demangling the type.
+        //
+        // TODO: Avoid the extra allocations to the bump allocator in this case.
+        (void)demangleType(MangledName, QualifierMangleMode::Drop);
+        if (Error)
+          return nullptr;
+      }
+
       // 1 - single inheritance       <name>
       // H - multiple inheritance     <name> <number>
       // I - virtual inheritance      <name> <number> <number>
diff --git a/llvm/test/Demangle/ms-auto-templates.test b/llvm/test/Demangle/ms-auto-templates.test
new file mode 100644
index 0000000000000..039c150b06d48
--- /dev/null
+++ b/llvm/test/Demangle/ms-auto-templates.test
@@ -0,0 +1,39 @@
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+??0?$AutoNTTPClass@$MPEAH1?i@@3HA@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int i>::AutoNTTPClass<&int i>(void)
+
+??0?$AutoNTTPClass@$1?i@@3HA@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int i>::AutoNTTPClass<&int i>(void)
+
+??0?$AutoNTTPClass@$MPEAH1?i@@3HA$MPEAH1?j@@3HA@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int i, &int j>::AutoNTTPClass<&int i, &int j>(void)
+
+??0?$AutoNTTPClass@$1?i@@3HA$1?j@@3HA@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int i, &int j>::AutoNTTPClass<&int i, &int j>(void)
+
+??0?$AutoNTTPClass@$MP6AHXZ1?Func@@YAHXZ@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int __cdecl Func(void)>::AutoNTTPClass<&int __cdecl Func(void)>(void)
+
+??0?$AutoNTTPClass@$1?Func@@YAHXZ@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int __cdecl Func(void)>::AutoNTTPClass<&int __cdecl Func(void)>(void)
+
+??0?$AutoNTTPClass@$MP6AHXZ1?Func@@YAHXZ$MP6AHXZ1?Func2@@YAHXZ@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int __cdecl Func(void), &int __cdecl Func2(void)>::AutoNTTPClass<&int __cdecl Func(void), &int __cdecl Func2(void)>(void)
+
+??0?$AutoNTTPClass@$1?Func@@YAHXZ$1?Func2@@YAHXZ@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<&int __cdecl Func(void), &int __cdecl Func2(void)>::AutoNTTPClass<&int __cdecl Func(void), &int __cdecl Func2(void)>(void)
+
+??$AutoFunc@$MPEAH1?i@@3HA@@YA?A?<auto>@@XZ
+; CHECK: <auto> __cdecl AutoFunc<&int i>(void)
+
+??$AutoFunc@$1?i@@3HA@@YA?A?<auto>@@XZ
+; CHECK: <auto> __cdecl AutoFunc<&int i>(void)
+
+??$AutoFunc@$MP6AHXZ1?Func@@YAHXZ@@YA?A?<auto>@@XZ
+; CHECK: <auto> __cdecl AutoFunc<&int __cdecl Func(void)>(void)
+
+??$AutoFunc@$1?Func@@YAHXZ@@YA?A?<auto>@@XZ
+; CHECK: <auto> __cdecl AutoFunc<&int __cdecl Func(void)>(void)

>From 8c9ba63934bd8efef66ea8ec43870e07c900b8d0 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Mon, 24 Jun 2024 18:37:12 -0700
Subject: [PATCH 2/4] Fix integer literals with auto nttp

---
 llvm/lib/Demangle/MicrosoftDemangle.cpp   | 57 +++++++++++++++--------
 llvm/test/Demangle/ms-auto-templates.test | 18 +++++++
 2 files changed, 55 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index 1c90c8553fb54..d0aafcc90d2d7 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -53,6 +53,24 @@ static bool consumeFront(std::string_view &S, std::string_view C) {
   return true;
 }
 
+static bool consumeFrontWithOrWithoutPrefix(std::string_view &S, std::string_view C, bool CheckWithout, size_t N) {
+    std::string_view CWithout = C.substr(N);
+    if (CheckWithout && llvm::itanium_demangle::starts_with(S, CWithout)) {
+        S.remove_prefix(CWithout.size());
+        return true;
+    }
+    if (!llvm::itanium_demangle::starts_with(S, C))
+        return false;
+    S.remove_prefix(C.size());
+    return true;
+}
+
+static bool startsWithOrWithoutPrefix(std::string_view S, std::string_view C, bool CheckWithout, size_t N) {
+  if (CheckWithout && llvm::itanium_demangle::starts_with(S, C.substr(N)))
+    return true;
+  return llvm::itanium_demangle::starts_with(S, C);
+}
+
 static bool isMemberPointer(std::string_view MangledName, bool &Error) {
   Error = false;
   const char F = MangledName.front();
@@ -2256,6 +2274,18 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
 
     NodeList &TP = **Current;
 
+    // <auto-nttp> ::= $ M <type> <nttp>
+    const bool IsAutoNTTP = consumeFront(MangledName, "$M");
+    if (IsAutoNTTP) {
+      // The deduced type of the auto NTTP parameter isn't printed so
+      // we want to ignore the AST created from demangling the type.
+      //
+      // TODO: Avoid the extra allocations to the bump allocator in this case.
+      (void)demangleType(MangledName, QualifierMangleMode::Drop);
+      if (Error)
+        return nullptr;
+    }
+
     TemplateParameterReferenceNode *TPRN = nullptr;
     if (consumeFront(MangledName, "$$Y")) {
       // Template alias
@@ -2266,29 +2296,16 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
     } else if (consumeFront(MangledName, "$$C")) {
       // Type has qualifiers.
       TP.N = demangleType(MangledName, QualifierMangleMode::Mangle);
-    } else if (llvm::itanium_demangle::starts_with(MangledName, "$1") ||
-               llvm::itanium_demangle::starts_with(MangledName, "$H") ||
-               llvm::itanium_demangle::starts_with(MangledName, "$I") ||
-               llvm::itanium_demangle::starts_with(MangledName, "$J") ||
-               llvm::itanium_demangle::starts_with(MangledName, "$M")) {
+    } else if (startsWithOrWithoutPrefix(MangledName, "$1", IsAutoNTTP, 1) ||
+               startsWithOrWithoutPrefix(MangledName, "$H", IsAutoNTTP, 1) ||
+               startsWithOrWithoutPrefix(MangledName, "$I", IsAutoNTTP, 1) ||
+               startsWithOrWithoutPrefix(MangledName, "$J", IsAutoNTTP, 1)) {
       // Pointer to member
       TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
       TPRN->IsMemberPointer = true;
 
-      MangledName.remove_prefix(1);
-
-      // <auto-nttp> ::= $ M <type> 1? <mangled-name>
-      if (llvm::itanium_demangle::starts_with(MangledName, 'M')) {
-        MangledName.remove_prefix(1);
-
-        // The deduced type of the auto NTTP parameter isn't printed so
-        // we want to ignore the AST created from demangling the type.
-        //
-        // TODO: Avoid the extra allocations to the bump allocator in this case.
-        (void)demangleType(MangledName, QualifierMangleMode::Drop);
-        if (Error)
-          return nullptr;
-      }
+      if (!IsAutoNTTP)
+          MangledName.remove_prefix(1); // Remove leading '$'
 
       // 1 - single inheritance       <name>
       // H - multiple inheritance     <name> <number>
@@ -2357,7 +2374,7 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
       }
       TPRN->IsMemberPointer = true;
 
-    } else if (consumeFront(MangledName, "$0")) {
+    } else if (consumeFrontWithOrWithoutPrefix(MangledName, "$0", IsAutoNTTP, 1)) {
       // Integral non-type template parameter
       bool IsNegative = false;
       uint64_t Value = 0;
diff --git a/llvm/test/Demangle/ms-auto-templates.test b/llvm/test/Demangle/ms-auto-templates.test
index 039c150b06d48..a90ffb69df558 100644
--- a/llvm/test/Demangle/ms-auto-templates.test
+++ b/llvm/test/Demangle/ms-auto-templates.test
@@ -37,3 +37,21 @@
 
 ??$AutoFunc@$1?Func@@YAHXZ@@YA?A?<auto>@@XZ
 ; CHECK: <auto> __cdecl AutoFunc<&int __cdecl Func(void)>(void)
+
+??$AutoFunc@$MH00@@YA?A?<auto>@@XZ
+; CHECK: <auto> __cdecl AutoFunc<1>(void)
+
+??$AutoFunc@$00@@YA?A?<auto>@@XZ
+; CHECK: <auto> __cdecl AutoFunc<1>(void)
+
+??0?$AutoNTTPClass@$0A@@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<0>::AutoNTTPClass<0>(void)
+
+??0?$AutoNTTPClass@$MH0A@@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<0>::AutoNTTPClass<0>(void)
+
+??0?$AutoNTTPClass@$0A@$0A@$0GB@@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<0, 0, 97>::AutoNTTPClass<0, 0, 97>(void)
+
+??0?$AutoNTTPClass@$MH0A@$M_N0A@$MD0GB@@@QEAA at XZ
+; CHECK: public: __cdecl AutoNTTPClass<0, 0, 97>::AutoNTTPClass<0, 0, 97>(void)

>From a9a489f7b116a8e74b0a4588dcda452604eb67a8 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Mon, 24 Jun 2024 21:32:19 -0700
Subject: [PATCH 3/4] formatting

---
 llvm/lib/Demangle/MicrosoftDemangle.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index d0aafcc90d2d7..12742185519e8 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -2305,7 +2305,7 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
       TPRN->IsMemberPointer = true;
 
       if (!IsAutoNTTP)
-          MangledName.remove_prefix(1); // Remove leading '$'
+        MangledName.remove_prefix(1); // Remove leading '$'
 
       // 1 - single inheritance       <name>
       // H - multiple inheritance     <name> <number>

>From 0fbc555c36c4bea3a81b1035aebe2db223881839 Mon Sep 17 00:00:00 2001
From: MaxEW707 <max.enrico.winkler at gmail.com>
Date: Mon, 24 Jun 2024 23:33:11 -0700
Subject: [PATCH 4/4] Change impl

---
 llvm/lib/Demangle/MicrosoftDemangle.cpp | 30 ++++++++++---------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp
index 12742185519e8..e2ab4ca1fbc69 100644
--- a/llvm/lib/Demangle/MicrosoftDemangle.cpp
+++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp
@@ -53,21 +53,15 @@ static bool consumeFront(std::string_view &S, std::string_view C) {
   return true;
 }
 
-static bool consumeFrontWithOrWithoutPrefix(std::string_view &S, std::string_view C, bool CheckWithout, size_t N) {
-    std::string_view CWithout = C.substr(N);
-    if (CheckWithout && llvm::itanium_demangle::starts_with(S, CWithout)) {
-        S.remove_prefix(CWithout.size());
-        return true;
-    }
-    if (!llvm::itanium_demangle::starts_with(S, C))
-        return false;
-    S.remove_prefix(C.size());
-    return true;
+static bool consumeFront(std::string_view &S, std::string_view CA,
+                         std::string_view CB, bool A) {
+  const std::string_view &C = A ? CA : CB;
+  return consumeFront(S, C);
 }
 
-static bool startsWithOrWithoutPrefix(std::string_view S, std::string_view C, bool CheckWithout, size_t N) {
-  if (CheckWithout && llvm::itanium_demangle::starts_with(S, C.substr(N)))
-    return true;
+static bool startsWith(std::string_view S, std::string_view CA,
+                       std::string_view CB, bool A) {
+  const std::string_view &C = A ? CA : CB;
   return llvm::itanium_demangle::starts_with(S, C);
 }
 
@@ -2296,10 +2290,10 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
     } else if (consumeFront(MangledName, "$$C")) {
       // Type has qualifiers.
       TP.N = demangleType(MangledName, QualifierMangleMode::Mangle);
-    } else if (startsWithOrWithoutPrefix(MangledName, "$1", IsAutoNTTP, 1) ||
-               startsWithOrWithoutPrefix(MangledName, "$H", IsAutoNTTP, 1) ||
-               startsWithOrWithoutPrefix(MangledName, "$I", IsAutoNTTP, 1) ||
-               startsWithOrWithoutPrefix(MangledName, "$J", IsAutoNTTP, 1)) {
+    } else if (startsWith(MangledName, "$1", "1", !IsAutoNTTP) ||
+               startsWith(MangledName, "$H", "H", !IsAutoNTTP) ||
+               startsWith(MangledName, "$I", "I", !IsAutoNTTP) ||
+               startsWith(MangledName, "$J", "J", !IsAutoNTTP)) {
       // Pointer to member
       TP.N = TPRN = Arena.alloc<TemplateParameterReferenceNode>();
       TPRN->IsMemberPointer = true;
@@ -2374,7 +2368,7 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) {
       }
       TPRN->IsMemberPointer = true;
 
-    } else if (consumeFrontWithOrWithoutPrefix(MangledName, "$0", IsAutoNTTP, 1)) {
+    } else if (consumeFront(MangledName, "$0", "0", !IsAutoNTTP)) {
       // Integral non-type template parameter
       bool IsNegative = false;
       uint64_t Value = 0;



More information about the llvm-commits mailing list