demangling process when it does.
Use this to support a "lookup" query for the mangling canonicalizer that
does not create new nodes. This could also be used to implement
demangling with a fixed-size temporary storage buffer.
Reviewers: erik.pilkington
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D51003
llvm-svn: 340670
if (consumeIf('s')) {
First = parse_discriminator(First, Last);
- return make<LocalName>(Encoding, make<NameType>("string literal"));
+ auto *StringLitName = make<NameType>("string literal");
+ if (!StringLitName)
+ return nullptr;
+ return make<LocalName>(Encoding, StringLitName);
}
if (consumeIf('d')) {
case SpecialSubKind::ostream:
case SpecialSubKind::iostream:
SoFar = make<ExpandedSpecialSubstitution>(SSK);
+ if (!SoFar)
+ return nullptr;
default:
break;
}
Node *SoFar = nullptr;
auto PushComponent = [&](Node *Comp) {
+ if (!Comp) return false;
if (SoFar) SoFar = make<NestedName>(SoFar, Comp);
else SoFar = Comp;
if (State) State->EndsWithTemplateArgs = false;
+ return SoFar != nullptr;
};
- if (consumeIf("St"))
+ if (consumeIf("St")) {
SoFar = make<NameType>("std");
+ if (!SoFar)
+ return nullptr;
+ }
while (!consumeIf('E')) {
consumeIf('L'); // extension
// ::= <template-param>
if (look() == 'T') {
- Node *TP = parseTemplateParam();
- if (TP == nullptr)
+ if (!PushComponent(parseTemplateParam()))
return nullptr;
- PushComponent(TP);
Subs.push_back(SoFar);
continue;
}
if (TA == nullptr || SoFar == nullptr)
return nullptr;
SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+ if (!SoFar)
+ return nullptr;
if (State) State->EndsWithTemplateArgs = true;
Subs.push_back(SoFar);
continue;
// ::= <decltype>
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;
}
// ::= <substitution>
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;
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;
}
// ::= <prefix> <unqualified-name>
- Node *N = parseUnqualifiedName(State);
- if (N == nullptr)
+ if (!PushComponent(parseUnqualifiedName(State)))
return nullptr;
- PushComponent(N);
Subs.push_back(SoFar);
}
if (TA == nullptr)
return nullptr;
SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+ if (!SoFar)
+ return nullptr;
}
while (!consumeIf('E')) {
if (Qual == nullptr)
return nullptr;
SoFar = make<QualifiedName>(SoFar, Qual);
+ if (!SoFar)
+ return nullptr;
}
Node *Base = parseBaseUnresolvedName();
SoFar = make<GlobalQualifiedName>(Qual);
else
SoFar = Qual;
+ if (!SoFar)
+ return nullptr;
} while (!consumeIf('E'));
}
// sr <unresolved-type> <base-unresolved-name>
if (TA == nullptr)
return nullptr;
SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+ if (!SoFar)
+ return nullptr;
}
}
if (SN.empty())
return nullptr;
N = make<AbiTagAttr>(N, SN);
+ if (!N)
+ return nullptr;
}
return N;
}
Node *ExceptionSpec = nullptr;
if (consumeIf("Do")) {
ExceptionSpec = make<NameType>("noexcept");
+ if (!ExceptionSpec)
+ return nullptr;
} else if (consumeIf("DO")) {
Node *E = parseExpr();
if (E == nullptr || !consumeIf('E'))
return nullptr;
ExceptionSpec = make<NoexceptSpec>(E);
+ if (!ExceptionSpec)
+ return nullptr;
} else if (consumeIf("Dw")) {
size_t SpecsBegin = Names.size();
while (!consumeIf('E')) {
}
ExceptionSpec =
make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
+ if (!ExceptionSpec)
+ return nullptr;
}
consumeIf("Dx"); // transaction safe
return nullptr;
Names.push_back(Arg);
}
- return make<EnclosingExpr>(
- "sizeof... (", make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)),
- ")");
+ auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin));
+ if (!Pack)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof... (", Pack, ")");
}
}
return nullptr;
Names.push_back(Arg);
}
Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs));
+ if (!Attrs)
+ return nullptr;
}
Node *ReturnType = nullptr;
default:
return nullptr;
}
+ if (!SpecialSub)
+ return nullptr;
// Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>
// has ABI tags, the tags are appended to the substitution; the result is a
// substitutable component.
// operator types), then we should only look it up in the right context.
if (PermitForwardTemplateReferences) {
Node *ForwardRef = make<ForwardTemplateReference>(Index);
+ if (!ForwardRef)
+ return nullptr;
assert(ForwardRef->getKind() == Node::KForwardTemplateReference);
ForwardTemplateRefs.push_back(
static_cast<ForwardTemplateReference *>(ForwardRef));
if (Arg->getKind() == Node::KTemplateArgumentPack) {
TableEntry = make<ParameterPack>(
static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
+ if (!TableEntry)
+ return nullptr;
}
TemplateParams.push_back(TableEntry);
} else {
///
/// 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;
void reset() {}
template<typename T, typename ...Args>
- std::pair<Node*, bool> getOrCreateNode(Args &&...As) {
+ std::pair<Node*, bool> getOrCreateNode(bool CreateNewNodes, Args &&...As) {
llvm::FoldingSetNodeID ID;
profileCtor(ID, NodeKind<T>::Kind, As...);
if (NodeHeader *Existing = Nodes.FindNodeOrInsertPos(ID, InsertPos))
return {static_cast<T*>(Existing->getNode()), false};
+ if (!CreateNewNodes)
+ return {nullptr, true};
+
static_assert(alignof(T) <= alignof(NodeHeader),
"underaligned node header for specific node kind");
void *Storage =
template<typename T, typename... Args>
Node *makeNode(Args &&...As) {
- return getOrCreateNode<T>(std::forward<Args>(As)...).first;
+ return getOrCreateNode<T>(true, std::forward<Args>(As)...).first;
}
void *allocateNodeArray(size_t sz) {
// of creation.
template<>
std::pair<Node *, bool>
-FoldingNodeAllocator::getOrCreateNode<ForwardTemplateReference>(size_t &Index) {
+FoldingNodeAllocator::getOrCreateNode<ForwardTemplateReference>(bool,
+ size_t &Index) {
return {new (RawAlloc.Allocate(sizeof(ForwardTemplateReference),
alignof(ForwardTemplateReference)))
ForwardTemplateReference(Index),
Node *MostRecentlyCreated = nullptr;
Node *TrackedNode = nullptr;
bool TrackedNodeIsUsed = false;
+ bool CreateNewNodes = true;
llvm::SmallDenseMap<Node*, Node*, 32> Remappings;
template<typename T, typename ...Args> Node *makeNodeSimple(Args &&...As) {
std::pair<Node *, bool> Result =
- getOrCreateNode<T>(std::forward<Args>(As)...);
+ getOrCreateNode<T>(CreateNewNodes, std::forward<Args>(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;
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.
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());
ItaniumManglingCanonicalizer::Key
ItaniumManglingCanonicalizer::canonicalize(StringRef Mangling) {
+ P->Demangler.ASTAllocator.setCreateNewNodes(true);
+ P->Demangler.reset(Mangling.begin(), Mangling.end());
+ return reinterpret_cast<Key>(P->Demangler.parse());
+}
+
+ItaniumManglingCanonicalizer::Key
+ItaniumManglingCanonicalizer::lookup(StringRef Mangling) {
+ P->Demangler.ASTAllocator.setCreateNewNodes(false);
P->Demangler.reset(Mangling.begin(), Mangling.end());
return reinterpret_cast<Key>(P->Demangler.parse());
}
//
//===----------------------------------------------------------------------===//
-#include <cstdlib>
#include "llvm/Support/ItaniumManglingCanonicalizer.h"
+
#include "gtest/gtest.h"
+#include <cstdlib>
+#include <map>
+
using EquivalenceError = llvm::ItaniumManglingCanonicalizer::EquivalenceError;
using FragmentKind = llvm::ItaniumManglingCanonicalizer::FragmentKind;
},
{}
},
+};
+static std::initializer_list<Testcase> ForwardTemplateReferenceTestcases = {
// ForwardTemplateReference does not support canonicalization.
// FIXME: We should consider ways of fixing this, perhaps by eliminating
// the ForwardTemplateReference node with a tree transformation.
},
};
-TEST(ItaniumManglingCanonicalizerTest, TestTestcases) {
+template<bool CanonicalizeFirst>
+static void testTestcases(std::initializer_list<Testcase> Testcases) {
for (const auto &Testcase : Testcases) {
llvm::ItaniumManglingCanonicalizer Canonicalizer;
for (const auto &Equiv : Testcase.Equivalences) {
}
using CanonKey = llvm::ItaniumManglingCanonicalizer::Key;
+
+ std::map<const EquivalenceClass*, CanonKey> Keys;
+ if (CanonicalizeFirst)
+ for (const auto &Class : Testcase.Classes)
+ Keys.insert({&Class, Canonicalizer.canonicalize(*Class.begin())});
+
std::map<CanonKey, llvm::StringRef> 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)
}
}
+TEST(ItaniumManglingCanonicalizerTest, TestCanonicalize) {
+ testTestcases<false>(Testcases);
+}
+
+TEST(ItaniumManglingCanonicalizerTest, TestLookup) {
+ testTestcases<true>(Testcases);
+}
+
+TEST(ItaniumManglingCanonicalizerTest, TestForwardTemplateReference) {
+ // lookup(...) after canonicalization (intentionally) returns different
+ // values for this testcase.
+ testTestcases<false>(ForwardTemplateReferenceTestcases);
+}
+
+
TEST(ItaniumManglingCanonicalizerTest, TestInvalidManglings) {
llvm::ItaniumManglingCanonicalizer Canonicalizer;
EXPECT_EQ(Canonicalizer.addEquivalence(FragmentKind::Type, "", "1X"),