Index: src/cxa_demangle.cpp =================================================================== --- src/cxa_demangle.cpp +++ src/cxa_demangle.cpp @@ -7,6 +7,12 @@ // //===----------------------------------------------------------------------===// +// FIXME: (possibly) incomplete list of features that clang mangles that this +// file does not yet support: +// - enable_if attribute +// - decomposition declarations +// - C++ modules TS + #define _LIBCPP_NO_EXCEPTIONS #include "__cxxabi_config.h" @@ -178,6 +184,7 @@ KConversionOperatorType, KPostfixQualifiedType, KNameType, + KAbiTagAttr, KObjCProtoName, KPointerType, KLValueReferenceType, @@ -384,6 +391,21 @@ void printLeft(OutputStream &s) const override { s += Name; } }; +class AbiTagAttr final : public Node { + const Node* Base; + StringView Tag; +public: + AbiTagAttr(const Node* Base_, StringView Tag_) + : Node(KAbiTagAttr), Base(Base_), Tag(Tag_) {} + + void printLeft(OutputStream &S) const override { + Base->printLeft(S); + S += "[abi:"; + S += Tag; + S += "]"; + } +}; + class ObjCProtoName : public Node { Node *Ty; Node *Protocol; @@ -1795,10 +1817,10 @@ return first; } -// ::= +// ::= [0-9]* const char* -parse_source_name(const char* first, const char* last, Db& db) +parse_positive_integer(const char* first, const char* last, size_t* out) { if (first != last) { @@ -1813,15 +1835,55 @@ if (++t == last) return first; } - if (static_cast(last - t) >= n) - { - StringView r(t, t + n); - if (r.substr(0, 10) == "_GLOBAL__N") - db.Names.push_back(db.make("(anonymous namespace)")); - else - db.Names.push_back(db.make(r)); - first = t + n; - } + *out = n; + first = t; + } + } + return first; +} + +// extension +// ::= * +// ::= B + +const char* +parse_abi_tag_seq(const char* first, const char* last, Db& db) +{ + while (first != last && *first == 'B' && first+1 != last) + { + size_t length; + const char* t = parse_positive_integer(first+1, last, &length); + if (t == first+1) + return first; + if (static_cast(last - t) < length || db.Names.empty()) + return first; + db.Names.back() = db.make( + db.Names.back(), StringView(t, t + length)); + first = t + length; + } + return first; +} + +// ::= + +const char* +parse_source_name(const char* first, const char* last, Db& db) +{ + if (first != last) + { + size_t length; + const char* t = parse_positive_integer(first, last, &length); + if (t == first) + return first; + if (static_cast(last - t) >= length) + { + StringView r(t, t + length); + if (r.substr(0, 10) == "_GLOBAL__N") + db.Names.push_back(db.make("(anonymous namespace)")); + else + db.Names.push_back(db.make(r)); + first = t + length; + first = parse_abi_tag_seq(first, last, db); } } return first; @@ -4315,6 +4377,7 @@ db.Names.push_back( db.make(db.Names.back(), false)); first += 2; + first = parse_abi_tag_seq(first, last, db); db.ParsedCtorDtorCV = true; break; } @@ -4331,6 +4394,7 @@ db.Names.push_back( db.make(db.Names.back(), true)); first += 2; + first = parse_abi_tag_seq(first, last, db); db.ParsedCtorDtorCV = true; break; } @@ -4373,6 +4437,7 @@ return first; db.Names.push_back(db.make(count)); first = t0 + 1; + first = parse_abi_tag_seq(first, last, db); } break; case 'l': @@ -4462,7 +4527,7 @@ default: t = parse_operator_name(first, last, db); if (t != first) - first = t; + first = parse_abi_tag_seq(t, last, db); break; }; } Index: test/test_demangle.pass.cpp =================================================================== --- test/test_demangle.pass.cpp +++ test/test_demangle.pass.cpp @@ -29605,6 +29605,12 @@ {"_ZTW1x", "thread-local wrapper routine for x"}, {"_ZTHN3fooE", "thread-local initialization routine for foo"}, {"_Z4algoIJiiiEEvZ1gEUlT_E_", "void algo(g::'lambda'(int, int, int))"}, + + {"_Z1fB3foov", "f[abi:foo]()"}, + {"_Z1fB3fooB3barv", "f[abi:foo][abi:bar]()"}, + {"_ZN1SB5outer1fB5innerEv", "S[abi:outer]::f[abi:inner]()"}, + {"_ZN1SC2B8ctor_tagEv", "S::S[abi:ctor_tag]()"}, + {"_ZplB4MERP1SS_", "operator+[abi:MERP](S, S)"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]);