Author: epilk Date: Sun Mar 25 15:50:33 2018 New Revision: 328464 URL: http://llvm.org/viewvc/llvm-project?rev=328464&view=rev Log: [demangler] Use a back-patching scheme to resolve forward references.
Strictly in a conversion operator's type, a <template-param> refers to a <template-arg> that is further ahead in the mangled name. Instead of doing a second parse to resolve these, introduce a ForwardTemplateReference Node and back-patch the referenced <template-arg> when we're in the right context. This is also a correctness fix, previously we would only do a second parse if the <template-param> was out of bounds in the current set of <template-args>. This lead to misdemangles (gasp!) when the conversion operator was a member of a templated struct, for instance. Modified: libcxxabi/trunk/src/cxa_demangle.cpp libcxxabi/trunk/test/test_demangle.pass.cpp Modified: libcxxabi/trunk/src/cxa_demangle.cpp URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=328464&r1=328463&r2=328464&view=diff ============================================================================== --- libcxxabi/trunk/src/cxa_demangle.cpp (original) +++ libcxxabi/trunk/src/cxa_demangle.cpp Sun Mar 25 15:50:33 2018 @@ -190,6 +190,7 @@ public: KTemplateArgumentPack, KParameterPackExpansion, KTemplateArgs, + KForwardTemplateReference, KNameWithTemplateArgs, KGlobalQualifiedName, KStdQualifiedName, @@ -1091,6 +1092,29 @@ public: } }; +struct ForwardTemplateReference : Node { + size_t Index; + Node *Ref = nullptr; + + ForwardTemplateReference(size_t Index_) + : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown, + Cache::Unknown), + Index(Index_) {} + + bool hasRHSComponentSlow(OutputStream &S) const override { + return Ref->hasRHSComponent(S); + } + bool hasArraySlow(OutputStream &S) const override { + return Ref->hasArray(S); + } + bool hasFunctionSlow(OutputStream &S) const override { + return Ref->hasFunction(S); + } + + void printLeft(OutputStream &S) const override { Ref->printLeft(S); } + void printRight(OutputStream &S) const override { Ref->printRight(S); } +}; + class NameWithTemplateArgs final : public Node { // name<template_args> Node *Name; @@ -1924,10 +1948,12 @@ struct Db { // stored on the stack. PODSmallVector<Node *, 8> TemplateParams; - unsigned EncodingDepth = 0; - bool TagTemplates = true; - bool FixForwardReferences = false; + // Set of unresolved forward <template-param> references. These can occur in a + // conversion operator's type, and are resolved in the enclosing <encoding>. + PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs; + bool TryToParseTemplateArgs = true; + bool PermitForwardTemplateReferences = false; bool ParsingLambdaParams = false; BumpPointerAllocator ASTAllocator; @@ -1989,7 +2015,7 @@ struct Db { bool parseSeqId(size_t *Out); Node *parseSubstitution(); Node *parseTemplateParam(); - Node *parseTemplateArgs(); + Node *parseTemplateArgs(bool TagTemplates = false); Node *parseTemplateArg(); /// Parse the <expr> production. @@ -2025,8 +2051,25 @@ struct Db { bool EndsWithTemplateArgs = false; Qualifiers CVQualifiers = QualNone; FunctionRefQual ReferenceQualifier = FrefQualNone; + size_t ForwardTemplateRefsBegin; + + NameState(Db *Enclosing) + : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {} }; + bool resolveForwardTemplateRefs(NameState &State) { + size_t I = State.ForwardTemplateRefsBegin; + size_t E = ForwardTemplateRefs.size(); + for (; I < E; ++I) { + size_t Idx = ForwardTemplateRefs[I]->Index; + if (Idx >= TemplateParams.size()) + return true; + ForwardTemplateRefs[I]->Ref = TemplateParams[Idx]; + } + ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin); + return false; + } + /// Parse the <name> production> Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); @@ -2075,7 +2118,7 @@ Node *Db::parseName(NameState *State) { return nullptr; if (look() != 'I') return nullptr; - Node *TA = parseTemplateArgs(); + Node *TA = parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; if (State) State->EndsWithTemplateArgs = true; @@ -2088,7 +2131,7 @@ Node *Db::parseName(NameState *State) { // ::= <unscoped-template-name> <template-args> if (look() == 'I') { Subs.push_back(N); - Node *TA = parseTemplateArgs(); + Node *TA = parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; if (State) State->EndsWithTemplateArgs = true; @@ -2302,9 +2345,15 @@ Node *Db::parseOperatorName(NameState *S return make<NameType>("operator~"); // ::= cv <type> # (cast) case 'v': { - SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false); First += 2; - Node *Ty = parseType(); + SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false); + // If we're parsing an encoding, State != nullptr and the conversion + // operators' <type> could have a <template-param> that refers to some + // <template-arg>s further ahead in the mangled name. + SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences, + PermitForwardTemplateReferences || + State != nullptr); + Node* Ty = parseType(); if (Ty == nullptr) return nullptr; if (State) State->CtorDtorConversion = true; @@ -2528,7 +2577,7 @@ Node *Db::parseCtorDtorName(Node *&SoFar ++First; if (State) State->CtorDtorConversion = true; if (IsInherited) { - if (parseName() == nullptr) + if (parseName(State) == nullptr) return nullptr; } return make<CtorDtorName>(SoFar, false); @@ -2598,7 +2647,7 @@ Node *Db::parseNestedName(NameState *Sta // ::= <template-prefix> <template-args> if (look() == 'I') { - Node *TA = parseTemplateArgs(); + Node *TA = parseTemplateArgs(State != nullptr); if (TA == nullptr || SoFar == nullptr) return nullptr; SoFar = make<NameWithTemplateArgs>(SoFar, TA); @@ -4369,15 +4418,6 @@ Node *Db::parseSpecialName() { // ::= <data name> // ::= <special-name> Node *Db::parseEncoding() { - // Always "tag" templates (insert them into Db::TemplateParams) unless we're - // doing a second parse to resolve a forward template reference, in which case - // we only tag templates if EncodingDepth > 1. - // FIXME: This is kinda broken; it would be better to make a forward reference - // and patch it all in one pass. - SwapAndRestore<bool> SaveTagTemplates(TagTemplates, - TagTemplates || EncodingDepth); - SwapAndRestore<unsigned> SaveEncodingDepth(EncodingDepth, EncodingDepth + 1); - if (look() == 'G' || look() == 'T') return parseSpecialName(); @@ -4388,12 +4428,16 @@ Node *Db::parseEncoding() { return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_'; }; - NameState NameInfo; + NameState NameInfo(this); Node *Name = parseName(&NameInfo); - if (Name == nullptr || IsEndOfEncoding()) - return Name; + if (Name == nullptr) + return nullptr; - TagTemplates = false; + if (resolveForwardTemplateRefs(NameInfo)) + return nullptr; + + if (IsEndOfEncoding()) + return Name; Node *Attrs = nullptr; if (consumeIf("Ua9enable_ifI")) { @@ -4601,10 +4645,16 @@ Node *Db::parseTemplateParam() { if (ParsingLambdaParams) return make<NameType>("auto"); - if (Index >= TemplateParams.size()) { - FixForwardReferences = true; - return make<NameType>("FORWARD_REFERENCE"); + // If we're in a context where this <template-param> refers to a + // <template-arg> further ahead in the mangled name (currently just conversion + // operator types), then we should only look it up in the right context. + if (PermitForwardTemplateReferences) { + ForwardTemplateRefs.push_back(make<ForwardTemplateReference>(Index)); + return ForwardTemplateRefs.back(); } + + if (Index >= TemplateParams.size()) + return nullptr; return TemplateParams[Index]; } @@ -4653,7 +4703,7 @@ Node *Db::parseTemplateArg() { // <template-args> ::= I <template-arg>* E // extension, the abi says <template-arg>+ -Node *Db::parseTemplateArgs() { +Node *Db::parseTemplateArgs(bool TagTemplates) { if (!consumeIf('I')) return nullptr; @@ -4790,20 +4840,9 @@ __cxa_demangle(const char *MangledName, if (AST == nullptr) InternalStatus = invalid_mangled_name; - if (InternalStatus == success && Parser.FixForwardReferences && - !Parser.TemplateParams.empty()) { - Parser.FixForwardReferences = false; - Parser.TagTemplates = false; - Parser.Names.clear(); - Parser.Subs.clear(); - Parser.First = MangledName; - Parser.Last = MangledName + MangledNameLength; - AST = Parser.parse(); - if (AST == nullptr || Parser.FixForwardReferences) - InternalStatus = invalid_mangled_name; - } - if (InternalStatus == success) { + assert(Parser.ForwardTemplateRefs.empty()); + if (Buf == nullptr) { BufSize = 1024; Buf = static_cast<char*>(std::malloc(BufSize)); Modified: libcxxabi/trunk/test/test_demangle.pass.cpp URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=328464&r1=328463&r2=328464&view=diff ============================================================================== --- libcxxabi/trunk/test/test_demangle.pass.cpp (original) +++ libcxxabi/trunk/test/test_demangle.pass.cpp Sun Mar 25 15:50:33 2018 @@ -29732,6 +29732,12 @@ const char* cases[][2] = {"_Z1fUa9enable_ifIXLi1EEEv", "f() [enable_if:1]"}, {"_ZN5test4IdE1fEUa9enable_ifIXeqfL0p_Li1EEXeqfL0p0_Li2EEEi", "test4<double>::f(int) [enable_if:(fp) == (1), (fp0) == (2)]"}, {"_Z3quxUa9enable_ifIXLi1EEXL_Z9TRUEFACTSEEEi", "qux(int) [enable_if:1, TRUEFACTS]"}, + + // Conversion operators: + {"_ZN5OuterI4MarpEcv7MuncherIJT_T0_DpT1_EEI4MerpS0_JicfEEEv", "Outer<Marp>::operator Muncher<Merp, Marp, int, char, float><Merp, Marp, int, char, float>()"}, + {"_ZN5OuterI4MarpEcvT_I4MerpEEv", "Outer<Marp>::operator Merp<Merp>()"}, + {"_ZZN5OuterI4MarpEcv7MuncherIJT_T0_DpT1_EEI4MerpS0_JicfEEEvEN1ScvS9_Ev", "Outer<Marp>::operator Muncher<Merp, Marp, int, char, float><Merp, Marp, int, char, float>()::S::operator Merp()"}, + {"_ZN1Scv7MuncherIJDpPT_EEIJFivEA_iEEEv", "S::operator Muncher<int (*)(), int (*) []><int (), int []>()"}, }; const unsigned N = sizeof(cases) / sizeof(cases[0]); @@ -29799,11 +29805,11 @@ const char* invalid_cases[] = "Z1 Z1 IJEEAcvZcvT_EcvT_T_", "T_IZaaIJEEAnaaaT_T__", "PT_IJPNT_IJEET_T_T_T_)J)JKE", -// "1 IJEVNT_T_T_EE", + "1 IJEVNT_T_T_EE", "AT__ZSiIJEEAnwscT_T__", "FSiIJEENT_IoE ", "ZTVSiIZTVSiIZTVSiIZTVSiINIJEET_T_T_T_T_ ", -// "Ana_T_E_T_IJEffffffffffffffersfffffrsrsffffffbgE", + "Ana_T_E_T_IJEffffffffffffffersfffffrsrsffffffbgE", }; const unsigned NI = sizeof(invalid_cases) / sizeof(invalid_cases[0]); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits