diff --git a/third_party/llvm/include/llvm/Demangle/Demangle.h b/third_party/llvm/include/llvm/Demangle/Demangle.h index e1f73c4..fe12960 100644 --- a/third_party/llvm/include/llvm/Demangle/Demangle.h +++ b/third_party/llvm/include/llvm/Demangle/Demangle.h @@ -32,7 +32,7 @@ enum : int { /// Returns a non-NULL pointer to a NUL-terminated C style string /// that should be explicitly freed, if successful. Otherwise, may return /// nullptr if mangled_name is not a valid mangling or is nullptr. -char *itaniumDemangle(std::string_view mangled_name); +char *itaniumDemangle(std::string_view mangled_name, bool ParseParams = true); enum MSDemangleFlags { MSDF_None = 0, @@ -67,7 +67,9 @@ char *dlangDemangle(std::string_view MangledName); /// demangling occurred. std::string demangle(std::string_view MangledName); -bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result); +bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result, + bool CanHaveLeadingDot = true, + bool ParseParams = true); /// "Partial" demangler. This supports demangling a string into an AST /// (typically an intermediate stage in itaniumDemangle) and querying certain @@ -102,7 +104,7 @@ struct ItaniumPartialDemangler { char *getFunctionParameters(char *Buf, size_t *N) const; char *getFunctionReturnType(char *Buf, size_t *N) const; - /// If this function has any any cv or reference qualifiers. These imply that + /// If this function has any cv or reference qualifiers. These imply that /// the function is a non-static member function. bool hasFunctionQualifiers() const; diff --git a/third_party/llvm/include/llvm/Demangle/DemangleConfig.h b/third_party/llvm/include/llvm/Demangle/DemangleConfig.h index 2ff95dd..30f72ff 100644 --- a/third_party/llvm/include/llvm/Demangle/DemangleConfig.h +++ b/third_party/llvm/include/llvm/Demangle/DemangleConfig.h @@ -86,6 +86,11 @@ #define DEMANGLE_FALLTHROUGH #endif +#ifndef DEMANGLE_ASSERT +#include +#define DEMANGLE_ASSERT(__expr, __msg) assert((__expr) && (__msg)) +#endif + #define DEMANGLE_NAMESPACE_BEGIN namespace llvm { namespace itanium_demangle { #define DEMANGLE_NAMESPACE_END } } diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h index 550e169..e7c008b 100644 --- a/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/ItaniumDemangle.h @@ -20,7 +20,6 @@ #include "StringViewExtras.h" #include "Utility.h" #include -#include #include #include #include @@ -31,16 +30,20 @@ #include #include +#ifdef _LIBCXXABI_COMPILER_CLANG +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-template" +#endif + DEMANGLE_NAMESPACE_BEGIN template class PODSmallVector { - static_assert(std::is_pod::value, - "T is required to be a plain old data type"); - + static_assert(std::is_trivial::value, + "T is required to be a trivial type"); T *First = nullptr; T *Last = nullptr; T *Cap = nullptr; - T Inline[N] = {0}; + T Inline[N] = {}; bool isInline() const { return First == Inline; } @@ -55,13 +58,13 @@ template class PODSmallVector { if (isInline()) { auto *Tmp = static_cast(std::malloc(NewCap * sizeof(T))); if (Tmp == nullptr) - std::terminate(); + std::abort(); std::copy(First, Last, Tmp); First = Tmp; } else { First = static_cast(std::realloc(First, NewCap * sizeof(T))); if (First == nullptr) - std::terminate(); + std::abort(); } Last = First + S; Cap = First + NewCap; @@ -123,12 +126,12 @@ template class PODSmallVector { // NOLINTNEXTLINE(readability-identifier-naming) void pop_back() { - assert(Last != First && "Popping empty vector!"); + DEMANGLE_ASSERT(Last != First, "Popping empty vector!"); --Last; } - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); + void shrinkToSize(size_t Index) { + DEMANGLE_ASSERT(Index <= size(), "shrinkToSize() can't expand!"); Last = First + Index; } @@ -138,11 +141,11 @@ template class PODSmallVector { bool empty() const { return First == Last; } size_t size() const { return static_cast(Last - First); } T &back() { - assert(Last != First && "Calling back() on empty vector!"); + DEMANGLE_ASSERT(Last != First, "Calling back() on empty vector!"); return *(Last - 1); } T &operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); + DEMANGLE_ASSERT(Index < size(), "Invalid access!"); return *(begin() + Index); } void clear() { Last = First; } @@ -528,6 +531,23 @@ class ElaboratedTypeSpefType : public Node { } }; +class TransformedType : public Node { + std::string_view Transform; + Node *BaseType; +public: + TransformedType(std::string_view Transform_, Node *BaseType_) + : Node(KTransformedType), Transform(Transform_), BaseType(BaseType_) {} + + template void match(Fn F) const { F(Transform, BaseType); } + + void printLeft(OutputBuffer &OB) const override { + OB += Transform; + OB += '('; + BaseType->print(OB); + OB += ')'; + } +}; + struct AbiTagAttr : Node { Node *Base; std::string_view Tag; @@ -867,26 +887,53 @@ class DynamicExceptionSpec : public Node { } }; +/// Represents the explicitly named object parameter. +/// E.g., +/// \code{.cpp} +/// struct Foo { +/// void bar(this Foo && self); +/// }; +/// \endcode +class ExplicitObjectParameter final : public Node { + Node *Base; + +public: + ExplicitObjectParameter(Node *Base_) + : Node(KExplicitObjectParameter), Base(Base_) { + DEMANGLE_ASSERT( + Base != nullptr, + "Creating an ExplicitObjectParameter without a valid Base Node."); + } + + template void match(Fn F) const { F(Base); } + + void printLeft(OutputBuffer &OB) const override { + OB += "this "; + Base->print(OB); + } +}; + class FunctionEncoding final : public Node { const Node *Ret; const Node *Name; NodeArray Params; const Node *Attrs; + const Node *Requires; Qualifiers CVQuals; FunctionRefQual RefQual; public: FunctionEncoding(const Node *Ret_, const Node *Name_, NodeArray Params_, - const Node *Attrs_, Qualifiers CVQuals_, - FunctionRefQual RefQual_) + const Node *Attrs_, const Node *Requires_, + Qualifiers CVQuals_, FunctionRefQual RefQual_) : Node(KFunctionEncoding, /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No, /*FunctionCache=*/Cache::Yes), Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_), - CVQuals(CVQuals_), RefQual(RefQual_) {} + Requires(Requires_), CVQuals(CVQuals_), RefQual(RefQual_) {} template void match(Fn F) const { - F(Ret, Name, Params, Attrs, CVQuals, RefQual); + F(Ret, Name, Params, Attrs, Requires, CVQuals, RefQual); } Qualifiers getCVQuals() const { return CVQuals; } @@ -929,6 +976,11 @@ class FunctionEncoding final : public Node { if (Attrs != nullptr) Attrs->print(OB); + + if (Requires != nullptr) { + OB += " requires "; + Requires->print(OB); + } } }; @@ -1000,6 +1052,24 @@ struct NestedName : Node { } }; +struct MemberLikeFriendName : Node { + Node *Qual; + Node *Name; + + MemberLikeFriendName(Node *Qual_, Node *Name_) + : Node(KMemberLikeFriendName), Qual(Qual_), Name(Name_) {} + + template void match(Fn F) const { F(Qual, Name); } + + std::string_view getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputBuffer &OB) const override { + Qual->print(OB); + OB += "::friend "; + Name->print(OB); + } +}; + struct ModuleName : Node { ModuleName *Parent; Node *Name; @@ -1165,6 +1235,24 @@ class SyntheticTemplateParamName final : public Node { } }; +class TemplateParamQualifiedArg final : public Node { + Node *Param; + Node *Arg; + +public: + TemplateParamQualifiedArg(Node *Param_, Node *Arg_) + : Node(KTemplateParamQualifiedArg), Param(Param_), Arg(Arg_) {} + + template void match(Fn F) const { F(Param, Arg); } + + Node *getArg() { return Arg; } + + void printLeft(OutputBuffer &OB) const override { + // Don't print Param to keep the output consistent. + Arg->print(OB); + } +}; + /// A template type parameter declaration, 'typename T'. class TypeTemplateParamDecl final : public Node { Node *Name; @@ -1180,6 +1268,26 @@ class TypeTemplateParamDecl final : public Node { void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; +/// A constrained template type parameter declaration, 'C T'. +class ConstrainedTypeTemplateParamDecl final : public Node { + Node *Constraint; + Node *Name; + +public: + ConstrainedTypeTemplateParamDecl(Node *Constraint_, Node *Name_) + : Node(KConstrainedTypeTemplateParamDecl, Cache::Yes), + Constraint(Constraint_), Name(Name_) {} + + template void match(Fn F) const { F(Constraint, Name); } + + void printLeft(OutputBuffer &OB) const override { + Constraint->print(OB); + OB += " "; + } + + void printRight(OutputBuffer &OB) const override { Name->print(OB); } +}; + /// A non-type template parameter declaration, 'int N'. class NonTypeTemplateParamDecl final : public Node { Node *Name; @@ -1208,13 +1316,14 @@ class NonTypeTemplateParamDecl final : public Node { class TemplateTemplateParamDecl final : public Node { Node *Name; NodeArray Params; + Node *Requires; public: - TemplateTemplateParamDecl(Node *Name_, NodeArray Params_) + TemplateTemplateParamDecl(Node *Name_, NodeArray Params_, Node *Requires_) : Node(KTemplateTemplateParamDecl, Cache::Yes), Name(Name_), - Params(Params_) {} + Params(Params_), Requires(Requires_) {} - template void match(Fn F) const { F(Name, Params); } + template void match(Fn F) const { F(Name, Params, Requires); } void printLeft(OutputBuffer &OB) const override { ScopedOverride LT(OB.GtIsGt, 0); @@ -1223,7 +1332,13 @@ class TemplateTemplateParamDecl final : public Node { OB += "> typename "; } - void printRight(OutputBuffer &OB) const override { Name->print(OB); } + void printRight(OutputBuffer &OB) const override { + Name->print(OB); + if (Requires != nullptr) { + OB += " requires "; + Requires->print(OB); + } + } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1320,7 +1435,7 @@ class ParameterPack final : public Node { /// A variadic template argument. This node represents an occurrence of /// JE in some . It isn't itself unexpanded, unless -/// one of it's Elements is. The parser inserts a ParameterPack into the +/// one of its Elements is. The parser inserts a ParameterPack into the /// TemplateParams table if the this pack belongs to apply to an /// . class TemplateArgumentPack final : public Node { @@ -1386,11 +1501,13 @@ class ParameterPackExpansion final : public Node { class TemplateArgs final : public Node { NodeArray Params; + Node *Requires; public: - TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {} + TemplateArgs(NodeArray Params_, Node *Requires_) + : Node(KTemplateArgs), Params(Params_), Requires(Requires_) {} - template void match(Fn F) const { F(Params); } + template void match(Fn F) const { F(Params, Requires); } NodeArray getParams() { return Params; } @@ -1399,6 +1516,7 @@ class TemplateArgs final : public Node { OB += "<"; Params.printWithComma(OB); OB += ">"; + // Don't print the requires clause to keep the output simple. } }; @@ -1583,7 +1701,7 @@ class SpecialSubstitution final : public ExpandedSpecialSubstitution { std::string_view SV = ExpandedSpecialSubstitution::getBaseName(); if (isInstantiation()) { // The instantiations are typedefs that drop the "basic_" prefix. - assert(llvm::itanium_demangle::starts_with(SV, "basic_")); + DEMANGLE_ASSERT(starts_with(SV, "basic_"), ""); SV.remove_prefix(sizeof("basic_") - 1); } return SV; @@ -1649,17 +1767,21 @@ class UnnamedTypeName : public Node { class ClosureTypeName : public Node { NodeArray TemplateParams; + const Node *Requires1; NodeArray Params; + const Node *Requires2; std::string_view Count; public: - ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, + ClosureTypeName(NodeArray TemplateParams_, const Node *Requires1_, + NodeArray Params_, const Node *Requires2_, std::string_view Count_) : Node(KClosureTypeName), TemplateParams(TemplateParams_), - Params(Params_), Count(Count_) {} + Requires1(Requires1_), Params(Params_), Requires2(Requires2_), + Count(Count_) {} template void match(Fn F) const { - F(TemplateParams, Params, Count); + F(TemplateParams, Requires1, Params, Requires2, Count); } void printDeclarator(OutputBuffer &OB) const { @@ -1669,12 +1791,22 @@ class ClosureTypeName : public Node { TemplateParams.printWithComma(OB); OB += ">"; } + if (Requires1 != nullptr) { + OB += " requires "; + Requires1->print(OB); + OB += " "; + } OB.printOpen(); Params.printWithComma(OB); OB.printClose(); + if (Requires2 != nullptr) { + OB += " requires "; + Requires2->print(OB); + } } void printLeft(OutputBuffer &OB) const override { + // FIXME: This demangling is not particularly readable. OB += "\'lambda"; OB += Count; OB += "\'"; @@ -2303,6 +2435,95 @@ class IntegerLiteral : public Node { } }; +class RequiresExpr : public Node { + NodeArray Parameters; + NodeArray Requirements; +public: + RequiresExpr(NodeArray Parameters_, NodeArray Requirements_) + : Node(KRequiresExpr), Parameters(Parameters_), + Requirements(Requirements_) {} + + template void match(Fn F) const { F(Parameters, Requirements); } + + void printLeft(OutputBuffer &OB) const override { + OB += "requires"; + if (!Parameters.empty()) { + OB += ' '; + OB.printOpen(); + Parameters.printWithComma(OB); + OB.printClose(); + } + OB += ' '; + OB.printOpen('{'); + for (const Node *Req : Requirements) { + Req->print(OB); + } + OB += ' '; + OB.printClose('}'); + } +}; + +class ExprRequirement : public Node { + const Node *Expr; + bool IsNoexcept; + const Node *TypeConstraint; +public: + ExprRequirement(const Node *Expr_, bool IsNoexcept_, + const Node *TypeConstraint_) + : Node(KExprRequirement), Expr(Expr_), IsNoexcept(IsNoexcept_), + TypeConstraint(TypeConstraint_) {} + + template void match(Fn F) const { + F(Expr, IsNoexcept, TypeConstraint); + } + + void printLeft(OutputBuffer &OB) const override { + OB += " "; + if (IsNoexcept || TypeConstraint) + OB.printOpen('{'); + Expr->print(OB); + if (IsNoexcept || TypeConstraint) + OB.printClose('}'); + if (IsNoexcept) + OB += " noexcept"; + if (TypeConstraint) { + OB += " -> "; + TypeConstraint->print(OB); + } + OB += ';'; + } +}; + +class TypeRequirement : public Node { + const Node *Type; +public: + TypeRequirement(const Node *Type_) + : Node(KTypeRequirement), Type(Type_) {} + + template void match(Fn F) const { F(Type); } + + void printLeft(OutputBuffer &OB) const override { + OB += " typename "; + Type->print(OB); + OB += ';'; + } +}; + +class NestedRequirement : public Node { + const Node *Constraint; +public: + NestedRequirement(const Node *Constraint_) + : Node(KNestedRequirement), Constraint(Constraint_) {} + + template void match(Fn F) const { F(Constraint); } + + void printLeft(OutputBuffer &OB) const override { + OB += " requires "; + Constraint->print(OB); + OB += ';'; + } +}; + template struct FloatData; namespace float_literal_impl { @@ -2371,7 +2592,7 @@ void Node::visit(Fn F) const { return F(static_cast(this)); #include "ItaniumNodes.def" } - assert(0 && "unknown mangling node kind"); + DEMANGLE_ASSERT(0, "unknown mangling node kind"); } /// Determine the kind of a node from its type. @@ -2397,6 +2618,8 @@ template struct AbstractManglingParser { // table. PODSmallVector Subs; + // A list of template argument values corresponding to a template parameter + // list. using TemplateParamList = PODSmallVector; class ScopedTemplateParamList { @@ -2411,9 +2634,11 @@ template struct AbstractManglingParser { Parser->TemplateParams.push_back(&Params); } ~ScopedTemplateParamList() { - assert(Parser->TemplateParams.size() >= OldNumTemplateParamLists); - Parser->TemplateParams.dropBack(OldNumTemplateParamLists); + DEMANGLE_ASSERT(Parser->TemplateParams.size() >= OldNumTemplateParamLists, + ""); + Parser->TemplateParams.shrinkToSize(OldNumTemplateParamLists); } + TemplateParamList *params() { return &Params; } }; // Template parameter table. Like the above, but referenced like "T42_". @@ -2428,12 +2653,31 @@ template struct AbstractManglingParser { // parameter list, the corresponding parameter list pointer will be null. PODSmallVector TemplateParams; + class SaveTemplateParams { + AbstractManglingParser *Parser; + decltype(TemplateParams) OldParams; + decltype(OuterTemplateParams) OldOuterParams; + + public: + SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { + OldParams = std::move(Parser->TemplateParams); + OldOuterParams = std::move(Parser->OuterTemplateParams); + Parser->TemplateParams.clear(); + Parser->OuterTemplateParams.clear(); + } + ~SaveTemplateParams() { + Parser->TemplateParams = std::move(OldParams); + Parser->OuterTemplateParams = std::move(OldOuterParams); + } + }; + // Set of unresolved forward references. These can occur in a // conversion operator's type, and are resolved in the enclosing . PODSmallVector ForwardTemplateRefs; bool TryToParseTemplateArgs = true; bool PermitForwardTemplateReferences = false; + bool InConstraintExpr = false; size_t ParsingLambdaParamsAtLevel = (size_t)-1; unsigned NumSyntheticTemplateParameters[3] = {}; @@ -2472,16 +2716,15 @@ template struct AbstractManglingParser { } NodeArray popTrailingNodeArray(size_t FromPosition) { - assert(FromPosition <= Names.size()); + DEMANGLE_ASSERT(FromPosition <= Names.size(), ""); NodeArray res = makeNodeArray(Names.begin() + (long)FromPosition, Names.end()); - Names.dropBack(FromPosition); + Names.shrinkToSize(FromPosition); return res; } bool consumeIf(std::string_view S) { - if (llvm::itanium_demangle::starts_with( - std::string_view(First, Last - First), S)) { + if (starts_with(std::string_view(First, Last - First), S)) { First += S.size(); return true; } @@ -2514,11 +2757,16 @@ template struct AbstractManglingParser { bool parseSeqId(size_t *Out); Node *parseSubstitution(); Node *parseTemplateParam(); - Node *parseTemplateParamDecl(); + Node *parseTemplateParamDecl(TemplateParamList *Params); Node *parseTemplateArgs(bool TagTemplates = false); Node *parseTemplateArg(); - /// Parse the production. + bool isTemplateParamDecl() { + return look() == 'T' && + std::string_view("yptnk").find(look(1)) != std::string_view::npos; + } + + /// Parse the production. Node *parseExpr(); Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec); Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec); @@ -2531,6 +2779,8 @@ template struct AbstractManglingParser { Node *parseFoldExpr(); Node *parsePointerToMemberConversionExpr(Node::Prec Prec); Node *parseSubobjectExpr(); + Node *parseConstraintExpr(); + Node *parseRequiresExpr(); /// Parse the production. Node *parseType(); @@ -2542,7 +2792,7 @@ template struct AbstractManglingParser { Node *parseClassEnumType(); Node *parseQualifiedType(); - Node *parseEncoding(); + Node *parseEncoding(bool ParseParams = true); bool parseCallOffset(); Node *parseSpecialName(); @@ -2554,6 +2804,7 @@ template struct AbstractManglingParser { Qualifiers CVQualifiers = QualNone; FunctionRefQual ReferenceQualifier = FrefQualNone; size_t ForwardTemplateRefsBegin; + bool HasExplicitObjectParameter = false; NameState(AbstractManglingParser *Enclosing) : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} @@ -2569,7 +2820,7 @@ template struct AbstractManglingParser { return true; ForwardTemplateRefs[I]->Ref = (*TemplateParams[0])[Idx]; } - ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); + ForwardTemplateRefs.shrinkToSize(State.ForwardTemplateRefsBegin); return false; } @@ -2633,10 +2884,10 @@ template struct AbstractManglingParser { std::string_view getSymbol() const { std::string_view Res = Name; if (Kind < Unnameable) { - assert(llvm::itanium_demangle::starts_with(Res, "operator") && - "operator name does not start with 'operator'"); + DEMANGLE_ASSERT(starts_with(Res, "operator"), + "operator name does not start with 'operator'"); Res.remove_prefix(sizeof("operator") - 1); - if (llvm::itanium_demangle::starts_with(Res, ' ')) + if (starts_with(Res, ' ')) Res.remove_prefix(1); } return Res; @@ -2658,7 +2909,7 @@ template struct AbstractManglingParser { Node *parseDestructorName(); /// Top-level entry point into the parser. - Node *parse(); + Node *parse(bool ParseParams = true); }; const char* parse_discriminator(const char* first, const char* last); @@ -2722,6 +2973,10 @@ Node *AbstractManglingParser::parseLocalName(NameState *State) { return make(Encoding, StringLitName); } + // The template parameters of the inner name are unrelated to those of the + // enclosing context. + SaveTemplateParams SaveTemplateParamsScope(this); + if (consumeIf('d')) { parseNumber(true); if (!consumeIf('_')) @@ -2777,9 +3032,9 @@ AbstractManglingParser::parseUnscopedName(NameState *State, return Res; } -// ::= [] L? [] +// ::= [] F? L? [] // ::= [] [] -// ::= [] L? [] +// ::= [] F? L? [] // ::= [] L? [] // # structured binding declaration // ::= [] L? DC + E @@ -2789,6 +3044,8 @@ Node *AbstractManglingParser::parseUnqualifiedName( if (getDerived().parseModuleNameOpt(Module)) return nullptr; + bool IsMemberLikeFriend = Scope && consumeIf('F'); + consumeIf('L'); Node *Result; @@ -2819,7 +3076,9 @@ Node *AbstractManglingParser::parseUnqualifiedName( Result = make(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); - if (Result != nullptr && Scope != nullptr) + if (Result != nullptr && IsMemberLikeFriend) + Result = make(Scope, Result); + else if (Result != nullptr && Scope != nullptr) Result = make(Scope, Result); return Result; @@ -2851,7 +3110,8 @@ bool AbstractManglingParser::parseModuleNameOpt( // // ::= Ul E [ ] _ // -// ::= + # Parameter types or "v" if the lambda has no parameters +// ::= * [Q ] +// + # or "v" if the lambda has no parameters template Node * AbstractManglingParser::parseUnnamedTypeName(NameState *State) { @@ -2872,10 +3132,10 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { ScopedTemplateParamList LambdaTemplateParams(this); size_t ParamsBegin = Names.size(); - while (look() == 'T' && - std::string_view("yptn").find(look(1)) != std::string_view::npos) { - Node *T = parseTemplateParamDecl(); - if (!T) + while (getDerived().isTemplateParamDecl()) { + Node *T = + getDerived().parseTemplateParamDecl(LambdaTemplateParams.params()); + if (T == nullptr) return nullptr; Names.push_back(T); } @@ -2906,20 +3166,38 @@ AbstractManglingParser::parseUnnamedTypeName(NameState *State) { if (TempParams.empty()) TemplateParams.pop_back(); - if (!consumeIf("vE")) { + Node *Requires1 = nullptr; + if (consumeIf('Q')) { + Requires1 = getDerived().parseConstraintExpr(); + if (Requires1 == nullptr) + return nullptr; + } + + if (!consumeIf("v")) { do { Node *P = getDerived().parseType(); if (P == nullptr) return nullptr; Names.push_back(P); - } while (!consumeIf('E')); + } while (look() != 'E' && look() != 'Q'); } NodeArray Params = popTrailingNodeArray(ParamsBegin); + Node *Requires2 = nullptr; + if (consumeIf('Q')) { + Requires2 = getDerived().parseConstraintExpr(); + if (Requires2 == nullptr) + return nullptr; + } + + if (!consumeIf('E')) + return nullptr; + std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; - return make(TempParams, Params, Count); + return make(TempParams, Requires1, Params, Requires2, + Count); } if (consumeIf("Ub")) { (void)parseNumber(); @@ -2940,7 +3218,7 @@ Node *AbstractManglingParser::parseSourceName(NameState *) { return nullptr; std::string_view Name(First, Length); First += Length; - if (llvm::itanium_demangle::starts_with(Name, "_GLOBAL__N")) + if (starts_with(Name, "_GLOBAL__N")) return make("(anonymous namespace)"); return make(Name); } @@ -3185,15 +3463,25 @@ AbstractManglingParser::parseNestedName(NameState *State) { if (!consumeIf('N')) return nullptr; - Qualifiers CVTmp = parseCVQualifiers(); - if (State) State->CVQualifiers = CVTmp; + // 'H' specifies that the encoding that follows + // has an explicit object parameter. + if (!consumeIf('H')) { + Qualifiers CVTmp = parseCVQualifiers(); + if (State) + State->CVQualifiers = CVTmp; - if (consumeIf('O')) { - if (State) State->ReferenceQualifier = FrefQualRValue; - } else if (consumeIf('R')) { - if (State) State->ReferenceQualifier = FrefQualLValue; - } else { - if (State) State->ReferenceQualifier = FrefQualNone; + if (consumeIf('O')) { + if (State) + State->ReferenceQualifier = FrefQualRValue; + } else if (consumeIf('R')) { + if (State) + State->ReferenceQualifier = FrefQualLValue; + } else { + if (State) + State->ReferenceQualifier = FrefQualNone; + } + } else if (State) { + State->HasExplicitObjectParameter = true; } Node *SoFar = nullptr; @@ -3441,7 +3729,7 @@ Node *AbstractManglingParser::parseUnresolvedName(bool Global) { } } - assert(SoFar != nullptr); + DEMANGLE_ASSERT(SoFar != nullptr, ""); Node *Base = getDerived().parseBaseUnresolvedName(); if (Base == nullptr) @@ -3709,7 +3997,7 @@ Node *AbstractManglingParser::parseQualifiedType() { return nullptr; // extension ::= U # objc-type - if (llvm::itanium_demangle::starts_with(Qual, "objcproto")) { + if (starts_with(Qual, "objcproto")) { constexpr size_t Len = sizeof("objcproto") - 1; std::string_view ProtoSourceName(Qual.data() + Len, Qual.size() - Len); std::string_view Proto; @@ -3889,7 +4177,15 @@ Node *AbstractManglingParser::parseType() { // Typically, s are not considered substitution candidates, // but the exception to that exception is vendor extended types (Itanium C++ // ABI 5.9.1). - Result = make(Res); + if (consumeIf('I')) { + Node *BaseType = parseType(); + if (BaseType == nullptr) + return nullptr; + if (!consumeIf('E')) + return nullptr; + Result = make(Res, BaseType); + } else + Result = make(Res); break; } case 'D': @@ -3956,6 +4252,17 @@ Node *AbstractManglingParser::parseType() { case 'c': First += 2; return make("decltype(auto)"); + // ::= Dk # constrained auto + // ::= DK # constrained decltype(auto) + case 'k': + case 'K': { + std::string_view Kind = look(1) == 'k' ? " auto" : " decltype(auto)"; + First += 2; + Node *Constraint = getDerived().parseName(); + if (!Constraint) + return nullptr; + return make(Constraint, Kind); + } // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) case 'n': First += 2; @@ -4507,6 +4814,75 @@ Node *AbstractManglingParser::parseSubobjectExpr() { Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); } +template +Node *AbstractManglingParser::parseConstraintExpr() { + // Within this expression, all enclosing template parameter lists are in + // scope. + ScopedOverride SaveInConstraintExpr(InConstraintExpr, true); + return getDerived().parseExpr(); +} + +template +Node *AbstractManglingParser::parseRequiresExpr() { + NodeArray Params; + if (consumeIf("rQ")) { + // ::= rQ _ + E + size_t ParamsBegin = Names.size(); + while (!consumeIf('_')) { + Node *Type = getDerived().parseType(); + if (Type == nullptr) + return nullptr; + Names.push_back(Type); + } + Params = popTrailingNodeArray(ParamsBegin); + } else if (!consumeIf("rq")) { + // ::= rq + E + return nullptr; + } + + size_t ReqsBegin = Names.size(); + do { + Node *Constraint = nullptr; + if (consumeIf('X')) { + // ::= X [N] [R ] + Node *Expr = getDerived().parseExpr(); + if (Expr == nullptr) + return nullptr; + bool Noexcept = consumeIf('N'); + Node *TypeReq = nullptr; + if (consumeIf('R')) { + TypeReq = getDerived().parseName(); + if (TypeReq == nullptr) + return nullptr; + } + Constraint = make(Expr, Noexcept, TypeReq); + } else if (consumeIf('T')) { + // ::= T + Node *Type = getDerived().parseType(); + if (Type == nullptr) + return nullptr; + Constraint = make(Type); + } else if (consumeIf('Q')) { + // ::= Q + // + // FIXME: We use instead of . Either + // the requires expression is already inside a constraint expression, in + // which case it makes no difference, or we're in a requires-expression + // that might be partially-substituted, where the language behavior is + // not yet settled and clang mangles after substitution. + Node *NestedReq = getDerived().parseExpr(); + if (NestedReq == nullptr) + return nullptr; + Constraint = make(NestedReq); + } + if (Constraint == nullptr) + return nullptr; + Names.push_back(Constraint); + } while (!consumeIf('E')); + + return make(Params, popTrailingNodeArray(ReqsBegin)); +} + // ::= // ::= // ::= @@ -4743,6 +5119,8 @@ Node *AbstractManglingParser::parseExpr() { return Ex; return make("noexcept ", Ex, Node::Prec::Unary); } + if (look() == 'r' && (look(1) == 'q' || look(1) == 'Q')) + return parseRequiresExpr(); if (consumeIf("so")) return parseSubobjectExpr(); if (consumeIf("sp")) { @@ -5021,29 +5399,14 @@ Node *AbstractManglingParser::parseSpecialName() { } // ::= +// [`Q` ] // ::= // ::= template -Node *AbstractManglingParser::parseEncoding() { +Node *AbstractManglingParser::parseEncoding(bool ParseParams) { // The template parameters of an encoding are unrelated to those of the // enclosing context. - class SaveTemplateParams { - AbstractManglingParser *Parser; - decltype(TemplateParams) OldParams; - decltype(OuterTemplateParams) OldOuterParams; - - public: - SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { - OldParams = std::move(Parser->TemplateParams); - OldOuterParams = std::move(Parser->OuterTemplateParams); - Parser->TemplateParams.clear(); - Parser->OuterTemplateParams.clear(); - } - ~SaveTemplateParams() { - Parser->TemplateParams = std::move(OldParams); - Parser->OuterTemplateParams = std::move(OldOuterParams); - } - } SaveTemplateParams(this); + SaveTemplateParams SaveTemplateParamsScope(this); if (look() == 'G' || look() == 'T') return getDerived().parseSpecialName(); @@ -5066,6 +5429,16 @@ Node *AbstractManglingParser::parseEncoding() { if (IsEndOfEncoding()) return Name; + // ParseParams may be false at the top level only, when called from parse(). + // For example in the mangled name _Z3fooILZ3BarEET_f, ParseParams may be + // false when demangling 3fooILZ3BarEET_f but is always true when demangling + // 3Bar. + if (!ParseParams) { + while (consume()) + ; + return Name; + } + Node *Attrs = nullptr; if (consumeIf("Ua9enable_ifI")) { size_t BeforeArgs = Names.size(); @@ -5087,22 +5460,35 @@ Node *AbstractManglingParser::parseEncoding() { return nullptr; } - if (consumeIf('v')) - return make(ReturnType, Name, NodeArray(), - Attrs, NameInfo.CVQualifiers, - NameInfo.ReferenceQualifier); + NodeArray Params; + if (!consumeIf('v')) { + size_t ParamsBegin = Names.size(); + do { + Node *Ty = getDerived().parseType(); + if (Ty == nullptr) + return nullptr; - size_t ParamsBegin = Names.size(); - do { - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) + const bool IsFirstParam = ParamsBegin == Names.size(); + if (NameInfo.HasExplicitObjectParameter && IsFirstParam) + Ty = make(Ty); + + if (Ty == nullptr) + return nullptr; + + Names.push_back(Ty); + } while (!IsEndOfEncoding() && look() != 'Q'); + Params = popTrailingNodeArray(ParamsBegin); + } + + Node *Requires = nullptr; + if (consumeIf('Q')) { + Requires = getDerived().parseConstraintExpr(); + if (!Requires) return nullptr; - Names.push_back(Ty); - } while (!IsEndOfEncoding()); + } - return make(ReturnType, Name, - popTrailingNodeArray(ParamsBegin), - Attrs, NameInfo.CVQualifiers, + return make(ReturnType, Name, Params, Attrs, Requires, + NameInfo.CVQualifiers, NameInfo.ReferenceQualifier); } @@ -5129,7 +5515,8 @@ template <> struct FloatData { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) || defined(__riscv) || defined(__loongarch__) + defined(__wasm__) || defined(__riscv) || defined(__loongarch__) || \ + defined(__ve__) static const size_t mangled_size = 32; #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) static const size_t mangled_size = 16; @@ -5153,7 +5540,7 @@ Node *AbstractManglingParser::parseFloatingLiteral() { return nullptr; std::string_view Data(First, N); for (char C : Data) - if (!std::isxdigit(C)) + if (!(C >= '0' && C <= '9') && !(C >= 'a' && C <= 'f')) return nullptr; First += N; if (!consumeIf('E')) @@ -5263,6 +5650,7 @@ Node *AbstractManglingParser::parseSubstitution() { // ::= TL _ _ template Node *AbstractManglingParser::parseTemplateParam() { + const char *Begin = First; if (!consumeIf('T')) return nullptr; @@ -5284,6 +5672,14 @@ Node *AbstractManglingParser::parseTemplateParam() { return nullptr; } + // We don't track enclosing template parameter levels well enough to reliably + // substitute them all within a , so print the + // parameter numbering instead for now. + // TODO: Track all enclosing template parameters and substitute them here. + if (InConstraintExpr) { + return make(std::string_view(Begin, First - 1 - Begin)); + } + // If we're in a context where this refers to a // further ahead in the mangled name (currently just conversion // operator types), then we should only look it up in the right context. @@ -5292,7 +5688,8 @@ Node *AbstractManglingParser::parseTemplateParam() { Node *ForwardRef = make(Index); if (!ForwardRef) return nullptr; - assert(ForwardRef->getKind() == Node::KForwardTemplateReference); + DEMANGLE_ASSERT(ForwardRef->getKind() == Node::KForwardTemplateReference, + ""); ForwardTemplateRefs.push_back( static_cast(ForwardRef)); return ForwardRef; @@ -5317,15 +5714,18 @@ Node *AbstractManglingParser::parseTemplateParam() { } // ::= Ty # type parameter +// ::= Tk [] # constrained type parameter // ::= Tn # non-type parameter // ::= Tt * E # template parameter // ::= Tp # parameter pack template -Node *AbstractManglingParser::parseTemplateParamDecl() { +Node *AbstractManglingParser::parseTemplateParamDecl( + TemplateParamList *Params) { auto InventTemplateParamName = [&](TemplateParamKind Kind) { unsigned Index = NumSyntheticTemplateParameters[(int)Kind]++; Node *N = make(Kind, Index); - if (N) TemplateParams.back()->push_back(N); + if (N && Params) + Params->push_back(N); return N; }; @@ -5336,6 +5736,16 @@ Node *AbstractManglingParser::parseTemplateParamDecl() { return make(Name); } + if (consumeIf("Tk")) { + Node *Constraint = getDerived().parseName(); + if (!Constraint) + return nullptr; + Node *Name = InventTemplateParamName(TemplateParamKind::Type); + if (!Name) + return nullptr; + return make(Constraint, Name); + } + if (consumeIf("Tn")) { Node *Name = InventTemplateParamName(TemplateParamKind::NonType); if (!Name) @@ -5352,18 +5762,25 @@ Node *AbstractManglingParser::parseTemplateParamDecl() { return nullptr; size_t ParamsBegin = Names.size(); ScopedTemplateParamList TemplateTemplateParamParams(this); - while (!consumeIf("E")) { - Node *P = parseTemplateParamDecl(); + Node *Requires = nullptr; + while (!consumeIf('E')) { + Node *P = parseTemplateParamDecl(TemplateTemplateParamParams.params()); if (!P) return nullptr; Names.push_back(P); + if (consumeIf('Q')) { + Requires = getDerived().parseConstraintExpr(); + if (Requires == nullptr || !consumeIf('E')) + return nullptr; + break; + } } - NodeArray Params = popTrailingNodeArray(ParamsBegin); - return make(Name, Params); + NodeArray InnerParams = popTrailingNodeArray(ParamsBegin); + return make(Name, InnerParams, Requires); } if (consumeIf("Tp")) { - Node *P = parseTemplateParamDecl(); + Node *P = parseTemplateParamDecl(Params); if (!P) return nullptr; return make(P); @@ -5377,6 +5794,7 @@ Node *AbstractManglingParser::parseTemplateParamDecl() { // ::= # simple expressions // ::= J * E # argument pack // ::= LZ E # extension +// ::= template Node *AbstractManglingParser::parseTemplateArg() { switch (look()) { @@ -5411,12 +5829,24 @@ Node *AbstractManglingParser::parseTemplateArg() { // ::= # simple expressions return getDerived().parseExprPrimary(); } + case 'T': { + // Either or a . + if (!getDerived().isTemplateParamDecl()) + return getDerived().parseType(); + Node *Param = getDerived().parseTemplateParamDecl(nullptr); + if (!Param) + return nullptr; + Node *Arg = getDerived().parseTemplateArg(); + if (!Arg) + return nullptr; + return make(Param, Arg); + } default: return getDerived().parseType(); } } -// ::= I * E +// ::= I * [Q ] E // extension, the abi says + template Node * @@ -5433,30 +5863,39 @@ AbstractManglingParser::parseTemplateArgs(bool TagTemplates) { } size_t ArgsBegin = Names.size(); + Node *Requires = nullptr; while (!consumeIf('E')) { if (TagTemplates) { - auto OldParams = std::move(TemplateParams); Node *Arg = getDerived().parseTemplateArg(); - TemplateParams = std::move(OldParams); if (Arg == nullptr) return nullptr; Names.push_back(Arg); Node *TableEntry = Arg; + if (Arg->getKind() == Node::KTemplateParamQualifiedArg) { + TableEntry = + static_cast(TableEntry)->getArg(); + } if (Arg->getKind() == Node::KTemplateArgumentPack) { TableEntry = make( static_cast(TableEntry)->getElements()); if (!TableEntry) return nullptr; } - TemplateParams.back()->push_back(TableEntry); + OuterTemplateParams.push_back(TableEntry); } else { Node *Arg = getDerived().parseTemplateArg(); if (Arg == nullptr) return nullptr; Names.push_back(Arg); } + if (consumeIf('Q')) { + Requires = getDerived().parseConstraintExpr(); + if (!Requires || !consumeIf('E')) + return nullptr; + break; + } } - return make(popTrailingNodeArray(ArgsBegin)); + return make(popTrailingNodeArray(ArgsBegin), Requires); } // ::= _Z @@ -5465,9 +5904,9 @@ AbstractManglingParser::parseTemplateArgs(bool TagTemplates) { // extension ::= ___Z _block_invoke+ // extension ::= ___Z _block_invoke_+ template -Node *AbstractManglingParser::parse() { +Node *AbstractManglingParser::parse(bool ParseParams) { if (consumeIf("_Z") || consumeIf("__Z")) { - Node *Encoding = getDerived().parseEncoding(); + Node *Encoding = getDerived().parseEncoding(ParseParams); if (Encoding == nullptr) return nullptr; if (look() == '.') { @@ -5481,7 +5920,7 @@ Node *AbstractManglingParser::parse() { } if (consumeIf("___Z") || consumeIf("____Z")) { - Node *Encoding = getDerived().parseEncoding(); + Node *Encoding = getDerived().parseEncoding(ParseParams); if (Encoding == nullptr || !consumeIf("_block_invoke")) return nullptr; bool RequireNumber = consumeIf('_'); @@ -5508,4 +5947,8 @@ struct ManglingParser : AbstractManglingParser, Alloc> { DEMANGLE_NAMESPACE_END +#ifdef _LIBCXXABI_COMPILER_CLANG +#pragma clang diagnostic pop +#endif + #endif // DEMANGLE_ITANIUMDEMANGLE_H diff --git a/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def b/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def index c0e277d..3305526 100644 --- a/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def +++ b/third_party/llvm/include/llvm/Demangle/ItaniumNodes.def @@ -19,6 +19,7 @@ NODE(QualType) NODE(ConversionOperatorType) NODE(PostfixQualifiedType) NODE(ElaboratedTypeSpefType) +NODE(TransformedType) NODE(NameType) NODE(AbiTagAttr) NODE(EnableIfAttr) @@ -36,6 +37,7 @@ NODE(SpecialName) NODE(CtorVtableSpecialName) NODE(QualifiedName) NODE(NestedName) +NODE(MemberLikeFriendName) NODE(LocalName) NODE(ModuleName) NODE(ModuleEntity) @@ -44,7 +46,9 @@ NODE(PixelVectorType) NODE(BinaryFPType) NODE(BitIntType) NODE(SyntheticTemplateParamName) +NODE(TemplateParamQualifiedArg) NODE(TypeTemplateParamDecl) +NODE(ConstrainedTypeTemplateParamDecl) NODE(NonTypeTemplateParamDecl) NODE(TemplateTemplateParamDecl) NODE(TemplateParamPackDecl) @@ -91,5 +95,10 @@ NODE(DoubleLiteral) NODE(LongDoubleLiteral) NODE(BracedExpr) NODE(BracedRangeExpr) +NODE(RequiresExpr) +NODE(ExprRequirement) +NODE(TypeRequirement) +NODE(NestedRequirement) +NODE(ExplicitObjectParameter) #undef NODE diff --git a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h index 1529b80..6891185 100644 --- a/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h +++ b/third_party/llvm/include/llvm/Demangle/MicrosoftDemangle.h @@ -54,6 +54,10 @@ class ArenaAllocator { } } + // Delete the copy constructor and the copy assignment operator. + ArenaAllocator(const ArenaAllocator &) = delete; + ArenaAllocator &operator=(const ArenaAllocator &) = delete; + char *allocUnalignedBuffer(size_t Size) { assert(Head && Head->Buf); diff --git a/third_party/llvm/include/llvm/Demangle/Utility.h b/third_party/llvm/include/llvm/Demangle/Utility.h index a906d23..e893cce 100644 --- a/third_party/llvm/include/llvm/Demangle/Utility.h +++ b/third_party/llvm/include/llvm/Demangle/Utility.h @@ -19,11 +19,9 @@ #include "DemangleConfig.h" #include -#include #include #include #include -#include #include #include @@ -49,7 +47,7 @@ class OutputBuffer { BufferCapacity = Need; Buffer = static_cast(std::realloc(Buffer, BufferCapacity)); if (Buffer == nullptr) - std::terminate(); + std::abort(); } } @@ -160,7 +158,7 @@ class OutputBuffer { } void insert(size_t Pos, const char *S, size_t N) { - assert(Pos <= CurrentPosition); + DEMANGLE_ASSERT(Pos <= CurrentPosition, ""); if (N == 0) return; grow(N); @@ -173,7 +171,7 @@ class OutputBuffer { void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } char back() const { - assert(CurrentPosition); + DEMANGLE_ASSERT(CurrentPosition, ""); return Buffer[CurrentPosition - 1]; } diff --git a/third_party/llvm/lib/Demangle/Demangle.cpp b/third_party/llvm/lib/Demangle/Demangle.cpp index f2aa571..117b849 100644 --- a/third_party/llvm/lib/Demangle/Demangle.cpp +++ b/third_party/llvm/lib/Demangle/Demangle.cpp @@ -24,7 +24,8 @@ std::string llvm::demangle(std::string_view MangledName) { return Result; if (starts_with(MangledName, '_') && - nonMicrosoftDemangle(MangledName.substr(1), Result)) + nonMicrosoftDemangle(MangledName.substr(1), Result, + /*CanHaveLeadingDot=*/false)) return Result; if (char *Demangled = microsoftDemangle(MangledName, nullptr, nullptr)) { @@ -46,10 +47,18 @@ static bool isRustEncoding(std::string_view S) { return starts_with(S, "_R"); } static bool isDLangEncoding(std::string_view S) { return starts_with(S, "_D"); } bool llvm::nonMicrosoftDemangle(std::string_view MangledName, - std::string &Result) { + std::string &Result, bool CanHaveLeadingDot, + bool ParseParams) { char *Demangled = nullptr; + + // Do not consider the dot prefix as part of the demangled symbol name. + if (CanHaveLeadingDot && MangledName.size() > 0 && MangledName[0] == '.') { + MangledName.remove_prefix(1); + Result = "."; + } + if (isItaniumEncoding(MangledName)) - Demangled = itaniumDemangle(MangledName); + Demangled = itaniumDemangle(MangledName, ParseParams); else if (isRustEncoding(MangledName)) Demangled = rustDemangle(MangledName); else if (isDLangEncoding(MangledName)) @@ -58,7 +67,7 @@ bool llvm::nonMicrosoftDemangle(std::string_view MangledName, if (!Demangled) return false; - Result = Demangled; + Result += Demangled; std::free(Demangled); return true; } diff --git a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp index e3f208f..5c21b06 100644 --- a/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp +++ b/third_party/llvm/lib/Demangle/ItaniumDemangle.cpp @@ -366,13 +366,13 @@ class DefaultAllocator { using Demangler = itanium_demangle::ManglingParser; -char *llvm::itaniumDemangle(std::string_view MangledName) { +char *llvm::itaniumDemangle(std::string_view MangledName, bool ParseParams) { if (MangledName.empty()) return nullptr; Demangler Parser(MangledName.data(), MangledName.data() + MangledName.length()); - Node *AST = Parser.parse(); + Node *AST = Parser.parse(ParseParams); if (!AST) return nullptr; diff --git a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp index cd7ff40..c5835e8 100644 --- a/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -53,6 +53,18 @@ static bool consumeFront(std::string_view &S, std::string_view C) { return true; } +static bool consumeFront(std::string_view &S, std::string_view PrefixA, + std::string_view PrefixB, bool A) { + const std::string_view &Prefix = A ? PrefixA : PrefixB; + return consumeFront(S, Prefix); +} + +static bool startsWith(std::string_view S, std::string_view PrefixA, + std::string_view PrefixB, bool A) { + const std::string_view &Prefix = A ? PrefixA : PrefixB; + return llvm::itanium_demangle::starts_with(S, Prefix); +} + static bool isMemberPointer(std::string_view MangledName, bool &Error) { Error = false; const char F = MangledName.front(); @@ -2256,6 +2268,18 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) { NodeList &TP = **Current; + // ::= $ M + const bool IsAutoNTTP = consumeFront(MangledName, "$M"); + if (IsAutoNTTP) { + // The deduced type of the auto NTTP parameter isn't printed so + // we want to ignore the AST created from demangling the type. + // + // TODO: Avoid the extra allocations to the bump allocator in this case. + (void)demangleType(MangledName, QualifierMangleMode::Drop); + if (Error) + return nullptr; + } + TemplateParameterReferenceNode *TPRN = nullptr; if (consumeFront(MangledName, "$$Y")) { // Template alias @@ -2266,15 +2290,17 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) { } else if (consumeFront(MangledName, "$$C")) { // Type has qualifiers. TP.N = demangleType(MangledName, QualifierMangleMode::Mangle); - } else if (llvm::itanium_demangle::starts_with(MangledName, "$1") || - llvm::itanium_demangle::starts_with(MangledName, "$H") || - llvm::itanium_demangle::starts_with(MangledName, "$I") || - llvm::itanium_demangle::starts_with(MangledName, "$J")) { + } else if (startsWith(MangledName, "$1", "1", !IsAutoNTTP) || + startsWith(MangledName, "$H", "H", !IsAutoNTTP) || + startsWith(MangledName, "$I", "I", !IsAutoNTTP) || + startsWith(MangledName, "$J", "J", !IsAutoNTTP)) { // Pointer to member TP.N = TPRN = Arena.alloc(); TPRN->IsMemberPointer = true; - MangledName.remove_prefix(1); + if (!IsAutoNTTP) + MangledName.remove_prefix(1); // Remove leading '$' + // 1 - single inheritance // H - multiple inheritance // I - virtual inheritance @@ -2317,12 +2343,13 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) { TP.N = TPRN = Arena.alloc(); TPRN->Symbol = parse(MangledName); TPRN->Affinity = PointerAffinity::Reference; - } else if (llvm::itanium_demangle::starts_with(MangledName, "$F") || - llvm::itanium_demangle::starts_with(MangledName, "$G")) { + } else if (startsWith(MangledName, "$F", "F", !IsAutoNTTP) || + startsWith(MangledName, "$G", "G", !IsAutoNTTP)) { TP.N = TPRN = Arena.alloc(); // Data member pointer. - MangledName.remove_prefix(1); + if (!IsAutoNTTP) + MangledName.remove_prefix(1); // Remove leading '$' char InheritanceSpecifier = MangledName.front(); MangledName.remove_prefix(1); @@ -2342,7 +2369,7 @@ Demangler::demangleTemplateParameterList(std::string_view &MangledName) { } TPRN->IsMemberPointer = true; - } else if (consumeFront(MangledName, "$0")) { + } else if (consumeFront(MangledName, "$0", "0", !IsAutoNTTP)) { // Integral non-type template parameter bool IsNegative = false; uint64_t Value = 0;