diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -280,17 +280,20 @@ class VendorExtQualType final : public Node { const Node *Ty; StringView Ext; + const Node *TA; public: - VendorExtQualType(const Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} - template void match(Fn F) const { F(Ty, Ext); } + template void match(Fn F) const { F(Ty, Ext, TA); } void printLeft(OutputStream &S) const override { Ty->print(S); S += " "; S += Ext; + if (TA != nullptr) + TA->print(S); } }; @@ -3680,8 +3683,6 @@ if (Qual.empty()) return nullptr; - // FIXME parse the optional here! - // extension ::= U # objc-type if (Qual.startsWith("objcproto")) { StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); @@ -3699,10 +3700,17 @@ return make(Child, Proto); } + Node *TA = nullptr; + if (look() == 'I') { + TA = getDerived().parseTemplateArgs(); + if (TA == nullptr) + return nullptr; + } + Node *Child = getDerived().parseQualifiedType(); if (Child == nullptr) return nullptr; - return make(Child, Qual); + return make(Child, Qual, TA); } Qualifiers Quals = parseCVQualifiers(); diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp --- a/libcxxabi/test/test_demangle.pass.cpp +++ b/libcxxabi/test/test_demangle.pass.cpp @@ -29843,6 +29843,10 @@ {"_Z1fIL4Enumn1EEvv", "void f<(Enum)-1>()"}, {"_ZN1A1gIiEEDTcldtptfpT1b1fIT_EEEv", "decltype(this->b.f()) A::g()"}, + + // Optional template-args for vendor extended type qualifier. + // See https://bugs.llvm.org/show_bug.cgi?id=48009. + {"_Z3fooILi79EEbU7_ExtIntIXT_EEi", "bool foo<79>(int _ExtInt<79>)"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -280,17 +280,20 @@ class VendorExtQualType final : public Node { const Node *Ty; StringView Ext; + const Node *TA; public: - VendorExtQualType(const Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + VendorExtQualType(const Node *Ty_, StringView Ext_, const Node *TA_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} - template void match(Fn F) const { F(Ty, Ext); } + template void match(Fn F) const { F(Ty, Ext, TA); } void printLeft(OutputStream &S) const override { Ty->print(S); S += " "; S += Ext; + if (TA != nullptr) + TA->print(S); } }; @@ -3680,8 +3683,6 @@ if (Qual.empty()) return nullptr; - // FIXME parse the optional here! - // extension ::= U # objc-type if (Qual.startsWith("objcproto")) { StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); @@ -3699,10 +3700,17 @@ return make(Child, Proto); } + Node *TA = nullptr; + if (look() == 'I') { + TA = getDerived().parseTemplateArgs(); + if (TA == nullptr) + return nullptr; + } + Node *Child = getDerived().parseQualifiedType(); if (Child == nullptr) return nullptr; - return make(Child, Qual); + return make(Child, Qual, TA); } Qualifiers Quals = parseCVQualifiers(); diff --git a/llvm/unittests/Demangle/DemangleTest.cpp b/llvm/unittests/Demangle/DemangleTest.cpp --- a/llvm/unittests/Demangle/DemangleTest.cpp +++ b/llvm/unittests/Demangle/DemangleTest.cpp @@ -21,4 +21,9 @@ "invocation function for block in foo(int)"); EXPECT_EQ(demangle("?foo@@YAXH@Z"), "void __cdecl foo(int)"); EXPECT_EQ(demangle("foo"), "foo"); + + // Regression test for demangling of optional template-args for vendor + // extended type qualifier (https://bugs.llvm.org/show_bug.cgi?id=48009) + EXPECT_EQ(demangle("_Z3fooILi79EEbU7_ExtIntIXT_EEi"), + "bool foo<79>(int _ExtInt<79>)"); }