diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h index c8a77adc9fafd6..d0eaf6d6648042 100644 --- a/libcxxabi/src/demangle/ItaniumDemangle.h +++ b/libcxxabi/src/demangle/ItaniumDemangle.h @@ -2572,8 +2572,6 @@ const char* parse_discriminator(const char* first, const char* last); // ::= template Node *AbstractManglingParser::parseName(NameState *State) { - consumeIf('L'); // extension - if (look() == 'N') return getDerived().parseNestedName(State); if (look() == 'Z') @@ -2649,15 +2647,14 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { return make(Encoding, Entity); } -// ::= -// ::= St # ::std:: -// extension ::= StL +// ::= [L]* +// ::= St [L]* # ::std:: +// [*] extension template Node * AbstractManglingParser::parseUnscopedName(NameState *State) { bool IsStd = consumeIf("St"); - if (IsStd) - consumeIf('L'); + consumeIf('L'); Node *Result = getDerived().parseUnqualifiedName(State); if (Result == nullptr) @@ -3148,14 +3145,14 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, // ::= N [] [] E // ::= N [] [] E // -// ::= +// ::= [L]* // ::= // ::= // ::= // ::= # empty // ::= // ::= -// extension ::= L +// [*] extension // // := [] M // @@ -3175,88 +3172,85 @@ AbstractManglingParser::parseNestedName(NameState *State) { if (State) State->ReferenceQualifier = FrefQualRValue; } else if (consumeIf('R')) { if (State) State->ReferenceQualifier = FrefQualLValue; - } else + } else { if (State) State->ReferenceQualifier = FrefQualNone; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (!Comp) return false; - if (SoFar) SoFar = make(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - return SoFar != nullptr; - }; - - if (consumeIf("St")) { - SoFar = make("std"); - if (!SoFar) - return nullptr; } + Node *SoFar = nullptr; while (!consumeIf('E')) { consumeIf('L'); // extension - // := [] M if (consumeIf('M')) { + // := [] M if (SoFar == nullptr) return nullptr; continue; } - // ::= - if (look() == 'T') { - if (!PushComponent(getDerived().parseTemplateParam())) - return nullptr; - Subs.push_back(SoFar); - continue; - } + if (State) + // Only set end-with-template on the case that does that. + State->EndsWithTemplateArgs = false; - // ::= - if (look() == 'I') { + if (look() == 'T') { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseTemplateParam(); + } else if (look() == 'I') { + // ::= + if (SoFar == nullptr) + return nullptr; // Must have a prefix. Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) - return nullptr; - SoFar = make(SoFar, TA); - if (!SoFar) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - if (!PushComponent(getDerived().parseDecltype())) + if (TA == nullptr) return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (!PushComponent(S)) + if (SoFar->getKind() == Node::KNameWithTemplateArgs) + // Semantically cannot be generated by a + // C++ entity. There will always be [something like] a name between + // them. return nullptr; - if (SoFar != S) - Subs.push_back(S); - continue; - } - - // Parse an thats actually a . - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { + if (State) + State->EndsWithTemplateArgs = true; + SoFar = make(SoFar, TA); + } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseDecltype(); + } else if (look() == 'S') { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + if (look(1) == 't') { + // parseSubstition does not handle 'St'. + First += 2; + SoFar = make("std"); + } else { + SoFar = getDerived().parseSubstitution(); + } if (SoFar == nullptr) return nullptr; - if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State))) - return nullptr; - SoFar = getDerived().parseAbiTags(SoFar); - if (SoFar == nullptr) + continue; // Do not push a new substitution. + } else { + Node *N = nullptr; + if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { + // An that's actually a . + if (SoFar == nullptr) + return nullptr; + N = getDerived().parseCtorDtorName(SoFar, State); + if (N != nullptr) + N = getDerived().parseAbiTags(N); + } else { + // ::= + N = getDerived().parseUnqualifiedName(State); + } + if (N == nullptr) return nullptr; - Subs.push_back(SoFar); - continue; + if (SoFar) + SoFar = make(SoFar, N); + else + SoFar = N; } - - // ::= - if (!PushComponent(getDerived().parseUnqualifiedName(State))) + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); } @@ -5431,6 +5425,7 @@ bool AbstractManglingParser::parseSeqId(size_t *Out) { // ::= Si # ::std::basic_istream > // ::= So # ::std::basic_ostream > // ::= Sd # ::std::basic_iostream > +// The St case is handled specially in parseNestedName. template Node *AbstractManglingParser::parseSubstitution() { if (!consumeIf('S')) diff --git a/libcxxabi/test/test_demangle.pass.cpp b/libcxxabi/test/test_demangle.pass.cpp index 191b4b686969ba..263494af75d035 100644 --- a/libcxxabi/test/test_demangle.pass.cpp +++ b/libcxxabi/test/test_demangle.pass.cpp @@ -29936,6 +29936,11 @@ const char* invalid_cases[] = "FSiIJEENT_IoE ", "ZTVSiIZTVSiIZTVSiIZTVSiINIJEET_T_T_T_T_ ", "Ana_T_E_T_IJEffffffffffffffersfffffrsrsffffffbgE", + + "_ZN3TPLS_E", + "_ZN3CLSIiEIiEE", + "_ZN3CLSDtLi0EEE", + "_ZN3CLSIiEEvNS_T_Ev", }; const unsigned NI = sizeof(invalid_cases) / sizeof(invalid_cases[0]); diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h index 4ffac53790d0d0..302669ab832404 100644 --- a/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -2572,8 +2572,6 @@ const char* parse_discriminator(const char* first, const char* last); // ::= template Node *AbstractManglingParser::parseName(NameState *State) { - consumeIf('L'); // extension - if (look() == 'N') return getDerived().parseNestedName(State); if (look() == 'Z') @@ -2649,15 +2647,14 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { return make(Encoding, Entity); } -// ::= -// ::= St # ::std:: -// extension ::= StL +// ::= [L]* +// ::= St [L]* # ::std:: +// [*] extension template Node * AbstractManglingParser::parseUnscopedName(NameState *State) { bool IsStd = consumeIf("St"); - if (IsStd) - consumeIf('L'); + consumeIf('L'); Node *Result = getDerived().parseUnqualifiedName(State); if (Result == nullptr) @@ -3148,14 +3145,14 @@ AbstractManglingParser::parseCtorDtorName(Node *&SoFar, // ::= N [] [] E // ::= N [] [] E // -// ::= +// ::= [L]* // ::= // ::= // ::= // ::= # empty // ::= // ::= -// extension ::= L +// [*] extension // // := [] M // @@ -3175,88 +3172,85 @@ AbstractManglingParser::parseNestedName(NameState *State) { if (State) State->ReferenceQualifier = FrefQualRValue; } else if (consumeIf('R')) { if (State) State->ReferenceQualifier = FrefQualLValue; - } else + } else { if (State) State->ReferenceQualifier = FrefQualNone; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (!Comp) return false; - if (SoFar) SoFar = make(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - return SoFar != nullptr; - }; - - if (consumeIf("St")) { - SoFar = make("std"); - if (!SoFar) - return nullptr; } + Node *SoFar = nullptr; while (!consumeIf('E')) { consumeIf('L'); // extension - // := [] M if (consumeIf('M')) { + // := [] M if (SoFar == nullptr) return nullptr; continue; } - // ::= - if (look() == 'T') { - if (!PushComponent(getDerived().parseTemplateParam())) - return nullptr; - Subs.push_back(SoFar); - continue; - } + if (State) + // Only set end-with-template on the case that does that. + State->EndsWithTemplateArgs = false; - // ::= - if (look() == 'I') { + if (look() == 'T') { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseTemplateParam(); + } else if (look() == 'I') { + // ::= + if (SoFar == nullptr) + return nullptr; // Must have a prefix. Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) - return nullptr; - SoFar = make(SoFar, TA); - if (!SoFar) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - if (!PushComponent(getDerived().parseDecltype())) + if (TA == nullptr) return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (!PushComponent(S)) + if (SoFar->getKind() == Node::KNameWithTemplateArgs) + // Semantically cannot be generated by a + // C++ entity. There will always be [something like] a name between + // them. return nullptr; - if (SoFar != S) - Subs.push_back(S); - continue; - } - - // Parse an thats actually a . - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { + if (State) + State->EndsWithTemplateArgs = true; + SoFar = make(SoFar, TA); + } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseDecltype(); + } else if (look() == 'S') { + // ::= + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + if (look(1) == 't') { + // parseSubstition does not handle 'St'. + First += 2; + SoFar = make("std"); + } else { + SoFar = getDerived().parseSubstitution(); + } if (SoFar == nullptr) return nullptr; - if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State))) - return nullptr; - SoFar = getDerived().parseAbiTags(SoFar); - if (SoFar == nullptr) + continue; // Do not push a new substitution. + } else { + Node *N = nullptr; + if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { + // An that's actually a . + if (SoFar == nullptr) + return nullptr; + N = getDerived().parseCtorDtorName(SoFar, State); + if (N != nullptr) + N = getDerived().parseAbiTags(N); + } else { + // ::= + N = getDerived().parseUnqualifiedName(State); + } + if (N == nullptr) return nullptr; - Subs.push_back(SoFar); - continue; + if (SoFar) + SoFar = make(SoFar, N); + else + SoFar = N; } - - // ::= - if (!PushComponent(getDerived().parseUnqualifiedName(State))) + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); } @@ -5431,6 +5425,7 @@ bool AbstractManglingParser::parseSeqId(size_t *Out) { // ::= Si # ::std::basic_istream > // ::= So # ::std::basic_ostream > // ::= Sd # ::std::basic_iostream > +// The St case is handled specially in parseNestedName. template Node *AbstractManglingParser::parseSubstitution() { if (!consumeIf('S'))