Index: libcxxabi/src/demangle/ItaniumDemangle.h =================================================================== --- libcxxabi/src/demangle/ItaniumDemangle.h +++ libcxxabi/src/demangle/ItaniumDemangle.h @@ -2587,39 +2587,44 @@ Node *AbstractManglingParser::parseName(NameState *State) { consumeIf('L'); // extension - if (look() == 'N') - return getDerived().parseNestedName(State); - if (look() == 'Z') - return getDerived().parseLocalName(State); - - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) + Node *Result = nullptr; + if (look() == 'N') { + Result = getDerived().parseNestedName(State); + } else if (look() == 'Z') { + Result = getDerived().parseLocalName(State); + } else { + bool IsSubst = look() == 'S' && look(1) != 't'; + if (IsSubst) { + // A substitution must lead to: + // ::= + Result = getDerived().parseSubstitution(); + } else { + // An unscoped name can be one of: + // ::= + // ::= + Result = getDerived().parseUnscopedName(State); + } + if (Result == nullptr) return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(S, TA); - } - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) - return nullptr; - // ::= - if (look() == 'I') { - Subs.push_back(N); - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) + if (look() == 'I') { + // ::= + if (!IsSubst) + // An unscoped-template-name is substitutable. + Subs.push_back(Result); + Node *TA = getDerived().parseTemplateArgs(State != nullptr); + if (TA == nullptr) + return nullptr; + if (State) + State->EndsWithTemplateArgs = true; + Result = make(Result, TA); + } else if (IsSubst) { + // The substitution case must be followed by template-args return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(N, TA); + } } - // ::= - return N; + + return Result; } // := Z E [] @@ -2664,13 +2669,17 @@ template Node * AbstractManglingParser::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) - return nullptr; - return make(R); - } - return getDerived().parseUnqualifiedName(State); + bool IsStd = consumeIf("St"); + if (IsStd) + consumeIf('L'); + + Node *Result = getDerived().parseUnqualifiedName(State); + if (Result == nullptr) + return nullptr; + if (IsStd) + Result = make(Result); + + return Result; } // ::= [abi-tags] @@ -4065,9 +4074,9 @@ } // ::= # See Compression below case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) + if (look(1) != 't') { + Result = getDerived().parseSubstitution(); + if (Result == nullptr) return nullptr; // Sub could be either of: @@ -4084,13 +4093,13 @@ Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make(Sub, TA); - break; + Result = make(Result, TA); + } else { + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Result; } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; + break; } DEMANGLE_FALLTHROUGH; } Index: libcxxabi/test/test_demangle.pass.cpp =================================================================== --- libcxxabi/test/test_demangle.pass.cpp +++ libcxxabi/test/test_demangle.pass.cpp @@ -29855,6 +29855,8 @@ // This should be invalid, but it is currently not recognized as such // See https://llvm.org/PR51407 {"_Zcv1BIRT_EIS1_E", "operator B<><>"}, + + {"_Z3TPLIiET_S0_", "int TPL(int)"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); Index: llvm/include/llvm/Demangle/ItaniumDemangle.h =================================================================== --- llvm/include/llvm/Demangle/ItaniumDemangle.h +++ llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -2587,39 +2587,44 @@ Node *AbstractManglingParser::parseName(NameState *State) { consumeIf('L'); // extension - if (look() == 'N') - return getDerived().parseNestedName(State); - if (look() == 'Z') - return getDerived().parseLocalName(State); - - // ::= - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) + Node *Result = nullptr; + if (look() == 'N') { + Result = getDerived().parseNestedName(State); + } else if (look() == 'Z') { + Result = getDerived().parseLocalName(State); + } else { + bool IsSubst = look() == 'S' && look(1) != 't'; + if (IsSubst) { + // A substitution must lead to: + // ::= + Result = getDerived().parseSubstitution(); + } else { + // An unscoped name can be one of: + // ::= + // ::= + Result = getDerived().parseUnscopedName(State); + } + if (Result == nullptr) return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(S, TA); - } - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) - return nullptr; - // ::= - if (look() == 'I') { - Subs.push_back(N); - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) + if (look() == 'I') { + // ::= + if (!IsSubst) + // An unscoped-template-name is substitutable. + Subs.push_back(Result); + Node *TA = getDerived().parseTemplateArgs(State != nullptr); + if (TA == nullptr) + return nullptr; + if (State) + State->EndsWithTemplateArgs = true; + Result = make(Result, TA); + } else if (IsSubst) { + // The substitution case must be followed by template-args return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make(N, TA); + } } - // ::= - return N; + + return Result; } // := Z E [] @@ -2664,13 +2669,17 @@ template Node * AbstractManglingParser::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) - return nullptr; - return make(R); - } - return getDerived().parseUnqualifiedName(State); + bool IsStd = consumeIf("St"); + if (IsStd) + consumeIf('L'); + + Node *Result = getDerived().parseUnqualifiedName(State); + if (Result == nullptr) + return nullptr; + if (IsStd) + Result = make(Result); + + return Result; } // ::= [abi-tags] @@ -4065,9 +4074,9 @@ } // ::= # See Compression below case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) + if (look(1) != 't') { + Result = getDerived().parseSubstitution(); + if (Result == nullptr) return nullptr; // Sub could be either of: @@ -4084,13 +4093,13 @@ Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make(Sub, TA); - break; + Result = make(Result, TA); + } else { + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Result; } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; + break; } DEMANGLE_FALLTHROUGH; }