Skip to content

Commit bec968c

Browse files
committed
Demangling support for class type non-type template parameter extensions.
The extensions in question are described in: itanium-cxx-abi/cxx-abi#47 itanium-cxx-abi/cxx-abi#63 Differential Revision: https://reviews.llvm.org/D90003
1 parent 0b420d6 commit bec968c

File tree

3 files changed

+255
-0
lines changed

3 files changed

+255
-0
lines changed

libcxxabi/src/demangle/ItaniumDemangle.h

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
X(PostfixExpr) \
8383
X(ConditionalExpr) \
8484
X(MemberExpr) \
85+
X(SubobjectExpr) \
8586
X(EnclosingExpr) \
8687
X(CastExpr) \
8788
X(SizeofParamPackExpr) \
@@ -91,6 +92,7 @@
9192
X(PrefixExpr) \
9293
X(FunctionParam) \
9394
X(ConversionExpr) \
95+
X(PointerToMemberConversionExpr) \
9496
X(InitListExpr) \
9597
X(FoldExpr) \
9698
X(ThrowExpr) \
@@ -1656,6 +1658,40 @@ class MemberExpr : public Node {
16561658
}
16571659
};
16581660

1661+
class SubobjectExpr : public Node {
1662+
const Node *Type;
1663+
const Node *SubExpr;
1664+
StringView Offset;
1665+
NodeArray UnionSelectors;
1666+
bool OnePastTheEnd;
1667+
1668+
public:
1669+
SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_,
1670+
NodeArray UnionSelectors_, bool OnePastTheEnd_)
1671+
: Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_),
1672+
UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {}
1673+
1674+
template<typename Fn> void match(Fn F) const {
1675+
F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd);
1676+
}
1677+
1678+
void printLeft(OutputStream &S) const override {
1679+
SubExpr->print(S);
1680+
S += ".<";
1681+
Type->print(S);
1682+
S += " at offset ";
1683+
if (Offset.empty()) {
1684+
S += "0";
1685+
} else if (Offset[0] == 'n') {
1686+
S += "-";
1687+
S += Offset.dropFront();
1688+
} else {
1689+
S += Offset;
1690+
}
1691+
S += ">";
1692+
}
1693+
};
1694+
16591695
class EnclosingExpr : public Node {
16601696
const StringView Prefix;
16611697
const Node *Infix;
@@ -1843,6 +1879,28 @@ class ConversionExpr : public Node {
18431879
}
18441880
};
18451881

1882+
class PointerToMemberConversionExpr : public Node {
1883+
const Node *Type;
1884+
const Node *SubExpr;
1885+
StringView Offset;
1886+
1887+
public:
1888+
PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_,
1889+
StringView Offset_)
1890+
: Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_),
1891+
Offset(Offset_) {}
1892+
1893+
template<typename Fn> void match(Fn F) const { F(Type, SubExpr, Offset); }
1894+
1895+
void printLeft(OutputStream &S) const override {
1896+
S += "(";
1897+
Type->print(S);
1898+
S += ")(";
1899+
SubExpr->print(S);
1900+
S += ")";
1901+
}
1902+
};
1903+
18461904
class InitListExpr : public Node {
18471905
const Node *Ty;
18481906
NodeArray Inits;
@@ -2437,6 +2495,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
24372495
Node *parseConversionExpr();
24382496
Node *parseBracedExpr();
24392497
Node *parseFoldExpr();
2498+
Node *parsePointerToMemberConversionExpr();
2499+
Node *parseSubobjectExpr();
24402500

24412501
/// Parse the <type> production.
24422502
Node *parseType();
@@ -4404,6 +4464,50 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
44044464
return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
44054465
}
44064466

