diff --git a/libcxxabi/src/cxa_demangle.cpp b/libcxxabi/src/cxa_demangle.cpp index 01724ccb3470..49b3e12dd0dc 100644 --- a/libcxxabi/src/cxa_demangle.cpp +++ b/libcxxabi/src/cxa_demangle.cpp @@ -1977,6 +1977,7 @@ struct Db { Node *parseArrayType(); Node *parsePointerToMemberType(); Node *parseClassEnumType(); + Node *parseQualifiedType(bool &AppliesToFunction); // FIXME: remove this when all the parse_* functions have been rewritten. template @@ -2238,6 +2239,52 @@ Node *Db::parseClassEnumType() { return legacyParse(); } +// ::= +// ::= * +// ::= U [] # vendor extended type qualifier +Node *Db::parseQualifiedType(bool &AppliesToFunction) { + if (consumeIf('U')) { + StringView Qual = parseBareSourceName(); + 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")); + StringView Proto; + { + SwapAndRestore SaveFirst(First, ProtoSourceName.begin()), + SaveLast(Last, ProtoSourceName.end()); + Proto = parseBareSourceName(); + } + if (Proto.empty()) + return nullptr; + Node *Child = parseQualifiedType(AppliesToFunction); + if (Child == nullptr) + return nullptr; + return make(Child, Proto); + } + + Node *Child = parseQualifiedType(AppliesToFunction); + if (Child == nullptr) + return nullptr; + return make(Child, Qual); + } + + Qualifiers Quals = parseCVQualifiers(); + AppliesToFunction = look() == 'F'; + Node *Ty = parseType(); + if (Ty == nullptr) + return nullptr; + if (Quals != QualNone) { + return AppliesToFunction ? + make(Ty, Quals) : make(Ty, Quals); + } + return Ty; +} + // ::= // ::= // ::= @@ -2265,18 +2312,10 @@ Node *Db::parseType() { // ::= case 'r': case 'V': - case 'K': { - Qualifiers Q = parseCVQualifiers(); - bool AppliesToFunction = look() == 'F'; - - Node *Child = parseType(); - if (Child == nullptr) - return nullptr; - - if (AppliesToFunction) - Result = make(Child, Q); - else - Result = make(Child, Q); + case 'K': + case 'U': { + bool AppliesToFunction = false; + Result = parseQualifiedType(AppliesToFunction); // Itanium C++ ABI 5.1.5.3: // For the purposes of substitution, the CV-qualifiers and ref-qualifier @@ -2285,39 +2324,6 @@ Node *Db::parseType() { return Result; break; } - // ::= U [] # vendor extended type qualifier - case 'U': { - // FIXME: We should fold this into the cvr qualifier parsing above. This - // currently adds too many entries into the substitution table if multiple - // qualifiers are present on the same type, as all the qualifiers on a type - // should just get one entry in the substitution table. - ++First; - StringView Qual = parseBareSourceName(); - if (Qual.empty()) - return nullptr; - - // FIXME parse the optional here! - - Result = parseType(); - if (Result == nullptr) - return nullptr; - - // extension ::= U # objc-type - if (Qual.startsWith("objcproto")) { - StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); - StringView Proto; - { - SwapAndRestore SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); - Proto = parseBareSourceName(); - } - if (Proto.empty()) - return nullptr; - Result = make(Result, Proto); - } else - Result = make(Result, Qual); - break; - } // ::= v # void case 'v': ++First; diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp index ab9725745580..c66161da982c 100644 --- a/libcxxabi/test/test_demangle.pass.cpp +++ b/libcxxabi/test/test_demangle.pass.cpp @@ -29656,6 +29656,9 @@ const char* cases[][2] = {"_ZN5test73fT4IiEEDTcvT_Li1EES1_", "decltype((int)(1)) test7::fT4(int)"}, {"_ZN5test73fT6INS_1BEEEDTcvT__Li1ELi2EEES2_", "decltype((test7::B)(1, 2)) test7::fT6(test7::B)"}, {"_ZNK5test81XIiE3barIiEEDTcl3fooIT_EEEv", "decltype(foo()) test8::X::bar() const"}, + + // Multiple qualifiers on the same type should all get the same entry in the substitution table. + {"_Z1fPU3AS1KiS0_", "f(int const AS1*, int const AS1*)"} }; const unsigned N = sizeof(cases) / sizeof(cases[0]);