Index: llvm/include/llvm/Demangle/Demangle.h =================================================================== --- llvm/include/llvm/Demangle/Demangle.h +++ llvm/include/llvm/Demangle/Demangle.h @@ -60,6 +60,9 @@ // Demangles a Rust v0 mangled symbol. The API follows that of __cxa_demangle. char *rustDemangle(const char *MangledName, char *Buf, size_t *N, int *Status); +// Demangles a D mangled symbol. +char *dlangDemangle(const char *MangledName); + /// Attempt to demangle a string using different demangling schemes. /// The function uses heuristics to determine which demangling scheme to use. /// \param MangledName - reference to string to demangle. Index: llvm/lib/Demangle/CMakeLists.txt =================================================================== --- llvm/lib/Demangle/CMakeLists.txt +++ llvm/lib/Demangle/CMakeLists.txt @@ -4,6 +4,7 @@ MicrosoftDemangle.cpp MicrosoftDemangleNodes.cpp RustDemangle.cpp + DLangDemangle.cpp ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/Demangle" Index: llvm/lib/Demangle/DLangDemangle.cpp =================================================================== --- /dev/null +++ llvm/lib/Demangle/DLangDemangle.cpp @@ -0,0 +1,48 @@ +//===--- DLangDemangle.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines a demangler for the D programming language as specified +/// in the ABI specification, available at: +/// https://dlang.org/spec/abi.html#name_mangling +/// +//===----------------------------------------------------------------------===// +// +// Ported from the libiberty library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/Utility.h" + +#include + +using namespace llvm; +using llvm::itanium_demangle::OutputBuffer; + +char *llvm::dlangDemangle(const char *MangledName) { + if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0) + return nullptr; + + OutputBuffer Demangled; + if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024)) + return nullptr; + + if (strcmp(MangledName, "_Dmain") == 0) + Demangled << "D main"; + + // OutputBuffer's internal buffer is not null terminated and therefore we need + // to add it to comply with C null terminated strings. + if (Demangled.getCurrentPosition() > 0) { + Demangled << '\0'; + Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1); + return Demangled.getBuffer(); + } + + return nullptr; +} Index: llvm/lib/Demangle/Demangle.cpp =================================================================== --- llvm/lib/Demangle/Demangle.cpp +++ llvm/lib/Demangle/Demangle.cpp @@ -21,6 +21,11 @@ static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; } +static bool isDLangEncoding(const std::string &MangledName) { + return MangledName.size() >= 2 && MangledName[0] == '_' && + MangledName[1] == 'D'; +} + std::string llvm::demangle(const std::string &MangledName) { std::string Result; const char *S = MangledName.c_str(); @@ -47,6 +52,8 @@ Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr); else if (isRustEncoding(MangledName)) Demangled = rustDemangle(MangledName, nullptr, nullptr, nullptr); + else if (isDLangEncoding(MangledName)) + Demangled = dlangDemangle(MangledName); if (!Demangled) return false; Index: llvm/test/Demangle/dlang.test =================================================================== --- /dev/null +++ llvm/test/Demangle/dlang.test @@ -0,0 +1,10 @@ +RUN: llvm-cxxfilt -n < %s | FileCheck --match-full-lines %s + +; Full test suite for dlang demangling at +; llvm/unittests/Demangle/DLangDemangleTest.cpp + +CHECK: D main + _Dmain + +CHECK: _DDD + _DDD Index: llvm/unittests/Demangle/CMakeLists.txt =================================================================== --- llvm/unittests/Demangle/CMakeLists.txt +++ llvm/unittests/Demangle/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_unittest(DemangleTests DemangleTest.cpp + DLangDemangleTest.cpp ItaniumDemangleTest.cpp OutputBufferTest.cpp PartialDemangleTest.cpp Index: llvm/unittests/Demangle/DLangDemangleTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -0,0 +1,33 @@ +//===------------------ DLangDemangleTest.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include + +struct DLangDemangleTestFixture + : public testing::TestWithParam> { + char *Demangled; + + void SetUp() override { Demangled = llvm::dlangDemangle(GetParam().first); } + + void TearDown() override { std::free(Demangled); } +}; + +TEST_P(DLangDemangleTestFixture, DLangDemangleTest) { + EXPECT_STREQ(Demangled, GetParam().second); +} + +INSTANTIATE_TEST_SUITE_P(DLangDemangleTest, DLangDemangleTestFixture, + testing::Values(std::make_pair("_Dmain", "D main"), + std::make_pair(nullptr, nullptr), + std::make_pair("_Z", nullptr), + std::make_pair("_DDD", nullptr))); Index: llvm/unittests/Demangle/DemangleTest.cpp =================================================================== --- llvm/unittests/Demangle/DemangleTest.cpp +++ llvm/unittests/Demangle/DemangleTest.cpp @@ -23,6 +23,7 @@ EXPECT_EQ(demangle("foo"), "foo"); EXPECT_EQ(demangle("_RNvC3foo3bar"), "foo::bar"); EXPECT_EQ(demangle("__RNvC3foo3bar"), "foo::bar"); + EXPECT_EQ(demangle("_Dmain"), "D main"); // Regression test for demangling of optional template-args for vendor // extended type qualifier (https://bugs.llvm.org/show_bug.cgi?id=48009)