From bec968cbb367dd03439c89c1d4ef968ef662d7c0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 22 Oct 2020 19:29:36 -0700 Subject: [PATCH] Demangling support for class type non-type template parameter extensions. The extensions in question are described in: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 https://github.com/itanium-cxx-abi/cxx-abi/issues/63 Differential Revision: https://reviews.llvm.org/D90003 --- libcxxabi/src/demangle/ItaniumDemangle.h | 120 +++++++++++++++++++++++++++ libcxxabi/test/test_demangle.pass.cpp | 15 ++++ llvm/include/llvm/Demangle/ItaniumDemangle.h | 120 +++++++++++++++++++++++++++ 3 files changed, 255 insertions(+) diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index fd6e5cf..6bfc02d 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -82,6 +82,7 @@ X(PostfixExpr) \ X(ConditionalExpr) \ X(MemberExpr) \ + X(SubobjectExpr) \ X(EnclosingExpr) \ X(CastExpr) \ X(SizeofParamPackExpr) \ @@ -91,6 +92,7 @@ X(PrefixExpr) \ X(FunctionParam) \ X(ConversionExpr) \ + X(PointerToMemberConversionExpr) \ X(InitListExpr) \ X(FoldExpr) \ X(ThrowExpr) \ @@ -1656,6 +1658,40 @@ public: } }; +class SubobjectExpr : public Node { + const Node *Type; + const Node *SubExpr; + StringView Offset; + NodeArray UnionSelectors; + bool OnePastTheEnd; + +public: + SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_, + NodeArray UnionSelectors_, bool OnePastTheEnd_) + : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), + UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} + + template void match(Fn F) const { + F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); + } + + void printLeft(OutputStream &S) const override { + SubExpr->print(S); + S += ".<"; + Type->print(S); + S += " at offset "; + if (Offset.empty()) { + S += "0"; + } else if (Offset[0] == 'n') { + S += "-"; + S += Offset.dropFront(); + } else { + S += Offset; + } + S += ">"; + } +}; + class EnclosingExpr : public Node { const StringView Prefix; const Node *Infix; @@ -1843,6 +1879,28 @@ public: } }; +class PointerToMemberConversionExpr : public Node { + const Node *Type; + const Node *SubExpr; + StringView Offset; + +public: + PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, + StringView Offset_) + : Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_), + Offset(Offset_) {} + + template void match(Fn F) const { F(Type, SubExpr, Offset); } + + void printLeft(OutputStream &S) const override { + S += "("; + Type->print(S); + S += ")("; + SubExpr->print(S); + S += ")"; + } +}; + class InitListExpr : public Node { const Node *Ty; NodeArray Inits; @@ -2437,6 +2495,8 @@ template struct AbstractManglingParser { Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); + Node *parsePointerToMemberConversionExpr(); + Node *parseSubobjectExpr(); /// Parse the production. Node *parseType(); @@ -4404,6 +4464,50 @@ Node *AbstractManglingParser::parseFoldExpr() { return make(IsLeftFold, OperatorName, Pack, Init); } +// ::= mc [] E +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node *AbstractManglingParser::parsePointerToMemberConversionExpr() { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + StringView Offset = getDerived().parseNumber(true); + if (!consumeIf('E')) + return nullptr; + return make(Ty, Expr, Offset); +} + +// ::= so [] * [p] E +// ::= _ [] +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node *AbstractManglingParser::parseSubobjectExpr() { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + StringView Offset = getDerived().parseNumber(true); + size_t SelectorsBegin = Names.size(); + while (consumeIf('_')) { + Node *Selector = make(parseNumber()); + if (!Selector) + return nullptr; + Names.push_back(Selector); + } + bool OnePastTheEnd = consumeIf('p'); + if (!consumeIf('E')) + return nullptr; + return make( + Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); +} + // ::= // ::= // ::= @@ -4661,6 +4765,9 @@ Node *AbstractManglingParser::parseExpr() { return nullptr; case 'm': switch (First[1]) { + case 'c': + First += 2; + return parsePointerToMemberConversionExpr(); case 'i': First += 2; return getDerived().parseBinaryExpr("-"); @@ -4808,6 +4915,9 @@ Node *AbstractManglingParser::parseExpr() { return Ex; return make("static_cast", T, Ex); } + case 'o': + First += 2; + return parseSubobjectExpr(); case 'p': { First += 2; Node *Child = getDerived().parseExpr(); @@ -4975,6 +5085,16 @@ Node *AbstractManglingParser::parseSpecialName() { switch (look()) { case 'T': switch (look(1)) { + // TA # template parameter object + // + // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63 + case 'A': { + First += 2; + Node *Arg = getDerived().parseTemplateArg(); + if (Arg == nullptr) + return nullptr; + return make("template parameter object for ", Arg); + } // TV # virtual table case 'V': { First += 2; diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp index cbbccb1..3954fdb 100644 --- a/libcxxabi/test/test_demangle.pass.cpp +++ b/libcxxabi/test/test_demangle.pass.cpp @@ -29800,6 +29800,21 @@ const char* cases[][2] = {"_ZN1XIZ1fIiEvOT_EUlS2_DpT0_E_EclIJEEEvDpT_", "void X(int&&)::'lambda'(int&&, auto...)>::operator()<>()"}, {"_ZZZZN6abcdef9abcdefghi29abcdefabcdefabcdefabcefabcdef27xxxxxxxxxxxxxxxxxxxxxxxxxxxEN4absl8DurationERKNSt3__u12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPNS1_19yyyyyyyyyyyyyyyyyyyEENK3$_5clEvENKUlvE_clEvE6zzzzzz", "abcdef::abcdefghi::abcdefabcdefabcdefabcefabcdef::xxxxxxxxxxxxxxxxxxxxxxxxxxx(absl::Duration, std::__u::basic_string, std::__u::allocator > const&, abcdef::abcdefghi::abcdefabcdefabcdefabcefabcdef::yyyyyyyyyyyyyyyyyyy*)::$_5::operator()() const::'lambda'()::operator()() const::zzzzzz"}, + // C++2a class type non-type template parameters: + {"_Z1fIXtl1BLPi0ELi1EEEEvv", "void f()"}, + {"_Z1fIXtl1BLPi32EEEEvv", "void f()"}, + {"_Z1fIXtl1BrcPiLi0EEEEvv", "void f(0)}>()"}, + {"_Z1fIXtl1BadsoiL_Z6nestedE_EEEEvv", "void f)}>()"}, + {"_Z1fIXtl1BadsoiL_Z6nestedE16_0pEEEEvv", "void f)}>()"}, + {"_Z1fIXtl2BRsoiL_Z7derivedE4EEEEvv", "void f}>()"}, + {"_Z1fIXtl1BcvPiplcvPcadL_Z7derivedELl16EEEEvv", "void f()"}, + {"_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv", "void f)}>()"}, + {"_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv", "void f()"}, + // FIXME: This is not valid pointer-to-member syntax. + {"_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv", "void f()"}, + {"_Z1fIXtl1Edi1nLi42EEEEvv", "void f()"}, + {"_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE", "template parameter object for S{char [32]{(char)104, (char)101, (char)108, (char)108, (char)111, (char)32, (char)119, (char)111, (char)114, (char)108, (char)100}}"}, + // FIXME: This is wrong; the S2_ backref should expand to OT_ and then to // "double&&". But we can't cope with a substitution that represents a // different type the node it is a substitute for. diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index ede9c6d..cef6175 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -82,6 +82,7 @@ X(PostfixExpr) \ X(ConditionalExpr) \ X(MemberExpr) \ + X(SubobjectExpr) \ X(EnclosingExpr) \ X(CastExpr) \ X(SizeofParamPackExpr) \ @@ -91,6 +92,7 @@ X(PrefixExpr) \ X(FunctionParam) \ X(ConversionExpr) \ + X(PointerToMemberConversionExpr) \ X(InitListExpr) \ X(FoldExpr) \ X(ThrowExpr) \ @@ -1656,6 +1658,40 @@ public: } }; +class SubobjectExpr : public Node { + const Node *Type; + const Node *SubExpr; + StringView Offset; + NodeArray UnionSelectors; + bool OnePastTheEnd; + +public: + SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_, + NodeArray UnionSelectors_, bool OnePastTheEnd_) + : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), + UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} + + template void match(Fn F) const { + F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); + } + + void printLeft(OutputStream &S) const override { + SubExpr->print(S); + S += ".<"; + Type->print(S); + S += " at offset "; + if (Offset.empty()) { + S += "0"; + } else if (Offset[0] == 'n') { + S += "-"; + S += Offset.dropFront(); + } else { + S += Offset; + } + S += ">"; + } +}; + class EnclosingExpr : public Node { const StringView Prefix; const Node *Infix; @@ -1843,6 +1879,28 @@ public: } }; +class PointerToMemberConversionExpr : public Node { + const Node *Type; + const Node *SubExpr; + StringView Offset; + +public: + PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, + StringView Offset_) + : Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_), + Offset(Offset_) {} + + template void match(Fn F) const { F(Type, SubExpr, Offset); } + + void printLeft(OutputStream &S) const override { + S += "("; + Type->print(S); + S += ")("; + SubExpr->print(S); + S += ")"; + } +}; + class InitListExpr : public Node { const Node *Ty; NodeArray Inits; @@ -2437,6 +2495,8 @@ template struct AbstractManglingParser { Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); + Node *parsePointerToMemberConversionExpr(); + Node *parseSubobjectExpr(); /// Parse the production. Node *parseType(); @@ -4404,6 +4464,50 @@ Node *AbstractManglingParser::parseFoldExpr() { return make(IsLeftFold, OperatorName, Pack, Init); } +// ::= mc [] E +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node *AbstractManglingParser::parsePointerToMemberConversionExpr() { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + StringView Offset = getDerived().parseNumber(true); + if (!consumeIf('E')) + return nullptr; + return make(Ty, Expr, Offset); +} + +// ::= so [] * [p] E +// ::= _ [] +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template +Node *AbstractManglingParser::parseSubobjectExpr() { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + StringView Offset = getDerived().parseNumber(true); + size_t SelectorsBegin = Names.size(); + while (consumeIf('_')) { + Node *Selector = make(parseNumber()); + if (!Selector) + return nullptr; + Names.push_back(Selector); + } + bool OnePastTheEnd = consumeIf('p'); + if (!consumeIf('E')) + return nullptr; + return make( + Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); +} + // ::= // ::= // ::= @@ -4661,6 +4765,9 @@ Node *AbstractManglingParser::parseExpr() { return nullptr; case 'm': switch (First[1]) { + case 'c': + First += 2; + return parsePointerToMemberConversionExpr(); case 'i': First += 2; return getDerived().parseBinaryExpr("-"); @@ -4808,6 +4915,9 @@ Node *AbstractManglingParser::parseExpr() { return Ex; return make("static_cast", T, Ex); } + case 'o': + First += 2; + return parseSubobjectExpr(); case 'p': { First += 2; Node *Child = getDerived().parseExpr(); @@ -4975,6 +5085,16 @@ Node *AbstractManglingParser::parseSpecialName() { switch (look()) { case 'T': switch (look(1)) { + // TA # template parameter object + // + // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63 + case 'A': { + First += 2; + Node *Arg = getDerived().parseTemplateArg(); + if (Arg == nullptr) + return nullptr; + return make("template parameter object for ", Arg); + } // TV # virtual table case 'V': { First += 2; -- 2.7.4