aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
downloadydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp')
-rw-r--r--contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp644
1 files changed, 322 insertions, 322 deletions
diff --git a/contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp b/contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp
index 9d3cf61459..fa8acdc7e9 100644
--- a/contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp
+++ b/contrib/libs/llvm12/lib/Support/ItaniumManglingCanonicalizer.cpp
@@ -1,322 +1,322 @@
-//===----------------- ItaniumManglingCanonicalizer.cpp -------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Support/ItaniumManglingCanonicalizer.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Demangle/ItaniumDemangle.h"
-#include "llvm/Support/Allocator.h"
-
-using namespace llvm;
-using llvm::itanium_demangle::ForwardTemplateReference;
-using llvm::itanium_demangle::Node;
-using llvm::itanium_demangle::NodeKind;
-using llvm::itanium_demangle::StringView;
-
-namespace {
-struct FoldingSetNodeIDBuilder {
- llvm::FoldingSetNodeID &ID;
- void operator()(const Node *P) { ID.AddPointer(P); }
- void operator()(StringView Str) {
- ID.AddString(llvm::StringRef(Str.begin(), Str.size()));
- }
- template <typename T>
- std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>
- operator()(T V) {
- ID.AddInteger((unsigned long long)V);
- }
- void operator()(itanium_demangle::NodeArray A) {
- ID.AddInteger(A.size());
- for (const Node *N : A)
- (*this)(N);
- }
-};
-
-template<typename ...T>
-void profileCtor(llvm::FoldingSetNodeID &ID, Node::Kind K, T ...V) {
- FoldingSetNodeIDBuilder Builder = {ID};
- Builder(K);
- int VisitInOrder[] = {
- (Builder(V), 0) ...,
- 0 // Avoid empty array if there are no arguments.
- };
- (void)VisitInOrder;
-}
-
-// FIXME: Convert this to a generic lambda when possible.
-template<typename NodeT> struct ProfileSpecificNode {
- FoldingSetNodeID &ID;
- template<typename ...T> void operator()(T ...V) {
- profileCtor(ID, NodeKind<NodeT>::Kind, V...);
- }
-};
-
-struct ProfileNode {
- FoldingSetNodeID &ID;
- template<typename NodeT> void operator()(const NodeT *N) {
- N->match(ProfileSpecificNode<NodeT>{ID});
- }
-};
-
-template<> void ProfileNode::operator()(const ForwardTemplateReference *N) {
- llvm_unreachable("should never canonicalize a ForwardTemplateReference");
-}
-
-void profileNode(llvm::FoldingSetNodeID &ID, const Node *N) {
- N->visit(ProfileNode{ID});
-}
-
-class FoldingNodeAllocator {
- class alignas(alignof(Node *)) NodeHeader : public llvm::FoldingSetNode {
- public:
- // 'Node' in this context names the injected-class-name of the base class.
- itanium_demangle::Node *getNode() {
- return reinterpret_cast<itanium_demangle::Node *>(this + 1);
- }
- void Profile(llvm::FoldingSetNodeID &ID) { profileNode(ID, getNode()); }
- };
-
- BumpPtrAllocator RawAlloc;
- llvm::FoldingSet<NodeHeader> Nodes;
-
-public:
- void reset() {}
-
- template <typename T, typename... Args>
- std::pair<Node *, bool> getOrCreateNode(bool CreateNewNodes, Args &&... As) {
- // FIXME: Don't canonicalize forward template references for now, because
- // they contain state (the resolved template node) that's not known at their
- // point of creation.
- if (std::is_same<T, ForwardTemplateReference>::value) {
- // Note that we don't use if-constexpr here and so we must still write
- // this code in a generic form.
- return {new (RawAlloc.Allocate(sizeof(T), alignof(T)))
- T(std::forward<Args>(As)...),
- true};
- }
-
- llvm::FoldingSetNodeID ID;
- profileCtor(ID, NodeKind<T>::Kind, As...);
-
- void *InsertPos;
- 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 =
- RawAlloc.Allocate(sizeof(NodeHeader) + sizeof(T), alignof(NodeHeader));
- NodeHeader *New = new (Storage) NodeHeader;
- T *Result = new (New->getNode()) T(std::forward<Args>(As)...);
- Nodes.InsertNode(New, InsertPos);
- return {Result, true};
- }
-
- template<typename T, typename... Args>
- Node *makeNode(Args &&...As) {
- return getOrCreateNode<T>(true, std::forward<Args>(As)...).first;
- }
-
- void *allocateNodeArray(size_t sz) {
- return RawAlloc.Allocate(sizeof(Node *) * sz, alignof(Node *));
- }
-};
-
-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>(CreateNewNodes, std::forward<Args>(As)...);
- if (Result.second) {
- // Node is new. Make a note of that.
- MostRecentlyCreated = Result.first;
- } 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;
- assert(Remappings.find(Result.first) == Remappings.end() &&
- "should never need multiple remap steps");
- }
- if (Result.first == TrackedNode)
- TrackedNodeIsUsed = true;
- }
- return Result.first;
- }
-
- /// Helper to allow makeNode to be partially-specialized on T.
- template<typename T> struct MakeNodeImpl {
- CanonicalizerAllocator &Self;
- template<typename ...Args> Node *make(Args &&...As) {
- return Self.makeNodeSimple<T>(std::forward<Args>(As)...);
- }
- };
-
-public:
- template<typename T, typename ...Args> Node *makeNode(Args &&...As) {
- return MakeNodeImpl<T>{*this}.make(std::forward<Args>(As)...);
- }
-
- 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.
- Remappings.insert(std::make_pair(A, B));
- }
-
- bool isMostRecentlyCreated(Node *N) const { return MostRecentlyCreated == N; }
-
- void trackUsesOf(Node *N) {
- TrackedNode = N;
- TrackedNodeIsUsed = false;
- }
- bool trackedNodeIsUsed() const { return TrackedNodeIsUsed; }
-};
-
-/// Convert St3foo to NSt3fooE so that equivalences naming one also affect the
-/// other.
-template<>
-struct CanonicalizerAllocator::MakeNodeImpl<
- itanium_demangle::StdQualifiedName> {
- CanonicalizerAllocator &Self;
- Node *make(Node *Child) {
- Node *StdNamespace = Self.makeNode<itanium_demangle::NameType>("std");
- if (!StdNamespace)
- return nullptr;
- return Self.makeNode<itanium_demangle::NestedName>(StdNamespace, Child);
- }
-};
-
-// FIXME: Also expand built-in substitutions?
-
-using CanonicalizingDemangler =
- itanium_demangle::ManglingParser<CanonicalizerAllocator>;
-}
-
-struct ItaniumManglingCanonicalizer::Impl {
- CanonicalizingDemangler Demangler = {nullptr, nullptr};
-};
-
-ItaniumManglingCanonicalizer::ItaniumManglingCanonicalizer() : P(new Impl) {}
-ItaniumManglingCanonicalizer::~ItaniumManglingCanonicalizer() { delete P; }
-
-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());
- Node *N = nullptr;
- switch (Kind) {
- // A <name>, with minor extensions to allow arbitrary namespace and
- // template names that can't easily be written as <name>s.
- case FragmentKind::Name:
- // Very special case: allow "St" as a shorthand for "3std". It's not
- // valid as a <name> mangling, but is nonetheless the most natural
- // way to name the 'std' namespace.
- if (Str.size() == 2 && P->Demangler.consumeIf("St"))
- N = P->Demangler.make<itanium_demangle::NameType>("std");
- // We permit substitutions to name templates without their template
- // arguments. This mostly just falls out, as almost all template names
- // are valid as <name>s, but we also want to parse <substitution>s as
- // <name>s, even though they're not.
- else if (Str.startswith("S"))
- // Parse the substitution and optional following template arguments.
- N = P->Demangler.parseType();
- else
- N = P->Demangler.parseName();
- break;
-
- // A <type>.
- case FragmentKind::Type:
- N = P->Demangler.parseType();
- break;
-
- // An <encoding>.
- case FragmentKind::Encoding:
- N = P->Demangler.parseEncoding();
- break;
- }
-
- // If we have trailing junk, the mangling is invalid.
- if (P->Demangler.numLeft() != 0)
- N = nullptr;
-
- // If any node was created after N, then we cannot safely remap it because
- // it might already be in use by another node.
- return std::make_pair(N, Alloc.isMostRecentlyCreated(N));
- };
-
- Node *FirstNode, *SecondNode;
- bool FirstIsNew, SecondIsNew;
-
- std::tie(FirstNode, FirstIsNew) = Parse(First);
- if (!FirstNode)
- return EquivalenceError::InvalidFirstMangling;
-
- Alloc.trackUsesOf(FirstNode);
- std::tie(SecondNode, SecondIsNew) = Parse(Second);
- if (!SecondNode)
- return EquivalenceError::InvalidSecondMangling;
-
- // If they're already equivalent, there's nothing to do.
- if (FirstNode == SecondNode)
- return EquivalenceError::Success;
-
- if (FirstIsNew && !Alloc.trackedNodeIsUsed())
- Alloc.addRemapping(FirstNode, SecondNode);
- else if (SecondIsNew)
- Alloc.addRemapping(SecondNode, FirstNode);
- else
- return EquivalenceError::ManglingAlreadyUsed;
-
- return EquivalenceError::Success;
-}
-
-static ItaniumManglingCanonicalizer::Key
-parseMaybeMangledName(CanonicalizingDemangler &Demangler, StringRef Mangling,
- bool CreateNewNodes) {
- Demangler.ASTAllocator.setCreateNewNodes(CreateNewNodes);
- Demangler.reset(Mangling.begin(), Mangling.end());
- // Attempt demangling only for names that look like C++ mangled names.
- // Otherwise, treat them as extern "C" names. We permit the latter to
- // be remapped by (eg)
- // encoding 6memcpy 7memmove
- // consistent with how they are encoded as local-names inside a C++ mangling.
- Node *N;
- if (Mangling.startswith("_Z") || Mangling.startswith("__Z") ||
- Mangling.startswith("___Z") || Mangling.startswith("____Z"))
- N = Demangler.parse();
- else
- N = Demangler.make<itanium_demangle::NameType>(
- StringView(Mangling.data(), Mangling.size()));
- return reinterpret_cast<ItaniumManglingCanonicalizer::Key>(N);
-}
-
-ItaniumManglingCanonicalizer::Key
-ItaniumManglingCanonicalizer::canonicalize(StringRef Mangling) {
- return parseMaybeMangledName(P->Demangler, Mangling, true);
-}
-
-ItaniumManglingCanonicalizer::Key
-ItaniumManglingCanonicalizer::lookup(StringRef Mangling) {
- return parseMaybeMangledName(P->Demangler, Mangling, false);
-}
+//===----------------- ItaniumManglingCanonicalizer.cpp -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/ItaniumManglingCanonicalizer.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Demangle/ItaniumDemangle.h"
+#include "llvm/Support/Allocator.h"
+
+using namespace llvm;
+using llvm::itanium_demangle::ForwardTemplateReference;
+using llvm::itanium_demangle::Node;
+using llvm::itanium_demangle::NodeKind;
+using llvm::itanium_demangle::StringView;
+
+namespace {
+struct FoldingSetNodeIDBuilder {
+ llvm::FoldingSetNodeID &ID;
+ void operator()(const Node *P) { ID.AddPointer(P); }
+ void operator()(StringView Str) {
+ ID.AddString(llvm::StringRef(Str.begin(), Str.size()));
+ }
+ template <typename T>
+ std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>
+ operator()(T V) {
+ ID.AddInteger((unsigned long long)V);
+ }
+ void operator()(itanium_demangle::NodeArray A) {
+ ID.AddInteger(A.size());
+ for (const Node *N : A)
+ (*this)(N);
+ }
+};
+
+template<typename ...T>
+void profileCtor(llvm::FoldingSetNodeID &ID, Node::Kind K, T ...V) {
+ FoldingSetNodeIDBuilder Builder = {ID};
+ Builder(K);
+ int VisitInOrder[] = {
+ (Builder(V), 0) ...,
+ 0 // Avoid empty array if there are no arguments.
+ };
+ (void)VisitInOrder;
+}
+
+// FIXME: Convert this to a generic lambda when possible.
+template<typename NodeT> struct ProfileSpecificNode {
+ FoldingSetNodeID &ID;
+ template<typename ...T> void operator()(T ...V) {
+ profileCtor(ID, NodeKind<NodeT>::Kind, V...);
+ }
+};
+
+struct ProfileNode {
+ FoldingSetNodeID &ID;
+ template<typename NodeT> void operator()(const NodeT *N) {
+ N->match(ProfileSpecificNode<NodeT>{ID});
+ }
+};
+
+template<> void ProfileNode::operator()(const ForwardTemplateReference *N) {
+ llvm_unreachable("should never canonicalize a ForwardTemplateReference");
+}
+
+void profileNode(llvm::FoldingSetNodeID &ID, const Node *N) {
+ N->visit(ProfileNode{ID});
+}
+
+class FoldingNodeAllocator {
+ class alignas(alignof(Node *)) NodeHeader : public llvm::FoldingSetNode {
+ public:
+ // 'Node' in this context names the injected-class-name of the base class.
+ itanium_demangle::Node *getNode() {
+ return reinterpret_cast<itanium_demangle::Node *>(this + 1);
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) { profileNode(ID, getNode()); }
+ };
+
+ BumpPtrAllocator RawAlloc;
+ llvm::FoldingSet<NodeHeader> Nodes;
+
+public:
+ void reset() {}
+
+ template <typename T, typename... Args>
+ std::pair<Node *, bool> getOrCreateNode(bool CreateNewNodes, Args &&... As) {
+ // FIXME: Don't canonicalize forward template references for now, because
+ // they contain state (the resolved template node) that's not known at their
+ // point of creation.
+ if (std::is_same<T, ForwardTemplateReference>::value) {
+ // Note that we don't use if-constexpr here and so we must still write
+ // this code in a generic form.
+ return {new (RawAlloc.Allocate(sizeof(T), alignof(T)))
+ T(std::forward<Args>(As)...),
+ true};
+ }
+
+ llvm::FoldingSetNodeID ID;
+ profileCtor(ID, NodeKind<T>::Kind, As...);
+
+ void *InsertPos;
+ 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 =
+ RawAlloc.Allocate(sizeof(NodeHeader) + sizeof(T), alignof(NodeHeader));
+ NodeHeader *New = new (Storage) NodeHeader;
+ T *Result = new (New->getNode()) T(std::forward<Args>(As)...);
+ Nodes.InsertNode(New, InsertPos);
+ return {Result, true};
+ }
+
+ template<typename T, typename... Args>
+ Node *makeNode(Args &&...As) {
+ return getOrCreateNode<T>(true, std::forward<Args>(As)...).first;
+ }
+
+ void *allocateNodeArray(size_t sz) {
+ return RawAlloc.Allocate(sizeof(Node *) * sz, alignof(Node *));
+ }
+};
+
+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>(CreateNewNodes, std::forward<Args>(As)...);
+ if (Result.second) {
+ // Node is new. Make a note of that.
+ MostRecentlyCreated = Result.first;
+ } 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;
+ assert(Remappings.find(Result.first) == Remappings.end() &&
+ "should never need multiple remap steps");
+ }
+ if (Result.first == TrackedNode)
+ TrackedNodeIsUsed = true;
+ }
+ return Result.first;
+ }
+
+ /// Helper to allow makeNode to be partially-specialized on T.
+ template<typename T> struct MakeNodeImpl {
+ CanonicalizerAllocator &Self;
+ template<typename ...Args> Node *make(Args &&...As) {
+ return Self.makeNodeSimple<T>(std::forward<Args>(As)...);
+ }
+ };
+
+public:
+ template<typename T, typename ...Args> Node *makeNode(Args &&...As) {
+ return MakeNodeImpl<T>{*this}.make(std::forward<Args>(As)...);
+ }
+
+ 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.
+ Remappings.insert(std::make_pair(A, B));
+ }
+
+ bool isMostRecentlyCreated(Node *N) const { return MostRecentlyCreated == N; }
+
+ void trackUsesOf(Node *N) {
+ TrackedNode = N;
+ TrackedNodeIsUsed = false;
+ }
+ bool trackedNodeIsUsed() const { return TrackedNodeIsUsed; }
+};
+
+/// Convert St3foo to NSt3fooE so that equivalences naming one also affect the
+/// other.
+template<>
+struct CanonicalizerAllocator::MakeNodeImpl<
+ itanium_demangle::StdQualifiedName> {
+ CanonicalizerAllocator &Self;
+ Node *make(Node *Child) {
+ Node *StdNamespace = Self.makeNode<itanium_demangle::NameType>("std");
+ if (!StdNamespace)
+ return nullptr;
+ return Self.makeNode<itanium_demangle::NestedName>(StdNamespace, Child);
+ }
+};
+
+// FIXME: Also expand built-in substitutions?
+
+using CanonicalizingDemangler =
+ itanium_demangle::ManglingParser<CanonicalizerAllocator>;
+}
+
+struct ItaniumManglingCanonicalizer::Impl {
+ CanonicalizingDemangler Demangler = {nullptr, nullptr};
+};
+
+ItaniumManglingCanonicalizer::ItaniumManglingCanonicalizer() : P(new Impl) {}
+ItaniumManglingCanonicalizer::~ItaniumManglingCanonicalizer() { delete P; }
+
+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());
+ Node *N = nullptr;
+ switch (Kind) {
+ // A <name>, with minor extensions to allow arbitrary namespace and
+ // template names that can't easily be written as <name>s.
+ case FragmentKind::Name:
+ // Very special case: allow "St" as a shorthand for "3std". It's not
+ // valid as a <name> mangling, but is nonetheless the most natural
+ // way to name the 'std' namespace.
+ if (Str.size() == 2 && P->Demangler.consumeIf("St"))
+ N = P->Demangler.make<itanium_demangle::NameType>("std");
+ // We permit substitutions to name templates without their template
+ // arguments. This mostly just falls out, as almost all template names
+ // are valid as <name>s, but we also want to parse <substitution>s as
+ // <name>s, even though they're not.
+ else if (Str.startswith("S"))
+ // Parse the substitution and optional following template arguments.
+ N = P->Demangler.parseType();
+ else
+ N = P->Demangler.parseName();
+ break;
+
+ // A <type>.
+ case FragmentKind::Type:
+ N = P->Demangler.parseType();
+ break;
+
+ // An <encoding>.
+ case FragmentKind::Encoding:
+ N = P->Demangler.parseEncoding();
+ break;
+ }
+
+ // If we have trailing junk, the mangling is invalid.
+ if (P->Demangler.numLeft() != 0)
+ N = nullptr;
+
+ // If any node was created after N, then we cannot safely remap it because
+ // it might already be in use by another node.
+ return std::make_pair(N, Alloc.isMostRecentlyCreated(N));
+ };
+
+ Node *FirstNode, *SecondNode;
+ bool FirstIsNew, SecondIsNew;
+
+ std::tie(FirstNode, FirstIsNew) = Parse(First);
+ if (!FirstNode)
+ return EquivalenceError::InvalidFirstMangling;
+
+ Alloc.trackUsesOf(FirstNode);
+ std::tie(SecondNode, SecondIsNew) = Parse(Second);
+ if (!SecondNode)
+ return EquivalenceError::InvalidSecondMangling;
+
+ // If they're already equivalent, there's nothing to do.
+ if (FirstNode == SecondNode)
+ return EquivalenceError::Success;
+
+ if (FirstIsNew && !Alloc.trackedNodeIsUsed())
+ Alloc.addRemapping(FirstNode, SecondNode);
+ else if (SecondIsNew)
+ Alloc.addRemapping(SecondNode, FirstNode);
+ else
+ return EquivalenceError::ManglingAlreadyUsed;
+
+ return EquivalenceError::Success;
+}
+
+static ItaniumManglingCanonicalizer::Key
+parseMaybeMangledName(CanonicalizingDemangler &Demangler, StringRef Mangling,
+ bool CreateNewNodes) {
+ Demangler.ASTAllocator.setCreateNewNodes(CreateNewNodes);
+ Demangler.reset(Mangling.begin(), Mangling.end());
+ // Attempt demangling only for names that look like C++ mangled names.
+ // Otherwise, treat them as extern "C" names. We permit the latter to
+ // be remapped by (eg)
+ // encoding 6memcpy 7memmove
+ // consistent with how they are encoded as local-names inside a C++ mangling.
+ Node *N;
+ if (Mangling.startswith("_Z") || Mangling.startswith("__Z") ||
+ Mangling.startswith("___Z") || Mangling.startswith("____Z"))
+ N = Demangler.parse();
+ else
+ N = Demangler.make<itanium_demangle::NameType>(
+ StringView(Mangling.data(), Mangling.size()));
+ return reinterpret_cast<ItaniumManglingCanonicalizer::Key>(N);
+}
+
+ItaniumManglingCanonicalizer::Key
+ItaniumManglingCanonicalizer::canonicalize(StringRef Mangling) {
+ return parseMaybeMangledName(P->Demangler, Mangling, true);
+}
+
+ItaniumManglingCanonicalizer::Key
+ItaniumManglingCanonicalizer::lookup(StringRef Mangling) {
+ return parseMaybeMangledName(P->Demangler, Mangling, false);
+}