4467+
// <expression> ::= mc <parameter type> <expr> [<offset number>] E
4468+
//
4469+
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
4470+
template <typename Derived, typename Alloc>
4471+
Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr() {
4472+
Node *Ty = getDerived().parseType();
4473+
if (!Ty)
4474+
return nullptr;
4475+
Node *Expr = getDerived().parseExpr();
4476+
if (!Expr)
4477+
return nullptr;
4478+
StringView Offset = getDerived().parseNumber(true);
4479+
if (!consumeIf('E'))
4480+
return nullptr;
4481+
return make<PointerToMemberConversionExpr>(Ty, Expr, Offset);
4482+
}
4483+
4484+
// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
4485+
// <union-selector> ::= _ [<number>]
4486+
//
4487+
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
4488+
template <typename Derived, typename Alloc>
4489+
Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
4490+
Node *Ty = getDerived().parseType();
4491+
if (!Ty)
4492+
return nullptr;
4493+
Node *Expr = getDerived().parseExpr();
4494+
if (!Expr)
4495+
return nullptr;
4496+
StringView Offset = getDerived().parseNumber(true);
4497+
size_t SelectorsBegin = Names.size();
4498+
while (consumeIf('_')) {
4499+
Node *Selector = make<NameType>(parseNumber());
4500+
if (!Selector)
4501+
return nullptr;
4502+
Names.push_back(Selector);
4503+
}
4504+
bool OnePastTheEnd = consumeIf('p');
4505+
if (!consumeIf('E'))
4506+
return nullptr;
4507+
return make<SubobjectExpr>(
4508+
Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
4509+
}
4510+
44074511
// <expression> ::= <unary operator-name> <expression>
44084512
// ::= <binary operator-name> <expression> <expression>
44094513
// ::= <ternary operator-name> <expression> <expression> <expression>
@@ -4661,6 +4765,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
46614765
return nullptr;
46624766
case 'm':
46634767
switch (First[1]) {
4768+
case 'c':
4769+
First += 2;
4770+
return parsePointerToMemberConversionExpr();
46644771
case 'i':
46654772
First += 2;
46664773
return getDerived().parseBinaryExpr("-");
@@ -4808,6 +4915,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
48084915
return Ex;
48094916
return make<CastExpr>("static_cast", T, Ex);
48104917
}
4918+
case 'o':
4919+
First += 2;
4920+
return parseSubobjectExpr();
48114921
case 'p': {
48124922
First += 2;
48134923
Node *Child = getDerived().parseExpr();
@@ -4975,6 +5085,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
49755085
switch (look()) {
49765086
case 'T':
49775087
switch (look(1)) {
5088+
// TA <template-arg> # template parameter object
5089+
//
5090+
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63
5091+
case 'A': {
5092+
First += 2;
5093+
Node *Arg = getDerived().parseTemplateArg();
5094+
if (Arg == nullptr)
5095+
return nullptr;
5096+
return make<SpecialName>("template parameter object for ", Arg);
5097+
}
49785098
// TV <type> # virtual table
49795099
case 'V': {
49805100
First += 2;

libcxxabi/test/test_demangle.pass.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29800,6 +29800,21 @@ const char* cases[][2] =
2980029800
{"_ZN1XIZ1fIiEvOT_EUlS2_DpT0_E_EclIJEEEvDpT_", "void X<void f<int>(int&&)::'lambda'(int&&, auto...)>::operator()<>()"},
2980129801
{"_ZZZZN6abcdef9abcdefghi29abcdefabcdefabcdefabcefabcdef27xxxxxxxxxxxxxxxxxxxxxxxxxxxEN4absl8DurationERKNSt3__u12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEPNS1_19yyyyyyyyyyyyyyyyyyyEENK3$_5clEvENKUlvE_clEvE6zzzzzz", "abcdef::abcdefghi::abcdefabcdefabcdefabcefabcdef::xxxxxxxxxxxxxxxxxxxxxxxxxxx(absl::Duration, std::__u::basic_string<char, std::__u::char_traits<char>, std::__u::allocator<char> > const&, abcdef::abcdefghi::abcdefabcdefabcdefabcefabcdef::yyyyyyyyyyyyyyyyyyy*)::$_5::operator()() const::'lambda'()::operator()() const::zzzzzz"},
2980229802

29803+
// C++2a class type non-type template parameters:
29804+
{"_Z1fIXtl1BLPi0ELi1EEEEvv", "void f<B{(int*)0, 1}>()"},
29805+
{"_Z1fIXtl1BLPi32EEEEvv", "void f<B{(int*)32}>()"},
29806+
{"_Z1fIXtl1BrcPiLi0EEEEvv", "void f<B{reinterpret_cast<int*>(0)}>()"},
29807+
{"_Z1fIXtl1BadsoiL_Z6nestedE_EEEEvv", "void f<B{&(nested.<int at offset 0>)}>()"},
29808+
{"_Z1fIXtl1BadsoiL_Z6nestedE16_0pEEEEvv", "void f<B{&(nested.<int at offset 16>)}>()"},
29809+
{"_Z1fIXtl2BRsoiL_Z7derivedE4EEEEvv", "void f<BR{derived.<int at offset 4>}>()"},
29810+
{"_Z1fIXtl1BcvPiplcvPcadL_Z7derivedELl16EEEEvv", "void f<B{(int*)(((char*)(&(derived))) + (16l))}>()"},
29811+
{"_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv", "void f<C{&(derived.<int const at offset 4>)}>()"},
29812+
{"_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv", "void f<D{(int const Derived::*)0, 1}>()"},
29813+
// FIXME: This is not valid pointer-to-member syntax.
29814+
{"_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv", "void f<D{(int const Derived::*)(&(MoreDerived::z))}>()"},
29815+
{"_Z1fIXtl1Edi1nLi42EEEEvv", "void f<E{.n = 42}>()"},
29816+
{"_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}}"},
29817+
2980329818
// FIXME: This is wrong; the S2_ backref should expand to OT_ and then to
2980429819
// "double&&". But we can't cope with a substitution that represents a
2980529820
// different type the node it is a substitute for.

llvm/include/llvm/Demangle/ItaniumDemangle.h

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
X(PostfixExpr) \
8383
X(ConditionalExpr) \
8484
X(MemberExpr) \
85+
X(SubobjectExpr) \
8586
X(EnclosingExpr) \
8687
X(CastExpr) \
8788
X(SizeofParamPackExpr) \
@@ -91,6 +92,7 @@
9192
X(PrefixExpr) \
9293
X(FunctionParam) \
9394
X(ConversionExpr) \
95+
X(PointerToMemberConversionExpr) \
9496
X(InitListExpr) \
9597
X(FoldExpr) \
9698
X(ThrowExpr) \
@@ -1656,6 +1658,40 @@ class MemberExpr : public Node {
16561658
}
16571659
};
16581660

1661+
class SubobjectExpr : public Node {
1662+
const Node *Type;
1663+
const Node *SubExpr;
1664+
StringView Offset;
1665+
NodeArray UnionSelectors;
1666+
bool OnePastTheEnd;
1667+
1668+
public:
1669+
SubobjectExpr(const Node *Type_, const Node *SubExpr_, StringView Offset_,
1670+
NodeArray UnionSelectors_, bool OnePastTheEnd_)
1671+
: Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_),
1672+
UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {}
1673+
1674+
template<typename Fn> void match(Fn F) const {
1675+
F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd);
1676+
}
1677+
1678+
void printLeft(OutputStream &S) const override {
1679+
SubExpr->print(S);
1680+
S += ".<";
1681+
Type->print(S);
1682+
S += " at offset ";
1683+
if (Offset.empty()) {
1684+
S += "0";
1685+
} else if (Offset[0] == 'n') {
1686+
S += "-";
1687+
S += Offset.dropFront();
1688+
} else {
1689+
S += Offset;
1690+
}
1691+
S += ">";
1692+
}
1693+
};
1694+
16591695
class EnclosingExpr : public Node {
16601696
const StringView Prefix;
16611697
const Node *Infix;
@@ -1843,6 +1879,28 @@ class ConversionExpr : public Node {
18431879
}
18441880
};
18451881

1882+
class PointerToMemberConversionExpr : public Node {
1883+
const Node *Type;
1884+
const Node *SubExpr;
1885+
StringView Offset;
1886+
1887+
public:
1888+
PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_,
1889+
StringView Offset_)
1890+
: Node(KPointerToMemberConversionExpr), Type(Type_), SubExpr(SubExpr_),
1891+
Offset(Offset_) {}
1892+
1893+
template<typename Fn> void match(Fn F) const { F(Type, SubExpr, Offset); }
1894+
1895+
void printLeft(OutputStream &S) const override {
1896+
S += "(";
1897+
Type->print(S);
1898+
S += ")(";
1899+
SubExpr->print(S);
1900+
S += ")";
1901+
}
1902+
};
1903+
18461904
class InitListExpr : public Node {
18471905
const Node *Ty;
18481906
NodeArray Inits;
@@ -2437,6 +2495,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
24372495
Node *parseConversionExpr();
24382496
Node *parseBracedExpr();
24392497
Node *parseFoldExpr();
2498+
Node *parsePointerToMemberConversionExpr();
2499+
Node *parseSubobjectExpr();
24402500

24412501
/// Parse the <type> production.
24422502
Node *parseType();
@@ -4404,6 +4464,50 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() {
44044464
return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
44054465
}
44064466

4467+
// <expression> ::= mc <parameter type> <expr> [<offset number>] E
4468+
//
4469+
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
4470+
template <typename Derived, typename Alloc>
4471+
Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr() {
4472+
Node *Ty = getDerived().parseType();
4473+
if (!Ty)
4474+
return nullptr;
4475+
Node *Expr = getDerived().parseExpr();
4476+
if (!Expr)
4477+
return nullptr;
4478+
StringView Offset = getDerived().parseNumber(true);
4479+
if (!consumeIf('E'))
4480+
return nullptr;
4481+
return make<PointerToMemberConversionExpr>(Ty, Expr, Offset);
4482+
}
4483+
4484+
// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
4485+
// <union-selector> ::= _ [<number>]
4486+
//
4487+
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
4488+
template <typename Derived, typename Alloc>
4489+
Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() {
4490+
Node *Ty = getDerived().parseType();
4491+
if (!Ty)
4492+
return nullptr;
4493+
Node *Expr = getDerived().parseExpr();
4494+
if (!Expr)
4495+
return nullptr;
4496+
StringView Offset = getDerived().parseNumber(true);
4497+
size_t SelectorsBegin = Names.size();
4498+
while (consumeIf('_')) {
4499+
Node *Selector = make<NameType>(parseNumber());
4500+
if (!Selector)
4501+
return nullptr;
4502+
Names.push_back(Selector);
4503+
}
4504+
bool OnePastTheEnd = consumeIf('p');
4505+
if (!consumeIf('E'))
4506+
return nullptr;
4507+
return make<SubobjectExpr>(
4508+
Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
4509+
}
4510+
44074511
// <expression> ::= <unary operator-name> <expression>
44084512
// ::= <binary operator-name> <expression> <expression>
44094513
// ::= <ternary operator-name> <expression> <expression> <expression>
@@ -4661,6 +4765,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
46614765
return nullptr;
46624766
case 'm':
46634767
switch (First[1]) {
4768+
case 'c':
4769+
First += 2;
4770+
return parsePointerToMemberConversionExpr();
46644771
case 'i':
46654772
First += 2;
46664773
return getDerived().parseBinaryExpr("-");
@@ -4808,6 +4915,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
48084915
return Ex;
48094916
return make<CastExpr>("static_cast", T, Ex);
48104917
}
4918+
case 'o':
4919+
First += 2;
4920+
return parseSubobjectExpr();
48114921
case 'p': {
48124922
First += 2;
48134923
Node *Child = getDerived().parseExpr();
@@ -4975,6 +5085,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
49755085
switch (look()) {
49765086
case 'T':
49775087
switch (look(1)) {
5088+
// TA <template-arg> # template parameter object
5089+
//
5090+
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63
5091+
case 'A': {
5092+
First += 2;
5093+
Node *Arg = getDerived().parseTemplateArg();
5094+
if (Arg == nullptr)
5095+
return nullptr;
5096+
return make<SpecialName>("template parameter object for ", Arg);
5097+
}
49785098
// TV <type> # virtual table
49795099
case 'V': {
49805100
First += 2;

0 commit comments

Comments
 (0)