[libcxxabi] r310525 - [demangler] Improve representation of substitutions/templates
Erik Pilkington via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 9 14:30:57 PDT 2017
Author: epilk
Date: Wed Aug 9 14:30:57 2017
New Revision: 310525
URL: http://llvm.org/viewvc/llvm-project?rev=310525&view=rev
Log:
[demangler] Improve representation of substitutions/templates
Differential revision: https://reviews.llvm.org/D36427
Added:
libcxxabi/trunk/test/unittest_demangle.pass.cpp
Modified:
libcxxabi/trunk/src/cxa_demangle.cpp
Modified: libcxxabi/trunk/src/cxa_demangle.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=310525&r1=310524&r2=310525&view=diff
==============================================================================
--- libcxxabi/trunk/src/cxa_demangle.cpp (original)
+++ libcxxabi/trunk/src/cxa_demangle.cpp Wed Aug 9 14:30:57 2017
@@ -1407,117 +1407,6 @@ public:
}
};
-template <std::size_t N>
-class arena
-{
- static const std::size_t alignment = 16;
- alignas(alignment) char buf_[N];
- char* ptr_;
-
- std::size_t
- align_up(std::size_t n) noexcept
- {return (n + (alignment-1)) & ~(alignment-1);}
-
- bool
- pointer_in_buffer(char* p) noexcept
- {return buf_ <= p && p <= buf_ + N;}
-
-public:
- arena() noexcept : ptr_(buf_) {}
- ~arena() {ptr_ = nullptr;}
- arena(const arena&) = delete;
- arena& operator=(const arena&) = delete;
-
- char* allocate(std::size_t n);
- void deallocate(char* p, std::size_t n) noexcept;
-
- static constexpr std::size_t size() {return N;}
- std::size_t used() const {return static_cast<std::size_t>(ptr_ - buf_);}
- void reset() {ptr_ = buf_;}
-};
-
-template <std::size_t N>
-char*
-arena<N>::allocate(std::size_t n)
-{
- n = align_up(n);
- if (static_cast<std::size_t>(buf_ + N - ptr_) >= n)
- {
- char* r = ptr_;
- ptr_ += n;
- return r;
- }
- return static_cast<char*>(std::malloc(n));
-}
-
-template <std::size_t N>
-void
-arena<N>::deallocate(char* p, std::size_t n) noexcept
-{
- if (pointer_in_buffer(p))
- {
- n = align_up(n);
- if (p + n == ptr_)
- ptr_ = p;
- }
- else
- std::free(p);
-}
-
-template <class T, std::size_t N>
-class short_alloc
-{
- arena<N>& a_;
-public:
- typedef T value_type;
-
-public:
- template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;};
-
- short_alloc(arena<N>& a) noexcept : a_(a) {}
- template <class U>
- short_alloc(const short_alloc<U, N>& a) noexcept
- : a_(a.a_) {}
- short_alloc(const short_alloc&) = default;
- short_alloc& operator=(const short_alloc&) = delete;
-
- T* allocate(std::size_t n)
- {
- return reinterpret_cast<T*>(a_.allocate(n*sizeof(T)));
- }
- void deallocate(T* p, std::size_t n) noexcept
- {
- a_.deallocate(reinterpret_cast<char*>(p), n*sizeof(T));
- }
-
- template <class T1, std::size_t N1, class U, std::size_t M>
- friend
- bool
- operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept;
-
- template <class U, std::size_t M> friend class short_alloc;
-};
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
- return N == M && &x.a_ == &y.a_;
-}
-
-template <class T, std::size_t N, class U, std::size_t M>
-inline
-bool
-operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept
-{
- return !(x == y);
-}
-
-const size_t bs = 4 * 1024;
-template <class T> using Alloc = short_alloc<T, bs>;
-template <class T> using Vector = std::vector<T, Alloc<T>>;
-
class BumpPointerAllocator {
struct BlockMeta {
BlockMeta* Next;
@@ -1568,13 +1457,209 @@ public:
}
};
+template <class T, size_t N>
+class PODSmallVector {
+ static_assert(std::is_pod<T>::value,
+ "T is required to be a plain old data type");
+
+ T* First;
+ T* Last;
+ T* Cap;
+ T Inline[N];
+
+ bool isInline() const { return First == Inline; }
+
+ void clearInline() {
+ First = Inline;
+ Last = Inline;
+ Cap = Inline + N;
+ }
+
+ void reserve(size_t NewCap) {
+ size_t S = size();
+ if (isInline()) {
+ auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
+ std::copy(First, Last, Tmp);
+ First = Tmp;
+ } else
+ First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
+ Last = First + S;
+ Cap = First + NewCap;
+ }
+
+public:
+ PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {}
+
+ PODSmallVector(const PODSmallVector&) = delete;
+ PODSmallVector& operator=(const PODSmallVector&) = delete;
+
+ PODSmallVector(PODSmallVector&& Other) : PODSmallVector() {
+ if (Other.isInline()) {
+ std::copy(Other.begin(), Other.end(), First);
+ Last = First + Other.size();
+ Other.clear();
+ return;
+ }
+
+ First = Other.First;
+ Last = Other.Last;
+ Cap = Other.Cap;
+ Other.clearInline();
+ }
+
+ PODSmallVector& operator=(PODSmallVector&& Other) {
+ if (Other.isInline()) {
+ if (!isInline()) {
+ std::free(First);
+ clearInline();
+ }
+ std::copy(Other.begin(), Other.end(), First);
+ Last = First + Other.size();
+ Other.clear();
+ return *this;
+ }
+
+ if (isInline()) {
+ First = Other.First;
+ Last = Other.Last;
+ Cap = Other.Cap;
+ Other.clearInline();
+ return *this;
+ }
+
+ std::swap(First, Other.First);
+ std::swap(Last, Other.Last);
+ std::swap(Cap, Other.Cap);
+ Other.clear();
+ return *this;
+ }
+
+ void push_back(const T& Elem) {
+ if (Last == Cap)
+ reserve(size() * 2);
+ *Last++ = Elem;
+ }
+
+ void pop_back() {
+ assert(Last != First && "Popping empty vector!");
+ --Last;
+ }
+
+ void dropBack(size_t Index) {
+ assert(Index <= size() && "dropBack() can't expand!");
+ Last = First + Index;
+ }
+
+ T* begin() { return First; }
+ T* end() { return Last; }
+
+ bool empty() const { return First == Last; }
+ size_t size() const { return static_cast<size_t>(Last - First); }
+ T& back() {
+ assert(Last != First && "Calling back() on empty vector!");
+ return *(Last - 1);
+ }
+ T& operator[](size_t Index) {
+ assert(Index < size() && "Invalid access!");
+ return *(begin() + Index);
+ }
+ void clear() { Last = First; }
+
+ ~PODSmallVector() {
+ if (!isInline())
+ std::free(First);
+ }
+};
+
+// Substitution table. This type is used to track the substitutions that are
+// known by the parser.
+template <size_t Size>
+class SubstitutionTable {
+ // Substitutions hold the actual entries in the table, and PackIndices tells
+ // us which entries are members of which pack. For example, if the
+ // substitutions we're tracking are: {int, {float, FooBar}, char}, with
+ // {float, FooBar} being a parameter pack, we represent the substitutions as:
+ // Substitutions: int, float, FooBar, char
+ // PackIndices: 0, 1, 3
+ // So, PackIndicies[I] holds the offset of the begin of the Ith pack, and
+ // PackIndices[I + 1] holds the offset of the end.
+ PODSmallVector<Node*, Size> Substitutions;
+ PODSmallVector<unsigned, Size> PackIndices;
+
+public:
+ // Add a substitution that represents a single name to the table. This is
+ // modeled as a parameter pack with just one element.
+ void pushSubstitution(Node* Entry) {
+ pushPack();
+ pushSubstitutionIntoPack(Entry);
+ }
+
+ // Add a new empty pack to the table. Subsequent calls to
+ // pushSubstitutionIntoPack() will add to this pack.
+ void pushPack() {
+ PackIndices.push_back(static_cast<unsigned>(Substitutions.size()));
+ }
+ void pushSubstitutionIntoPack(Node* Entry) {
+ assert(!PackIndices.empty() && "No pack to push substitution into!");
+ Substitutions.push_back(Entry);
+ }
+
+ // Remove the last pack from the table.
+ void popPack() {
+ unsigned Last = PackIndices.back();
+ PackIndices.pop_back();
+ Substitutions.dropBack(Last);
+ }
+
+ // For use in a range-for loop.
+ struct NodeRange {
+ Node** First;
+ Node** Last;
+ Node** begin() { return First; }
+ Node** end() { return Last; }
+ };
+
+ // Retrieve the Nth substitution. This is represented as a range, as the
+ // substitution could be referring to a parameter pack.
+ NodeRange nthSubstitution(size_t N) {
+ assert(PackIndices[N] <= Substitutions.size());
+ // The Nth parameter pack starts at offset PackIndices[N], and ends at
+ // PackIndices[N + 1].
+ Node** Begin = Substitutions.begin() + PackIndices[N];
+ Node** End;
+ if (N + 1 != PackIndices.size()) {
+ assert(PackIndices[N + 1] <= Substitutions.size());
+ End = Substitutions.begin() + PackIndices[N + 1];
+ } else
+ End = Substitutions.end();
+ assert(Begin <= End);
+ return NodeRange{Begin, End};
+ }
+
+ size_t size() const { return PackIndices.size(); }
+ bool empty() const { return PackIndices.empty(); }
+ void clear() {
+ Substitutions.clear();
+ PackIndices.clear();
+ }
+};
+
struct Db
{
- typedef Vector<Node*> sub_type;
- typedef Vector<sub_type> template_param_type;
- sub_type Names;
- template_param_type Subs;
- Vector<template_param_type> TemplateParams;
+ // Name stack, this is used by the parser to hold temporary names that were
+ // parsed. The parser colapses multiple names into new nodes to construct
+ // the AST. Once the parser is finished, names.size() == 1.
+ PODSmallVector<Node*, 32> Names;
+
+ // Substitution table. Itanium supports name substitutions as a means of
+ // compression. The string "S42_" refers to the 42nd entry in this table.
+ SubstitutionTable<32> Subs;
+
+ // Template parameter table. Like the above, but referenced like "T42_".
+ // This has a smaller size compared to Subs and Names because it can be
+ // stored on the stack.
+ SubstitutionTable<4> TemplateParams;
+
Qualifiers CV = QualNone;
FunctionRefQual RefQuals = FrefQualNone;
unsigned EncodingDepth = 0;
@@ -1585,13 +1670,6 @@ struct Db
BumpPointerAllocator ASTAllocator;
- template <size_t N>
- Db(arena<N>& ar) :
- Names(ar),
- Subs(0, Names, ar),
- TemplateParams(0, Subs, ar)
- {}
-
template <class T, class... Args> T* make(Args&& ...args)
{
return new (ASTAllocator.allocate(sizeof(T)))
@@ -1612,7 +1690,7 @@ struct Db
assert(FromPosition <= Names.size());
NodeArray res = makeNodeArray(
Names.begin() + (long)FromPosition, Names.end());
- Names.erase(Names.begin() + (long)FromPosition, Names.end());
+ Names.dropBack(FromPosition);
return res;
}
};
@@ -1801,7 +1879,7 @@ parse_substitution(const char* first, co
case '_':
if (!db.Subs.empty())
{
- for (const auto& n : db.Subs.front())
+ for (Node* n : db.Subs.nthSubstitution(0))
db.Names.push_back(n);
first += 2;
}
@@ -1828,7 +1906,7 @@ parse_substitution(const char* first, co
++sub;
if (sub < db.Subs.size())
{
- for (const auto& n : db.Subs[sub])
+ for (Node* n : db.Subs.nthSubstitution(sub))
db.Names.push_back(n);
first = t+1;
}
@@ -2058,11 +2136,9 @@ parse_template_param(const char* first,
{
if (first[1] == '_')
{
- if (db.TemplateParams.empty())
- return first;
- if (!db.TemplateParams.back().empty())
+ if (!db.TemplateParams.empty())
{
- for (auto& t : db.TemplateParams.back().front())
+ for (Node *t : db.TemplateParams.nthSubstitution(0))
db.Names.push_back(t);
first += 2;
}
@@ -2082,12 +2158,12 @@ parse_template_param(const char* first,
sub *= 10;
sub += static_cast<size_t>(*t - '0');
}
- if (t == last || *t != '_' || db.TemplateParams.empty())
+ if (t == last || *t != '_')
return first;
++sub;
- if (sub < db.TemplateParams.back().size())
+ if (sub < db.TemplateParams.size())
{
- for (auto& temp : db.TemplateParams.back()[sub])
+ for (Node *temp : db.TemplateParams.nthSubstitution(sub))
db.Names.push_back(temp);
first = t+1;
}
@@ -2469,7 +2545,7 @@ parse_unresolved_type(const char* first,
size_t k1 = db.Names.size();
if (t != first && k1 == k0 + 1)
{
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
}
else
@@ -2485,7 +2561,7 @@ parse_unresolved_type(const char* first,
{
if (db.Names.empty())
return first;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
}
break;
@@ -2504,7 +2580,7 @@ parse_unresolved_type(const char* first,
return first;
db.Names.back() =
db.make<StdQualifiedName>(db.Names.back());
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
}
}
@@ -2959,8 +3035,7 @@ parse_conversion_expr(const char* first,
db.Names.begin() + (long)expr_list_begin);
auto* conv_expr = db.make<ConversionExpr>(
types, expressions);
- db.Names.erase(
- db.Names.begin() + (long)type_begin, db.Names.end());
+ db.Names.dropBack(type_begin);
db.Names.push_back(conv_expr);
first = t;
}
@@ -3313,8 +3388,8 @@ parse_type(const char* first, const char
if (t1 != t)
{
if (is_function)
- db.Subs.pop_back();
- db.Subs.emplace_back(db.Names.get_allocator());
+ db.Subs.popPack();
+ db.Subs.pushPack();
for (size_t k = k0; k < k1; ++k)
{
if (cv) {
@@ -3325,7 +3400,7 @@ parse_type(const char* first, const char
db.Names[k] =
db.make<QualType>(db.Names[k], cv);
}
- db.Subs.back().push_back(db.Names[k]);
+ db.Subs.pushSubstitutionIntoPack(db.Names[k]);
}
first = t1;
}
@@ -3350,7 +3425,7 @@ parse_type(const char* first, const char
if (db.Names.empty())
return first;
first = t;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
}
break;
case 'C':
@@ -3362,7 +3437,7 @@ parse_type(const char* first, const char
db.Names.back() = db.make<PostfixQualifiedType>(
db.Names.back(), " complex");
first = t;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
}
break;
case 'F':
@@ -3372,7 +3447,7 @@ parse_type(const char* first, const char
if (db.Names.empty())
return first;
first = t;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
}
break;
case 'G':
@@ -3384,7 +3459,7 @@ parse_type(const char* first, const char
db.Names.back() = db.make<PostfixQualifiedType>(
db.Names.back(), " imaginary");
first = t;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
}
break;
case 'M':
@@ -3394,7 +3469,7 @@ parse_type(const char* first, const char
if (db.Names.empty())
return first;
first = t;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
}
break;
case 'O':
@@ -3404,12 +3479,12 @@ parse_type(const char* first, const char
size_t k1 = db.Names.size();
if (t != first+1)
{
- db.Subs.emplace_back(db.Names.get_allocator());
+ db.Subs.pushPack();
for (size_t k = k0; k < k1; ++k)
{
db.Names[k] =
db.make<RValueReferenceType>(db.Names[k]);
- db.Subs.back().push_back(db.Names[k]);
+ db.Subs.pushSubstitutionIntoPack(db.Names[k]);
}
first = t;
}
@@ -3422,11 +3497,11 @@ parse_type(const char* first, const char
size_t k1 = db.Names.size();
if (t != first+1)
{
- db.Subs.emplace_back(db.Names.get_allocator());
+ db.Subs.pushPack();
for (size_t k = k0; k < k1; ++k)
{
db.Names[k] = db.make<PointerType>(db.Names[k]);
- db.Subs.back().push_back(db.Names[k]);
+ db.Subs.pushSubstitutionIntoPack(db.Names[k]);
}
first = t;
}
@@ -3439,12 +3514,12 @@ parse_type(const char* first, const char
size_t k1 = db.Names.size();
if (t != first+1)
{
- db.Subs.emplace_back(db.Names.get_allocator());
+ db.Subs.pushPack();
for (size_t k = k0; k < k1; ++k)
{
db.Names[k] =
db.make<LValueReferenceType>(db.Names[k]);
- db.Subs.back().push_back(db.Names[k]);
+ db.Subs.pushSubstitutionIntoPack(db.Names[k]);
}
first = t;
}
@@ -3457,9 +3532,9 @@ parse_type(const char* first, const char
size_t k1 = db.Names.size();
if (t != first)
{
- db.Subs.emplace_back(db.Names.get_allocator());
+ db.Subs.pushPack();
for (size_t k = k0; k < k1; ++k)
- db.Subs.back().push_back(db.Names[k]);
+ db.Subs.pushSubstitutionIntoPack(db.Names[k]);
if (db.TryToParseTemplateArgs && k1 == k0+1)
{
const char* t1 = parse_template_args(t, last, db);
@@ -3470,9 +3545,7 @@ parse_type(const char* first, const char
db.Names.back() = db.make<
NameWithTemplateArgs>(
db.Names.back(), args);
- db.Subs.push_back(Db::sub_type(
- 1, db.Names.back(),
- db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
t = t1;
}
}
@@ -3512,7 +3585,7 @@ parse_type(const char* first, const char
db.Names.push_back(db.make<VendorExtQualType>(type, proto));
}
}
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t2;
}
}
@@ -3526,7 +3599,7 @@ parse_type(const char* first, const char
{
if (db.Names.empty())
return first;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
}
}
@@ -3551,7 +3624,7 @@ parse_type(const char* first, const char
NameWithTemplateArgs>(
db.Names.back(), template_args);
// Need to create substitution for <template-template-param> <template-args>
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
}
}
@@ -3570,9 +3643,9 @@ parse_type(const char* first, const char
size_t k1 = db.Names.size();
if (t != first+2)
{
- db.Subs.emplace_back(db.Names.get_allocator());
+ db.Subs.pushPack();
for (size_t k = k0; k < k1; ++k)
- db.Subs.back().push_back(db.Names[k]);
+ db.Subs.pushSubstitutionIntoPack(db.Names[k]);
first = t;
return first;
}
@@ -3585,7 +3658,7 @@ parse_type(const char* first, const char
{
if (db.Names.empty())
return first;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
return first;
}
@@ -3596,7 +3669,7 @@ parse_type(const char* first, const char
{
if (db.Names.empty())
return first;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
return first;
}
@@ -3619,7 +3692,7 @@ parse_type(const char* first, const char
{
if (db.Names.empty())
return first;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
first = t;
}
}
@@ -5119,26 +5192,32 @@ parse_template_args(const char* first, c
if (last - first >= 2 && *first == 'I')
{
if (db.TagTemplates)
- db.TemplateParams.back().clear();
+ db.TemplateParams.clear();
const char* t = first+1;
size_t begin_idx = db.Names.size();
while (*t != 'E')
{
if (db.TagTemplates)
- db.TemplateParams.emplace_back(db.Names.get_allocator());
+ {
+ auto TmpParams = std::move(db.TemplateParams);
+ size_t k0 = db.Names.size();
+ const char* t1 = parse_template_arg(t, last, db);
+ size_t k1 = db.Names.size();
+ db.TemplateParams = std::move(TmpParams);
+
+ if (t1 == t || t1 == last || k0 > k1)
+ return first;
+ db.TemplateParams.pushPack();
+ for (size_t k = k0; k < k1; ++k)
+ db.TemplateParams.pushSubstitutionIntoPack(db.Names[k]);
+ t = t1;
+ continue;
+ }
size_t k0 = db.Names.size();
const char* t1 = parse_template_arg(t, last, db);
size_t k1 = db.Names.size();
- if (db.TagTemplates)
- db.TemplateParams.pop_back();
if (t1 == t || t1 == last || k0 > k1)
- return first;
- if (db.TagTemplates)
- {
- db.TemplateParams.back().emplace_back(db.Names.get_allocator());
- for (size_t k = k0; k < k1; ++k)
- db.TemplateParams.back().back().push_back(db.Names[k]);
- }
+ return first;
t = t1;
}
if (begin_idx > db.Names.size())
@@ -5218,9 +5297,7 @@ parse_nested_name(const char* first, con
{
db.Names.back() = db.make<QualifiedName>(
db.Names.back(), name);
- db.Subs.push_back(
- Db::sub_type(1, db.Names.back(),
- db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
}
else
db.Names.back() = name;
@@ -5243,7 +5320,7 @@ parse_nested_name(const char* first, con
db.make<QualifiedName>(db.Names.back(), name);
else
db.Names.back() = name;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
pop_subs = true;
t0 = t1;
}
@@ -5265,7 +5342,7 @@ parse_nested_name(const char* first, con
db.make<QualifiedName>(db.Names.back(), name);
else
db.Names.back() = name;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
pop_subs = true;
t0 = t1;
}
@@ -5282,8 +5359,7 @@ parse_nested_name(const char* first, con
db.Names.pop_back();
db.Names.back() = db.make<NameWithTemplateArgs>(
db.Names.back(), name);
- db.Subs.push_back(Db::sub_type(
- 1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
t0 = t1;
component_ends_with_template_args = true;
}
@@ -5308,7 +5384,7 @@ parse_nested_name(const char* first, con
db.make<QualifiedName>(db.Names.back(), name);
else
db.Names.back() = name;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
pop_subs = true;
t0 = t1;
}
@@ -5319,7 +5395,7 @@ parse_nested_name(const char* first, con
first = t0 + 1;
db.CV = cv;
if (pop_subs && !db.Subs.empty())
- db.Subs.pop_back();
+ db.Subs.popPack();
if (ends_with_template_args)
*ends_with_template_args = component_ends_with_template_args;
}
@@ -5484,7 +5560,7 @@ parse_name(const char* first, const char
{
if (db.Names.empty())
return first;
- db.Subs.push_back(Db::sub_type(1, db.Names.back(), db.Names.get_allocator()));
+ db.Subs.pushSubstitution(db.Names.back());
t0 = t1;
t1 = parse_template_args(t0, last, db);
if (t1 != t0)
@@ -6035,16 +6111,14 @@ __cxa_demangle(const char *mangled_name,
}
size_t internal_size = buf != nullptr ? *n : 0;
- arena<bs> a;
- Db db(a);
- db.TemplateParams.emplace_back(a);
+ Db db;
int internal_status = success;
size_t len = std::strlen(mangled_name);
demangle(mangled_name, mangled_name + len, db,
internal_status);
if (internal_status == success && db.FixForwardReferences &&
- !db.TemplateParams.empty() && !db.TemplateParams.front().empty())
+ !db.TemplateParams.empty())
{
db.FixForwardReferences = false;
db.TagTemplates = false;
Added: libcxxabi/trunk/test/unittest_demangle.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/unittest_demangle.pass.cpp?rev=310525&view=auto
==============================================================================
--- libcxxabi/trunk/test/unittest_demangle.pass.cpp (added)
+++ libcxxabi/trunk/test/unittest_demangle.pass.cpp Wed Aug 9 14:30:57 2017
@@ -0,0 +1,123 @@
+//===----------------------- unittest_demangle.cpp ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../src/cxa_demangle.cpp"
+
+using namespace __cxxabiv1;
+
+void testPODSmallVector() {
+ { // {push/pop}_back
+ PODSmallVector<int, 1> PSV;
+ PSV.push_back(0);
+ PSV.push_back(1);
+ PSV.push_back(2);
+ PSV.push_back(3);
+ for (int i = 0; i < 4; ++i)
+ assert(PSV[i] == i);
+ PSV.pop_back();
+ for (int i = 0; i < 3; ++i)
+ assert(PSV[i] == i);
+ PSV.pop_back();
+ PSV.pop_back();
+ assert(!PSV.empty() && PSV.size() == 1);
+ PSV.pop_back();
+ assert(PSV.empty() && PSV.size() == 0);
+ }
+
+ {
+ PODSmallVector<int, 1> PSV1;
+ PSV1.push_back(1);
+ PSV1.push_back(2);
+ PSV1.push_back(3);
+
+ PODSmallVector<int, 1> PSV2;
+ std::swap(PSV1, PSV2);
+ assert(PSV1.size() == 0);
+ assert(PSV2.size() == 3);
+ int i = 1;
+ for (int x : PSV2) {
+ assert(x == i);
+ ++i;
+ }
+ assert(i == 4);
+ std::swap(PSV1, PSV2);
+ assert(PSV1.size() == 3);
+ assert(PSV2.size() == 0);
+ i = 1;
+ for (int x : PSV1) {
+ assert(x == i);
+ ++i;
+ }
+ assert(i == 4);
+ }
+
+ {
+ PODSmallVector<int, 10> PSV1;
+ PODSmallVector<int, 10> PSV2;
+ PSV1.push_back(0);
+ PSV1.push_back(1);
+ PSV1.push_back(2);
+ assert(PSV1.size() == 3);
+ assert(PSV2.size() == 0);
+ std::swap(PSV1, PSV2);
+ assert(PSV1.size() == 0);
+ assert(PSV2.size() == 3);
+ int i = 0;
+ for (int x : PSV2) {
+ assert(x == i);
+ ++i;
+ }
+ for (int x : PSV1) {
+ assert(false);
+ (void)x;
+ }
+ }
+}
+
+void testSubstitutionTable() {
+ {
+ SubstitutionTable<2> Tab;
+
+ NameType Names[] = {{"MERP"}, {"MARP"}, {"MAMP"}};
+ Tab.pushPack();
+ Tab.pushSubstitutionIntoPack(&Names[0]);
+ Tab.pushSubstitutionIntoPack(&Names[1]);
+ Tab.pushSubstitutionIntoPack(&Names[2]);
+
+ int Index = 0;
+ for (Node* N : Tab.nthSubstitution(0)) {
+ assert(static_cast<NameType*>(N)->getName() == Names[Index].getName());
+ ++Index;
+ }
+ assert(Index == 3);
+
+ Tab.popPack();
+ assert(Tab.empty() && Tab.size() == 0);
+ Tab.pushSubstitution(&Names[0]);
+ Tab.pushSubstitution(&Names[1]);
+ assert(!Tab.empty() && Tab.size() == 2);
+
+ int I = 0;
+ for (Node* N : Tab.nthSubstitution(0)) {
+ assert(static_cast<NameType*>(N)->getName() == "MERP");
+ assert(I == 0);
+ ++I;
+ }
+ for (Node* N : Tab.nthSubstitution(1)) {
+ assert(static_cast<NameType*>(N)->getName() == "MARP");
+ assert(I == 1);
+ ++I;
+ }
+ }
+}
+
+int main() {
+ testPODSmallVector();
+ testSubstitutionTable();
+}
More information about the cfe-commits
mailing list