[llvm] [Demangle] Implement type D demangling and add all D basic type encodings (PR #202834)

Luís Ferreira via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 9 19:45:59 PDT 2026


https://github.com/ljmf00 updated https://github.com/llvm/llvm-project/pull/202834

>From 05e5f5dbc408603f91b2cf69269c91957ebec06f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lu=C3=ADs=20Ferreira?= <contact at lsferreira.net>
Date: Thu, 4 Jun 2026 01:37:18 +0000
Subject: [PATCH] [Demangle] Implement type D demangling and add all D basic
 type encodings
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch adds type name output to D demangler `parseType` and adds all
D basic type encodings to it.

Signed-off-by: Luís Ferreira <contact at lsferreira.net>
---
 llvm/lib/Demangle/DLangDemangle.cpp           | 148 ++++++++++++++++--
 llvm/unittests/Demangle/DLangDemangleTest.cpp |  49 ++++--
 2 files changed, 175 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Demangle/DLangDemangle.cpp b/llvm/lib/Demangle/DLangDemangle.cpp
index 8856302be6dd1..a3473f80f2c37 100644
--- a/llvm/lib/Demangle/DLangDemangle.cpp
+++ b/llvm/lib/Demangle/DLangDemangle.cpp
@@ -107,7 +107,7 @@ struct Demangler {
   ///
   /// \see https://dlang.org/spec/abi.html#back_ref .
   /// \see https://dlang.org/spec/abi.html#TypeBackRef .
-  void parseTypeBackref(std::string_view &Mangled);
+  void parseTypeBackref(OutputBuffer *Demangled, std::string_view &Mangled);
 
   /// Check whether it is the beginning of a symbol name.
   ///
@@ -156,7 +156,7 @@ struct Demangler {
   /// \return true on success, false on error.
   ///
   /// \see https://dlang.org/spec/abi.html#Type .
-  bool parseType(std::string_view &Mangled);
+  bool parseType(OutputBuffer *Demangled, std::string_view &Mangled);
 
   /// An immutable view of the string we are demangling.
   const std::string_view Str;
@@ -297,7 +297,8 @@ void Demangler::parseSymbolBackref(OutputBuffer *Demangled,
     Mangled = {};
 }
 
-void Demangler::parseTypeBackref(std::string_view &Mangled) {
+void Demangler::parseTypeBackref(OutputBuffer *Demangled,
+                                 std::string_view &Mangled) {
   // A type back reference always points to a letter.
   //    TypeBackRef:
   //        Q NumberBackRef
@@ -327,7 +328,7 @@ void Demangler::parseTypeBackref(std::string_view &Mangled) {
   }
 
   // TODO: Add support for function type back references.
-  if (!parseType(Backref))
+  if (!parseType(Demangled, Backref))
     Mangled = {};
 
   LastBackref = SaveRefPos;
@@ -379,8 +380,19 @@ void Demangler::parseMangle(OutputBuffer *Demangled,
   // Artificial symbols end with 'Z' and have no type.
   if (Mangled.front() == 'Z') {
     Mangled.remove_prefix(1);
-  } else if (!parseType(Mangled))
-    Mangled = {};
+  } else {
+    OutputBuffer TypeBuf;
+    if (!parseType(&TypeBuf, Mangled))
+      Mangled = {};
+    else {
+      // Insert type before the symbol name that was already appended.
+      size_t TypeLen = TypeBuf.getCurrentPosition();
+      if (TypeLen > 0) {
+        Demangled->insert(0, TypeBuf.getBuffer(), TypeLen);
+        Demangled->insert(TypeLen, " ", 1);
+      }
+    }
+  }
 }
 
 void Demangler::parseQualified(OutputBuffer *Demangled,
@@ -465,7 +477,7 @@ void Demangler::parseIdentifier(OutputBuffer *Demangled,
   parseLName(Demangled, Mangled, Len);
 }
 
-bool Demangler::parseType(std::string_view &Mangled) {
+bool Demangler::parseType(OutputBuffer *Demangled, std::string_view &Mangled) {
   if (Mangled.empty()) {
     Mangled = {};
     return false;
@@ -481,14 +493,130 @@ bool Demangler::parseType(std::string_view &Mangled) {
   // Basic types.
   case 'i':
     Mangled.remove_prefix(1);
-    // TODO: Add type name dumping
+    *Demangled << "int";
+    return true;
+
+  case 'v':
+    Mangled.remove_prefix(1);
+    *Demangled << "void";
     return true;
 
-    // TODO: Add support for the rest of the basic types.
+  case 'a':
+    Mangled.remove_prefix(1);
+    *Demangled << "char";
+    return true;
+  case 'b':
+    Mangled.remove_prefix(1);
+    *Demangled << "bool";
+    return true;
+  case 'c':
+    Mangled.remove_prefix(1);
+    *Demangled << "creal";
+    return true;
+  case 'd':
+    Mangled.remove_prefix(1);
+    *Demangled << "double";
+    return true;
+  case 'e':
+    Mangled.remove_prefix(1);
+    *Demangled << "real";
+    return true;
+  case 'f':
+    Mangled.remove_prefix(1);
+    *Demangled << "float";
+    return true;
+  case 'g':
+    Mangled.remove_prefix(1);
+    *Demangled << "byte";
+    return true;
+  case 'h':
+    Mangled.remove_prefix(1);
+    *Demangled << "ubyte";
+    return true;
+  case 'j':
+    Mangled.remove_prefix(1);
+    *Demangled << "ireal";
+    return true;
+  case 'k':
+    Mangled.remove_prefix(1);
+    *Demangled << "uint";
+    return true;
+  case 'l':
+    Mangled.remove_prefix(1);
+    *Demangled << "long";
+    return true;
+  case 'm':
+    Mangled.remove_prefix(1);
+    *Demangled << "ulong";
+    return true;
+  case 'n':
+    Mangled.remove_prefix(1);
+    return true; // typeof(null), no output
+  case 'o':
+    Mangled.remove_prefix(1);
+    *Demangled << "ifloat";
+    return true;
+  case 'p':
+    Mangled.remove_prefix(1);
+    *Demangled << "idouble";
+    return true;
+  case 'q':
+    Mangled.remove_prefix(1);
+    *Demangled << "cfloat";
+    return true;
+  case 'r':
+    Mangled.remove_prefix(1);
+    *Demangled << "cdouble";
+    return true;
+  case 's':
+    Mangled.remove_prefix(1);
+    *Demangled << "short";
+    return true;
+  case 't':
+    Mangled.remove_prefix(1);
+    *Demangled << "ushort";
+    return true;
+  case 'u':
+    Mangled.remove_prefix(1);
+    *Demangled << "wchar";
+    return true;
+  case 'w':
+    Mangled.remove_prefix(1);
+    *Demangled << "dchar";
+    return true;
+  case 'z': // two-char: zi=cent, zk=ucent
+    if (Mangled.size() < 2) {
+      Mangled = {};
+      return false;
+    }
+    if (Mangled[1] == 'i') {
+      Mangled.remove_prefix(2);
+      *Demangled << "cent";
+      return true;
+    }
+    if (Mangled[1] == 'k') {
+      Mangled.remove_prefix(2);
+      *Demangled << "ucent";
+      return true;
+    }
+    Mangled = {};
+    return false;
+  case 'N':
+    if (Mangled.size() < 2) {
+      Mangled = {};
+      return false;
+    }
+    if (Mangled[1] == 'n') {
+      Mangled.remove_prefix(2);
+      *Demangled << "noreturn";
+      return true;
+    }
+    Mangled = {};
+    return false;
 
   // Back referenced type.
   case 'Q': {
-    parseTypeBackref(Mangled);
+    parseTypeBackref(Demangled, Mangled);
     return true;
   }
 
diff --git a/llvm/unittests/Demangle/DLangDemangleTest.cpp b/llvm/unittests/Demangle/DLangDemangleTest.cpp
index 1322f530e5963..3aea8e23e039a 100644
--- a/llvm/unittests/Demangle/DLangDemangleTest.cpp
+++ b/llvm/unittests/Demangle/DLangDemangleTest.cpp
@@ -48,28 +48,53 @@ INSTANTIATE_TEST_SUITE_P(
                        "ModuleInfo for demangle.test"),
         std::make_pair("_D8demangle4__S14testZ", "demangle.test"),
         std::make_pair("_D8demangle4__Sd4testZ", "demangle.__Sd.test"),
-        std::make_pair("_D8demangle3fooi", "demangle.foo"),
+        std::make_pair("_D8demangle3fooi", "int demangle.foo"),
+        std::make_pair("_D8demangle3foov", "void demangle.foo"),
         std::make_pair("_D8demangle3foo",
                        nullptr), // symbol without a type sequence.
         std::make_pair("_D8demangle3fooinvalidtypeseq",
                        nullptr), // invalid type sequence.
         std::make_pair(
             "_D8demangle3ABCQe1ai",
-            "demangle.ABC.ABC.a"), // symbol back reference: `Qe` is a back
-                                   // reference for position 5, counting from e
-                                   // char, so decoding it points to `3`. Since
-                                   // `3` is a number, 3 chars get read and it
-                                   // succeeded.
+            "int demangle.ABC.ABC.a"), // symbol back reference: `Qe` is a back
         std::make_pair("_D8demangle3ABCQa1ai",
                        nullptr), // invalid symbol back reference (recursive).
         std::make_pair("_D8demangleQDXXXXXXXXXXXXx",
                        nullptr), // overflow back reference position.
-        std::make_pair(
-            "_D8demangle4ABCi1aQd",
-            "demangle.ABCi.a"), // type back reference: `Qd` is a back reference
-                                // for position 4, counting from `d` char, so
-                                // decoding it points to `i`.
+        std::make_pair("_D8demangle4ABCi1aQd",
+                       "int demangle.ABCi.a"), // type back reference: `Qd` is a
+                                               // back reference
         std::make_pair("_D8demangle3fooQXXXx",
                        nullptr), // invalid type back reference position.
         std::make_pair("_D8demangle5recurQa",
-                       nullptr))); // invalid type back reference (recursive).
+                       nullptr), // invalid type back reference (recursive).
+        // Basic types.
+        std::make_pair("_D8demangle3fooa", "char demangle.foo"),
+        std::make_pair("_D8demangle3foob", "bool demangle.foo"),
+        std::make_pair("_D8demangle3fooc", "creal demangle.foo"),
+        std::make_pair("_D8demangle3food", "double demangle.foo"),
+        std::make_pair("_D8demangle3fooe", "real demangle.foo"),
+        std::make_pair("_D8demangle3foof", "float demangle.foo"),
+        std::make_pair("_D8demangle3foog", "byte demangle.foo"),
+        std::make_pair("_D8demangle3fooh", "ubyte demangle.foo"),
+        std::make_pair("_D8demangle3fooj", "ireal demangle.foo"),
+        std::make_pair("_D8demangle3fook", "uint demangle.foo"),
+        std::make_pair("_D8demangle3fool", "long demangle.foo"),
+        std::make_pair("_D8demangle3foom", "ulong demangle.foo"),
+        std::make_pair("_D8demangle3foon", "demangle.foo"),
+        std::make_pair("_D8demangle3fooo", "ifloat demangle.foo"),
+        std::make_pair("_D8demangle3foop", "idouble demangle.foo"),
+        std::make_pair("_D8demangle3fooq", "cfloat demangle.foo"),
+        std::make_pair("_D8demangle3foor", "cdouble demangle.foo"),
+        std::make_pair("_D8demangle3foos", "short demangle.foo"),
+        std::make_pair("_D8demangle3foot", "ushort demangle.foo"),
+        std::make_pair("_D8demangle3foou", "wchar demangle.foo"),
+        std::make_pair("_D8demangle3foow", "dchar demangle.foo"),
+        std::make_pair("_D8demangle3foozi", "cent demangle.foo"),
+        std::make_pair("_D8demangle3foozk", "ucent demangle.foo"),
+        std::make_pair("_D8demangle3fooNn", "noreturn demangle.foo"),
+        // Garbage suffix failures.
+        std::make_pair("_D8demangle3fooiabc", nullptr),
+        std::make_pair("_D8demangle3foovxxx", nullptr),
+        std::make_pair("_D8demangle3fooza", nullptr),
+        std::make_pair("_D8demangle3fooNx", nullptr)));



More information about the llvm-commits mailing list