mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
Allow demangler's node allocator to fail, and bail out of the entire
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
This commit is contained in:
parent
fa2516f031
commit
b9999617a5
@ -2372,7 +2372,10 @@ template<typename Alloc> Node *Db<Alloc>::parseLocalName(NameState *State) {
|
||||
|
||||
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')) {
|
||||
@ -2786,6 +2789,8 @@ Node *Db<Alloc>::parseCtorDtorName(Node *&SoFar, NameState *State) {
|
||||
case SpecialSubKind::ostream:
|
||||
case SpecialSubKind::iostream:
|
||||
SoFar = make<ExpandedSpecialSubstitution>(SSK);
|
||||
if (!SoFar)
|
||||
return nullptr;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2847,13 +2852,18 @@ template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
|
||||
|
||||
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
|
||||
@ -2867,10 +2877,8 @@ template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
|
||||
|
||||
// ::= <template-param>
|
||||
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 @@ template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
|
||||
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;
|
||||
@ -2888,10 +2898,8 @@ template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
|
||||
|
||||
// ::= <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;
|
||||
}
|
||||
@ -2899,9 +2907,8 @@ template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
|
||||
// ::= <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;
|
||||
@ -2911,10 +2918,8 @@ template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
|
||||
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 @@ template<typename Alloc> Node *Db<Alloc>::parseNestedName(NameState *State) {
|
||||
}
|
||||
|
||||
// ::= <prefix> <unqualified-name>
|
||||
Node *N = parseUnqualifiedName(State);
|
||||
if (N == nullptr)
|
||||
if (!PushComponent(parseUnqualifiedName(State)))
|
||||
return nullptr;
|
||||
PushComponent(N);
|
||||
Subs.push_back(SoFar);
|
||||
}
|
||||
|
||||
@ -3039,6 +3042,8 @@ template<typename Alloc> Node *Db<Alloc>::parseUnresolvedName() {
|
||||
if (TA == nullptr)
|
||||
return nullptr;
|
||||
SoFar = make<NameWithTemplateArgs>(SoFar, TA);
|
||||
if (!SoFar)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (!consumeIf('E')) {
|
||||
@ -3046,6 +3051,8 @@ template<typename Alloc> Node *Db<Alloc>::parseUnresolvedName() {
|
||||
if (Qual == nullptr)
|
||||
return nullptr;
|
||||
SoFar = make<QualifiedName>(SoFar, Qual);
|
||||
if (!SoFar)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node *Base = parseBaseUnresolvedName();
|
||||
@ -3078,6 +3085,8 @@ template<typename Alloc> Node *Db<Alloc>::parseUnresolvedName() {
|
||||
SoFar = make<GlobalQualifiedName>(Qual);
|
||||
else
|
||||
SoFar = Qual;
|
||||
if (!SoFar)
|
||||
return nullptr;
|
||||
} while (!consumeIf('E'));
|
||||
}
|
||||
// sr <unresolved-type> <base-unresolved-name>
|
||||
@ -3092,6 +3101,8 @@ template<typename Alloc> Node *Db<Alloc>::parseUnresolvedName() {
|
||||
if (TA == nullptr)
|
||||
return nullptr;
|
||||
SoFar = make<NameWithTemplateArgs>(SoFar, TA);
|
||||
if (!SoFar)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3111,6 +3122,8 @@ template<typename Alloc> Node *Db<Alloc>::parseAbiTags(Node *N) {
|
||||
if (SN.empty())
|
||||
return nullptr;
|
||||
N = make<AbiTagAttr>(N, SN);
|
||||
if (!N)
|
||||
return nullptr;
|
||||
}
|
||||
return N;
|
||||
}
|
||||
@ -3163,11 +3176,15 @@ template<typename Alloc> Node *Db<Alloc>::parseFunctionType() {
|
||||
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')) {
|
||||
@ -3178,6 +3195,8 @@ template<typename Alloc> Node *Db<Alloc>::parseFunctionType() {
|
||||
}
|
||||
ExceptionSpec =
|
||||
make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
|
||||
if (!ExceptionSpec)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
consumeIf("Dx"); // transaction safe
|
||||
@ -4517,9 +4536,10 @@ template<typename Alloc> Node *Db<Alloc>::parseExpr() {
|
||||
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;
|
||||
@ -4771,6 +4791,8 @@ template<typename Alloc> Node *Db<Alloc>::parseEncoding() {
|
||||
Names.push_back(Arg);
|
||||
}
|
||||
Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs));
|
||||
if (!Attrs)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node *ReturnType = nullptr;
|
||||
@ -4915,6 +4937,8 @@ template<typename Alloc> Node *Db<Alloc>::parseSubstitution() {
|
||||
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.
|
||||
@ -4968,6 +4992,8 @@ template<typename Alloc> Node *Db<Alloc>::parseTemplateParam() {
|
||||
// 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));
|
||||
@ -5047,6 +5073,8 @@ Node *Db<Alloc>::parseTemplateArgs(bool TagTemplates) {
|
||||
if (Arg->getKind() == Node::KTemplateArgumentPack) {
|
||||
TableEntry = make<ParameterPack>(
|
||||
static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
|
||||
if (!TableEntry)
|
||||
return nullptr;
|
||||
}
|
||||
TemplateParams.push_back(TableEntry);
|
||||
} else {
|
||||
|
@ -76,8 +76,14 @@ public:
|
||||
///
|
||||
/// 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;
|
||||
|
@ -105,7 +105,7 @@ public:
|
||||
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...);
|
||||
|
||||
@ -113,6 +113,9 @@ public:
|
||||
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 =
|
||||
@ -125,7 +128,7 @@ public:
|
||||
|
||||
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) {
|
||||
@ -138,7 +141,8 @@ public:
|
||||
// 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),
|
||||
@ -149,15 +153,16 @@ class CanonicalizerAllocator : public FoldingNodeAllocator {
|
||||
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;
|
||||
@ -185,6 +190,8 @@ public:
|
||||
|
||||
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::EquivalenceError
|
||||
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::addEquivalence(FragmentKind Kind, StringRef First,
|
||||
|
||||
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());
|
||||
}
|
||||
|
@ -7,10 +7,13 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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;
|
||||
|
||||
@ -222,7 +225,9 @@ static std::initializer_list<Testcase> Testcases = {
|
||||
},
|
||||
{}
|
||||
},
|
||||
};
|
||||
|
||||
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.
|
||||
@ -245,7 +250,8 @@ static std::initializer_list<Testcase> Testcases = {
|
||||
},
|
||||
};
|
||||
|
||||
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) {
|
||||
@ -257,11 +263,21 @@ TEST(ItaniumManglingCanonicalizerTest, TestTestcases) {
|
||||
}
|
||||
|
||||
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)
|
||||
@ -276,6 +292,21 @@ TEST(ItaniumManglingCanonicalizerTest, TestTestcases) {
|
||||
}
|
||||
}
|
||||
|
||||
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"),
|
||||
|
Loading…
Reference in New Issue
Block a user