Skip to content

Commit

Permalink
Demangling support for class type non-type template parameter extensi…
Browse files Browse the repository at this point in the history
…ons.

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
  • Loading branch information
zygoloid committed Nov 20, 2020
1 parent 0b420d6 commit bec968c
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 0 deletions.
120 changes: 120 additions & 0 deletions libcxxabi/src/demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
X(PostfixExpr) \
X(ConditionalExpr) \
X(MemberExpr) \
X(SubobjectExpr) \
X(EnclosingExpr) \
X(CastExpr) \
X(SizeofParamPackExpr) \
Expand All @@ -91,6 +92,7 @@
X(PrefixExpr) \
X(FunctionParam) \
X(ConversionExpr) \
X(PointerToMemberConversionExpr) \
X(InitListExpr) \
X(FoldExpr) \
X(ThrowExpr) \
Expand Down Expand Up @@ -1656,6 +1658,40 @@ class MemberExpr : public Node {
}
};

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<typename Fn> 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;
Expand Down Expand Up @@ -1843,6 +1879,28 @@ class ConversionExpr : public Node {
}
};

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<typename Fn> 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;
Expand Down Expand Up @@ -2437,6 +2495,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseConversionExpr();
Node *parseBracedExpr();
Node *parseFoldExpr();
Node *parsePointerToMemberConversionExpr();
Node *parseSubobjectExpr();

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

// <expression> ::= mc <parameter type> <expr> [<offset number>] E
//
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::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<PointerToMemberConversionExpr>(Ty, Expr, Offset);
}

// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
// <union-selector> ::= _ [<number>]
//
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::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<NameType>(parseNumber());
if (!Selector)
return nullptr;
Names.push_back(Selector);
}
bool OnePastTheEnd = consumeIf('p');
if (!consumeIf('E'))
return nullptr;
return make<SubobjectExpr>(
Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
}

// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <ternary operator-name> <expression> <expression> <expression>
Expand Down Expand Up @@ -4661,6 +4765,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return nullptr;
case 'm':
switch (First[1]) {
case 'c':
First += 2;
return parsePointerToMemberConversionExpr();
case 'i':
First += 2;
return getDerived().parseBinaryExpr("-");
Expand Down Expand Up @@ -4808,6 +4915,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return Ex;
return make<CastExpr>("static_cast", T, Ex);
}
case 'o':
First += 2;
return parseSubobjectExpr();
case 'p': {
First += 2;
Node *Child = getDerived().parseExpr();
Expand Down Expand Up @@ -4975,6 +5085,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
switch (look()) {
case 'T':
switch (look(1)) {
// TA <template-arg> # 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<SpecialName>("template parameter object for ", Arg);
}
// TV <type> # virtual table
case 'V': {
First += 2;
Expand Down
15 changes: 15 additions & 0 deletions libcxxabi/test/test_demangle.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29800,6 +29800,21 @@ const char* cases[][2] =
{"_ZN1XIZ1fIiEvOT_EUlS2_DpT0_E_EclIJEEEvDpT_", "void X<void f<int>(int&&)::'lambda'(int&&, auto...)>::operator()<>()"},
{"_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"},

// C++2a class type non-type template parameters:
{"_Z1fIXtl1BLPi0ELi1EEEEvv", "void f<B{(int*)0, 1}>()"},
{"_Z1fIXtl1BLPi32EEEEvv", "void f<B{(int*)32}>()"},
{"_Z1fIXtl1BrcPiLi0EEEEvv", "void f<B{reinterpret_cast<int*>(0)}>()"},
{"_Z1fIXtl1BadsoiL_Z6nestedE_EEEEvv", "void f<B{&(nested.<int at offset 0>)}>()"},
{"_Z1fIXtl1BadsoiL_Z6nestedE16_0pEEEEvv", "void f<B{&(nested.<int at offset 16>)}>()"},
{"_Z1fIXtl2BRsoiL_Z7derivedE4EEEEvv", "void f<BR{derived.<int at offset 4>}>()"},
{"_Z1fIXtl1BcvPiplcvPcadL_Z7derivedELl16EEEEvv", "void f<B{(int*)(((char*)(&(derived))) + (16l))}>()"},
{"_Z1fIXtl1CadsoKiL_Z7derivedE4EEEEvv", "void f<C{&(derived.<int const at offset 4>)}>()"},
{"_Z1fIXtl1DLM7DerivedKi0ELi1EEEEvv", "void f<D{(int const Derived::*)0, 1}>()"},
// FIXME: This is not valid pointer-to-member syntax.
{"_Z1fIXtl1DmcM7DerivedKiadL_ZN11MoreDerived1zEEn8EEEEvv", "void f<D{(int const Derived::*)(&(MoreDerived::z))}>()"},
{"_Z1fIXtl1Edi1nLi42EEEEvv", "void f<E{.n = 42}>()"},
{"_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.
Expand Down
120 changes: 120 additions & 0 deletions llvm/include/llvm/Demangle/ItaniumDemangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
X(PostfixExpr) \
X(ConditionalExpr) \
X(MemberExpr) \
X(SubobjectExpr) \
X(EnclosingExpr) \
X(CastExpr) \
X(SizeofParamPackExpr) \
Expand All @@ -91,6 +92,7 @@
X(PrefixExpr) \
X(FunctionParam) \
X(ConversionExpr) \
X(PointerToMemberConversionExpr) \
X(InitListExpr) \
X(FoldExpr) \
X(ThrowExpr) \
Expand Down Expand Up @@ -1656,6 +1658,40 @@ class MemberExpr : public Node {
}
};

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<typename Fn> 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;
Expand Down Expand Up @@ -1843,6 +1879,28 @@ class ConversionExpr : public Node {
}
};

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<typename Fn> 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;
Expand Down Expand Up @@ -2437,6 +2495,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
Node *parseConversionExpr();
Node *parseBracedExpr();
Node *parseFoldExpr();
Node *parsePointerToMemberConversionExpr();
Node *parseSubobjectExpr();

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

// <expression> ::= mc <parameter type> <expr> [<offset number>] E
//
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::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<PointerToMemberConversionExpr>(Ty, Expr, Offset);
}

// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E
// <union-selector> ::= _ [<number>]
//
// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47
template <typename Derived, typename Alloc>
Node *AbstractManglingParser<Derived, Alloc>::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<NameType>(parseNumber());
if (!Selector)
return nullptr;
Names.push_back(Selector);
}
bool OnePastTheEnd = consumeIf('p');
if (!consumeIf('E'))
return nullptr;
return make<SubobjectExpr>(
Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd);
}

// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <ternary operator-name> <expression> <expression> <expression>
Expand Down Expand Up @@ -4661,6 +4765,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return nullptr;
case 'm':
switch (First[1]) {
case 'c':
First += 2;
return parsePointerToMemberConversionExpr();
case 'i':
First += 2;
return getDerived().parseBinaryExpr("-");
Expand Down Expand Up @@ -4808,6 +4915,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() {
return Ex;
return make<CastExpr>("static_cast", T, Ex);
}
case 'o':
First += 2;
return parseSubobjectExpr();
case 'p': {
First += 2;
Node *Child = getDerived().parseExpr();
Expand Down Expand Up @@ -4975,6 +5085,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() {
switch (look()) {
case 'T':
switch (look(1)) {
// TA <template-arg> # 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<SpecialName>("template parameter object for ", Arg);
}
// TV <type> # virtual table
case 'V': {
First += 2;
Expand Down

0 comments on commit bec968c

Please sign in to comment.