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,51 @@ +//===--- 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 D programming language as specified in the +/// ABI specification, available at: +/// https://dlang.org/spec/abi.html#name_mangling +/// +//===----------------------------------------------------------------------===// +// +// Ported from libiberty library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "llvm/Demangle/Utility.h" + +#include + +using namespace llvm; +using llvm::itanium_demangle::OutputString; + +char *llvm::dlangDemangle(const char *MangledName) { + OutputString Decl; + char *Demangled = nullptr; + + if (MangledName == nullptr || *MangledName == '\0') + return nullptr; + + if (strncmp(MangledName, "_D", 2) != 0) + return nullptr; + + initializeOutputString(nullptr, nullptr, Decl, 1024); + + if (strcmp(MangledName, "_Dmain") == 0) { + Decl << "D main"; + } + + if (Decl.getCurrentPosition() > 0) { + Decl << '\0'; + Decl.setCurrentPosition(Decl.getCurrentPosition() - 1); + Demangled = Decl.getBuffer(); + } + + return Demangled; +} 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 OutputStringTest.cpp PartialDemangleTest.cpp Index: llvm/unittests/Demangle/DLangDemangleTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Demangle/DLangDemangleTest.cpp @@ -0,0 +1,35 @@ +//===------------------ 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 +// +//===----------------------------------------------------------------------===// +// +// Testing input ported from libiberty library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Demangle/Demangle.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include +#include + +class DLangDemangleTestFixture + : public testing::TestWithParam> { +protected: + char *Demangled; + + virtual void SetUp() { Demangled = llvm::dlangDemangle(GetParam().first); } + + virtual void TearDown() { 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"))); Index: llvm/unittests/Demangle/DemangleTest.cpp =================================================================== --- llvm/unittests/Demangle/DemangleTest.cpp +++ llvm/unittests/Demangle/DemangleTest.cpp @@ -22,6 +22,7 @@ EXPECT_EQ(demangle("?foo@@YAXH@Z"), "void __cdecl foo(int)"); EXPECT_EQ(demangle("foo"), "foo"); EXPECT_EQ(demangle("_RNvC3foo3bar"), "foo::bar"); + EXPECT_EQ(demangle("_Dmain"), "D main"); EXPECT_EQ(demangle("__RNvC3foo3bar"), "foo::bar"); // Regression test for demangling of optional template-args for vendor