Index: llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h =================================================================== --- llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h +++ llvm/trunk/include/llvm/Demangle/ItaniumDemangle.h @@ -2372,7 +2372,10 @@ if (consumeIf('s')) { First = parse_discriminator(First, Last); - return make(Encoding, make("string literal")); + auto *StringLitName = make("string literal"); + if (!StringLitName) + return nullptr; + return make(Encoding, StringLitName); } if (consumeIf('d')) { @@ -2786,6 +2789,8 @@ case SpecialSubKind::ostream: case SpecialSubKind::iostream: SoFar = make(SSK); + if (!SoFar) + return nullptr; default: break; } @@ -2847,13 +2852,18 @@ 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")) + if (consumeIf("St")) { SoFar = make("std"); + if (!SoFar) + return nullptr; + } while (!consumeIf('E')) { consumeIf('L'); // extension @@ -2867,10 +2877,8 @@ // ::= if (look() == 'T') { - Node *TP = parseTemplateParam(); - if (TP == nullptr) + if (!PushComponent(parseTemplateParam())) return nullptr; - PushComponent(TP); Subs.push_back(SoFar); continue; } @@ -2881,6 +2889,8 @@ 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; @@ -2888,10 +2898,8 @@ // ::= if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - Node *DT = parseDecltype(); - if (DT == nullptr) + if (!PushComponent(parseDecltype())) return nullptr; - PushComponent(DT); Subs.push_back(SoFar); continue; } @@ -2899,9 +2907,8 @@ // ::= if (look() == 'S' && look(1) != 't') { Node *S = parseSubstitution(); - if (S == nullptr) + if (!PushComponent(S)) return nullptr; - PushComponent(S); if (SoFar != S) Subs.push_back(S); continue; @@ -2911,10 +2918,8 @@ if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { if (SoFar == nullptr) return nullptr; - Node *CtorDtor = parseCtorDtorName(SoFar, State); - if (CtorDtor == nullptr) + if (!PushComponent(parseCtorDtorName(SoFar, State))) return nullptr; - PushComponent(CtorDtor); SoFar = parseAbiTags(SoFar); if (SoFar == nullptr) return nullptr; @@ -2923,10 +2928,8 @@ } // ::= - Node *N = parseUnqualifiedName(State); - if (N == nullptr) + if (!PushComponent(parseUnqualifiedName(State))) return nullptr; - PushComponent(N); Subs.push_back(SoFar); } @@ -3039,6 +3042,8 @@ if (TA == nullptr) return nullptr; SoFar = make(SoFar, TA); + if (!SoFar) + return nullptr; } while (!consumeIf('E')) { @@ -3046,6 +3051,8 @@ if (Qual == nullptr) return nullptr; SoFar = make(SoFar, Qual); + if (!SoFar) + return nullptr; } Node *Base = parseBaseUnresolvedName(); @@ -3078,6 +3085,8 @@ SoFar = make(Qual); else SoFar = Qual; + if (!SoFar) + return nullptr; } while (!consumeIf('E')); } // sr @@ -3092,6 +3101,8 @@ if (TA == nullptr) return nullptr; SoFar = make(SoFar, TA); + if (!SoFar) + return nullptr; } } @@ -3111,6 +3122,8 @@ if (SN.empty()) return nullptr; N = make(N, SN); + if (!N) + return nullptr; } return N; } @@ -3163,11 +3176,15 @@ Node *ExceptionSpec = nullptr; if (consumeIf("Do")) { ExceptionSpec = make("noexcept"); + if (!ExceptionSpec) + return nullptr; } else if (consumeIf("DO")) { Node *E = parseExpr(); if (E == nullptr || !consumeIf('E')) return nullptr; ExceptionSpec = make(E); + if (!ExceptionSpec) + return nullptr; } else if (consumeIf("Dw")) { size_t SpecsBegin = Names.size(); while (!consumeIf('E')) { @@ -3178,6 +3195,8 @@ } ExceptionSpec = make(popTrailingNodeArray(SpecsBegin)); + if (!ExceptionSpec) + return nullptr; } consumeIf("Dx"); // transaction safe @@ -4517,9 +4536,10 @@ return nullptr; Names.push_back(Arg); } - return make( - "sizeof... (", make(popTrailingNodeArray(ArgsBegin)), - ")"); + auto *Pack = make(popTrailingNodeArray(ArgsBegin)); + if (!Pack) + return nullptr; + return make("sizeof... (", Pack, ")"); } } return nullptr; @@ -4771,6 +4791,8 @@ Names.push_back(Arg); } Attrs = make(popTrailingNodeArray(BeforeArgs)); + if (!Attrs) + return nullptr; } Node *ReturnType = nullptr; @@ -4915,6 +4937,8 @@ default: return nullptr; } + if (!SpecialSub) + return nullptr; // Itanium C++ ABI 5.1.2: If a name that would use a built-in // has ABI tags, the tags are appended to the substitution; the result is a // substitutable component. @@ -4968,6 +4992,8 @@ // operator types), then we should only look it up in the right context. if (PermitForwardTemplateReferences) { Node *ForwardRef = make(Index); + if (!ForwardRef) + return nullptr; assert(ForwardRef->getKind() == Node::KForwardTemplateReference); ForwardTemplateRefs.push_back( static_cast(ForwardRef)); @@ -5047,6 +5073,8 @@ if (Arg->getKind() == Node::KTemplateArgumentPack) { TableEntry = make( static_cast(TableEntry)->getElements()); + if (!TableEntry) + return nullptr; } TemplateParams.push_back(TableEntry); } else { Index: llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h =================================================================== --- llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h +++ llvm/trunk/include/llvm/Support/ItaniumManglingCanonicalizer.h @@ -76,8 +76,14 @@ /// /// Returns Key() if (and only if) the mangling is not a valid Itanium C++ /// ABI mangling. + /// + /// The string denoted by Mangling must live as long as the canonicalizer. Key canonicalize(StringRef Mangling); + /// Find a canonical key for the specified mangling, if one has already been + /// formed. Otherwise returns Key(). + Key lookup(StringRef Mangling); + private: struct Impl; Impl *P; Index: llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp =================================================================== --- llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp +++ llvm/trunk/lib/Support/ItaniumManglingCanonicalizer.cpp @@ -105,7 +105,7 @@ void reset() {} template - std::pair getOrCreateNode(Args &&...As) { + std::pair getOrCreateNode(bool CreateNewNodes, Args &&...As) { llvm::FoldingSetNodeID ID; profileCtor(ID, NodeKind::Kind, As...); @@ -113,6 +113,9 @@ if (NodeHeader *Existing = Nodes.FindNodeOrInsertPos(ID, InsertPos)) return {static_cast(Existing->getNode()), false}; + if (!CreateNewNodes) + return {nullptr, true}; + static_assert(alignof(T) <= alignof(NodeHeader), "underaligned node header for specific node kind"); void *Storage = @@ -125,7 +128,7 @@ template Node *makeNode(Args &&...As) { - return getOrCreateNode(std::forward(As)...).first; + return getOrCreateNode(true, std::forward(As)...).first; } void *allocateNodeArray(size_t sz) { @@ -138,7 +141,8 @@ // of creation. template<> std::pair -FoldingNodeAllocator::getOrCreateNode(size_t &Index) { +FoldingNodeAllocator::getOrCreateNode(bool, + size_t &Index) { return {new (RawAlloc.Allocate(sizeof(ForwardTemplateReference), alignof(ForwardTemplateReference))) ForwardTemplateReference(Index), @@ -149,15 +153,16 @@ Node *MostRecentlyCreated = nullptr; Node *TrackedNode = nullptr; bool TrackedNodeIsUsed = false; + bool CreateNewNodes = true; llvm::SmallDenseMap Remappings; template Node *makeNodeSimple(Args &&...As) { std::pair Result = - getOrCreateNode(std::forward(As)...); + getOrCreateNode(CreateNewNodes, std::forward(As)...); if (Result.second) { // Node is new. Make a note of that. MostRecentlyCreated = Result.first; - } else { + } else if (Result.first) { // Node is pre-existing; check if it's in our remapping table. if (auto *N = Remappings.lookup(Result.first)) { Result.first = N; @@ -185,6 +190,8 @@ void reset() { MostRecentlyCreated = nullptr; } + void setCreateNewNodes(bool CNN) { CreateNewNodes = CNN; } + void addRemapping(Node *A, Node *B) { // Note, we don't need to check whether B is also remapped, because if it // was we would have already remapped it when building it. @@ -230,6 +237,7 @@ ItaniumManglingCanonicalizer::addEquivalence(FragmentKind Kind, StringRef First, StringRef Second) { auto &Alloc = P->Demangler.ASTAllocator; + Alloc.setCreateNewNodes(true); auto Parse = [&](StringRef Str) { P->Demangler.reset(Str.begin(), Str.end()); @@ -302,6 +310,14 @@ ItaniumManglingCanonicalizer::Key ItaniumManglingCanonicalizer::canonicalize(StringRef Mangling) { + P->Demangler.ASTAllocator.setCreateNewNodes(true); + P->Demangler.reset(Mangling.begin(), Mangling.end()); + return reinterpret_cast(P->Demangler.parse()); +} + +ItaniumManglingCanonicalizer::Key +ItaniumManglingCanonicalizer::lookup(StringRef Mangling) { + P->Demangler.ASTAllocator.setCreateNewNodes(false); P->Demangler.reset(Mangling.begin(), Mangling.end()); return reinterpret_cast(P->Demangler.parse()); } Index: llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.cpp =================================================================== --- llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.cpp +++ llvm/trunk/unittests/Support/ItaniumManglingCanonicalizerTest.cpp @@ -7,10 +7,13 @@ // //===----------------------------------------------------------------------===// -#include #include "llvm/Support/ItaniumManglingCanonicalizer.h" + #include "gtest/gtest.h" +#include +#include + using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError; using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind; @@ -222,7 +225,9 @@ }, {} }, +}; +static std::initializer_list ForwardTemplateReferenceTestcases = { // ForwardTemplateReference does not support canonicalization. // FIXME: We should consider ways of fixing this, perhaps by eliminating // the ForwardTemplateReference node with a tree transformation. @@ -245,7 +250,8 @@ }, }; -TEST(ItaniumManglingCanonicalizerTest, TestTestcases) { +template +static void testTestcases(std::initializer_list Testcases) { for (const auto &Testcase : Testcases) { llvm::ItaniumManglingCanonicalizer Canonicalizer; for (const auto &Equiv : Testcase.Equivalences) { @@ -257,11 +263,21 @@ } using CanonKey = llvm::ItaniumManglingCanonicalizer::Key; + + std::map Keys; + if (CanonicalizeFirst) + for (const auto &Class : Testcase.Classes) + Keys.insert({&Class, Canonicalizer.canonicalize(*Class.begin())}); + std::map Found; for (const auto &Class : Testcase.Classes) { - CanonKey ClassKey = {}; + CanonKey ClassKey = Keys[&Class]; for (llvm::StringRef Str : Class) { - CanonKey ThisKey = Canonicalizer.canonicalize(Str); + // Force a copy to be made when calling lookup to test that it doesn't + // retain any part of the provided string. + CanonKey ThisKey = CanonicalizeFirst + ? Canonicalizer.lookup(std::string(Str)) + : Canonicalizer.canonicalize(Str); EXPECT_NE(ThisKey, CanonKey()) << "couldn't canonicalize " << Str; if (ClassKey) { EXPECT_EQ(ThisKey, ClassKey) @@ -276,6 +292,21 @@ } } +TEST(ItaniumManglingCanonicalizerTest, TestCanonicalize) { + testTestcases(Testcases); +} + +TEST(ItaniumManglingCanonicalizerTest, TestLookup) { + testTestcases(Testcases); +} + +TEST(ItaniumManglingCanonicalizerTest, TestForwardTemplateReference) { + // lookup(...) after canonicalization (intentionally) returns different + // values for this testcase. + testTestcases(ForwardTemplateReferenceTestcases); +} + + TEST(ItaniumManglingCanonicalizerTest, TestInvalidManglings) { llvm::ItaniumManglingCanonicalizer Canonicalizer; EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "", "1X"),