[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