<div dir="ltr"><div>Erik, </div>A bunch of old bugs reported in this code by OSS-Fuzz got auto-closed today, thanks! <div><br></div><div>Also a few new bugs got opened tonight, most likely caused by this patch. You are auto-CC-ed. </div><div>I would start from <a href="https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2767">https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=2767</a></div><div><pre class="gmail-issue_text" tabindex="1" style="max-width:80em;padding:0px 0px 3px 0.7em;outline:0px"><font color="#000000"><span style="font-size:11.726px;white-space:pre-wrap">Crash Type: Null-dereference READ
Crash Address: 0x000000000008
Crash State:
__cxxabiv1::parse_nested_name
__cxxabiv1::parse_name
__cxxabiv1::parse_local_name</span></font></pre><pre class="gmail-issue_text" tabindex="1" style="max-width:80em;padding:0px 0px 3px 0.7em;outline:0px"><font color="#000000"><span style="font-size:11.726px;white-space:pre-wrap"><br></span></font>Also, you have the access to all inputs generated by the demangler fuzzer in a few months of fuzzing. <br>You can use that corpus for local testing, and I would also encourage you to add the corpus to the public LLVM bots. </pre><pre class="gmail-issue_text" tabindex="1" style="font-size:11.726px;white-space:pre-wrap;max-width:80em;padding:0px 0px 3px 0.7em;outline:0px;color:rgb(0,0,0)">--kcc </pre><pre class="gmail-issue_text" tabindex="1" style="font-size:11.726px;white-space:pre-wrap;max-width:80em;padding:0px 0px 3px 0.7em;outline:0px;color:rgb(0,0,0)"><br></pre></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jul 27, 2017 at 5:43 PM, Erik Pilkington via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: epilk<br>
Date: Thu Jul 27 17:43:49 2017<br>
New Revision: 309340<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=309340&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=309340&view=rev</a><br>
Log:<br>
[demangler] Use an AST to represent demangled names<br>
<br>
The demangler now demangles by producing an AST, then traverses that<br>
AST to produce a demangled name. This is done for performance reasons,<br>
now the demangler doesn't manuiplate std::strings, which hurt<br>
performance and caused string operations to be inlined into the<br>
parser, leading to large code size and stack usage.<br>
<br>
Differential revision: <a href="https://reviews.llvm.org/D35159" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D35159</a><br>
<br>
Modified:<br>
libcxxabi/trunk/src/cxa_<wbr>demangle.cpp<br>
libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp<br>
<br>
Modified: libcxxabi/trunk/src/cxa_<wbr>demangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp?rev=309340&r1=309339&r2=309340&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxxabi/trunk/src/<wbr>cxa_demangle.cpp?rev=309340&<wbr>r1=309339&r2=309340&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxxabi/trunk/src/cxa_<wbr>demangle.cpp (original)<br>
+++ libcxxabi/trunk/src/cxa_<wbr>demangle.cpp Thu Jul 27 17:43:49 2017<br>
@@ -13,7 +13,6 @@<br>
<br>
#include <vector><br>
#include <algorithm><br>
-#include <string><br>
#include <numeric><br>
#include <cstdlib><br>
#include <cstring><br>
@@ -41,6 +40,1370 @@ enum<br>
success<br>
};<br>
<br>
+class StringView {<br>
+ const char *First;<br>
+ const char *Last;<br>
+<br>
+public:<br>
+ template <size_t N><br>
+ StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}<br>
+ StringView(const char *First, const char *Last) : First(First), Last(Last) {}<br>
+ StringView() : First(nullptr), Last(nullptr) {}<br>
+<br>
+ StringView substr(size_t From, size_t To) {<br>
+ if (To >= size())<br>
+ To = size() - 1;<br>
+ if (From >= size())<br>
+ From = size() - 1;<br>
+ return StringView(First + From, First + To);<br>
+ }<br>
+<br>
+ StringView dropFront(size_t N) const {<br>
+ if (N >= size())<br>
+ N = size() - 1;<br>
+ return StringView(First + N, Last);<br>
+ }<br>
+<br>
+ bool startsWith(StringView Str) const {<br>
+ if (Str.size() > size())<br>
+ return false;<br>
+ return std::equal(Str.begin(), Str.end(), begin());<br>
+ }<br>
+<br>
+ const char &operator[](size_t Idx) const { return *(begin() + Idx); }<br>
+<br>
+ const char *begin() const { return First; }<br>
+ const char *end() const { return Last; }<br>
+ size_t size() const { return static_cast<size_t>(Last - First); }<br>
+};<br>
+<br>
+bool operator==(const StringView &LHS, const StringView &RHS) {<br>
+ return LHS.size() == RHS.size() &&<br>
+ std::equal(LHS.begin(), LHS.end(), RHS.begin());<br>
+}<br>
+<br>
+// Stream that AST nodes write their string representation into after the AST<br>
+// has been parsed.<br>
+class OutputStream {<br>
+ char *Buffer;<br>
+ size_t CurrentPosition;<br>
+ size_t BufferCapacity;<br>
+<br>
+ // Ensure there is at least n more positions in buffer.<br>
+ void grow(size_t N) {<br>
+ if (N + CurrentPosition >= BufferCapacity) {<br>
+ BufferCapacity *= 2;<br>
+ if (BufferCapacity < N + CurrentPosition)<br>
+ BufferCapacity = N + CurrentPosition;<br>
+ Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));<br>
+ }<br>
+ }<br>
+<br>
+public:<br>
+ OutputStream(char *StartBuf, size_t Size)<br>
+ : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}<br>
+<br>
+ OutputStream &operator+=(StringView R) {<br>
+ size_t Size = R.size();<br>
+ if (Size == 0)<br>
+ return *this;<br>
+ grow(Size);<br>
+ memmove(Buffer + CurrentPosition, R.begin(), Size);<br>
+ CurrentPosition += Size;<br>
+ return *this;<br>
+ }<br>
+<br>
+ OutputStream &operator+=(char C) {<br>
+ grow(1);<br>
+ Buffer[CurrentPosition++] = C;<br>
+ return *this;<br>
+ }<br>
+<br>
+ // Offset of position in buffer, used for building stream_string_view.<br>
+ typedef unsigned StreamPosition;<br>
+<br>
+ // StringView into a stream, used for caching the ast nodes.<br>
+ class StreamStringView {<br>
+ StreamPosition First, Last;<br>
+<br>
+ friend class OutputStream;<br>
+<br>
+ public:<br>
+ StreamStringView() : First(0), Last(0) {}<br>
+<br>
+ StreamStringView(<wbr>StreamPosition First, StreamPosition Last)<br>
+ : First(First), Last(Last) {}<br>
+<br>
+ bool empty() const { return First == Last; }<br>
+ };<br>
+<br>
+ OutputStream &operator+=(StreamStringView &s) {<br>
+ size_t Sz = static_cast<size_t>(s.Last - s.First);<br>
+ if (Sz == 0)<br>
+ return *this;<br>
+ grow(Sz);<br>
+ memmove(Buffer + CurrentPosition, Buffer + s.First, Sz);<br>
+ CurrentPosition += Sz;<br>
+ return *this;<br>
+ }<br>
+<br>
+ StreamPosition getCurrentPosition() const {<br>
+ return static_cast<StreamPosition>(<wbr>CurrentPosition);<br>
+ }<br>
+<br>
+ StreamStringView makeStringViewFromPastPosition<wbr>(StreamPosition Pos) {<br>
+ return StreamStringView(Pos, getCurrentPosition());<br>
+ }<br>
+<br>
+ char back() const {<br>
+ return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';<br>
+ }<br>
+<br>
+ bool empty() const { return CurrentPosition == 0; }<br>
+<br>
+ char *getBuffer() { return Buffer; }<br>
+ char *getBufferEnd() { return Buffer + CurrentPosition - 1; }<br>
+ size_t getBufferCapacity() { return BufferCapacity; }<br>
+};<br>
+<br>
+// Base class of all AST nodes. The AST is built by the parser, then is<br>
+// traversed by the printLeft/Right functions to produce a demangled string.<br>
+class Node {<br>
+public:<br>
+ enum Kind : unsigned char {<br>
+ KDotSuffix,<br>
+ KVendorExtQualType,<br>
+ KQualType,<br>
+ KConversionOperatorType,<br>
+ KPostfixQualifiedType,<br>
+ KNameType,<br>
+ KObjCProtoName,<br>
+ KPointerType,<br>
+ KLValueReferenceType,<br>
+ KRValueReferenceType,<br>
+ KPointerToMemberType,<br>
+ KArrayType,<br>
+ KFunctionType,<br>
+ KTopLevelFunctionDecl,<br>
+ KFunctionQualType,<br>
+ KFunctionRefQualType,<br>
+ KLiteralOperator,<br>
+ KSpecialName,<br>
+ KCtorVtableSpecialName,<br>
+ KQualifiedName,<br>
+ KEmptyName,<br>
+ KVectorType,<br>
+ KTemplateParams,<br>
+ KNameWithTemplateArgs,<br>
+ KGlobalQualifiedName,<br>
+ KStdQualifiedName,<br>
+ KExpandedSpecialSubstitution,<br>
+ KSpecialSubstitution,<br>
+ KCtorDtorName,<br>
+ KDtorName,<br>
+ KUnnamedTypeName,<br>
+ KLambdaTypeName,<br>
+ KExpr,<br>
+ };<br>
+<br>
+ const Kind K;<br>
+<br>
+private:<br>
+ // If this Node has any RHS part, potentally many Nodes further down.<br>
+ const unsigned HasRHSComponent : 1;<br>
+ const unsigned HasFunction : 1;<br>
+ const unsigned HasArray : 1;<br>
+<br>
+public:<br>
+ Node(Kind K, bool HasRHS = false, bool HasFunction = false,<br>
+ bool HasArray = false)<br>
+ : K(K), HasRHSComponent(HasRHS), HasFunction(HasFunction),<br>
+ HasArray(HasArray) {}<br>
+<br>
+ bool hasRHSComponent() const { return HasRHSComponent; }<br>
+ bool hasArray() const { return HasArray; }<br>
+ bool hasFunction() const { return HasFunction; }<br>
+<br>
+ void print(OutputStream &s) const {<br>
+ printLeft(s);<br>
+ if (hasRHSComponent())<br>
+ printRight(s);<br>
+ }<br>
+<br>
+ // Print the "left" side of this Node into OutputStream.<br>
+ virtual void printLeft(OutputStream &) const = 0;<br>
+<br>
+ // Print the "right". This distinction is necessary to represent C++ types<br>
+ // that appear on the RHS of their subtype, such as arrays or functions.<br>
+ // Since most types don't have such a component, provide a default<br>
+ // implemenation.<br>
+ virtual void printRight(OutputStream &) const {}<br>
+<br>
+ virtual StringView getBaseName() const { return StringView(); }<br>
+<br>
+ // Silence compiler warnings, this dtor will never be called.<br>
+ virtual ~Node() = default;<br>
+};<br>
+<br>
+class NodeArray {<br>
+ Node **Elements;<br>
+ size_t NumElements;<br>
+<br>
+public:<br>
+ NodeArray() : NumElements(0) {}<br>
+ NodeArray(Node **Elements, size_t NumElements)<br>
+ : Elements(Elements), NumElements(NumElements) {}<br>
+<br>
+ bool empty() const { return NumElements == 0; }<br>
+ size_t size() const { return NumElements; }<br>
+<br>
+ void printWithSeperator(<wbr>OutputStream &S, StringView Seperator) const {<br>
+ for (size_t Idx = 0; Idx != NumElements; ++Idx) {<br>
+ if (Idx)<br>
+ S += Seperator;<br>
+ Elements[Idx]->print(S);<br>
+ }<br>
+ }<br>
+};<br>
+<br>
+class DotSuffix final : public Node {<br>
+ const Node *Prefix;<br>
+ const StringView Suffix;<br>
+<br>
+public:<br>
+ DotSuffix(Node *Prefix, StringView Suffix)<br>
+ : Node(KDotSuffix), Prefix(Prefix), Suffix(Suffix) {}<br>
+<br>
+ void printLeft(OutputStream &s) const override {<br>
+ Prefix->print(s);<br>
+ s += " (";<br>
+ s += Suffix;<br>
+ s += ")";<br>
+ }<br>
+};<br>
+<br>
+class VendorExtQualType final : public Node {<br>
+ const Node *Ext;<br>
+ const Node *Ty;<br>
+<br>
+public:<br>
+ VendorExtQualType(Node *Ext, Node *Ty)<br>
+ : Node(KVendorExtQualType), Ext(Ext), Ty(Ty) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ Ext->print(S);<br>
+ S += " ";<br>
+ Ty->printLeft(S);<br>
+ }<br>
+<br>
+ void printRight(OutputStream &S) const override { Ty->printRight(S); }<br>
+};<br>
+<br>
+enum Qualifiers {<br>
+ QualNone = 0,<br>
+ QualConst = 0x1,<br>
+ QualVolatile = 0x2,<br>
+ QualRestrict = 0x4,<br>
+};<br>
+<br>
+void addQualifiers(Qualifiers &Q1, Qualifiers Q2) {<br>
+ Q1 = static_cast<Qualifiers>(Q1 | Q2);<br>
+}<br>
+<br>
+class QualType : public Node {<br>
+protected:<br>
+ const Qualifiers Quals;<br>
+ const Node *Child;<br>
+<br>
+ void printQuals(OutputStream &S) const {<br>
+ if (Quals & QualConst)<br>
+ S += " const";<br>
+ if (Quals & QualVolatile)<br>
+ S += " volatile";<br>
+ if (Quals & QualRestrict)<br>
+ S += " restrict";<br>
+ }<br>
+<br>
+public:<br>
+ QualType(Node *Child, Qualifiers Quals)<br>
+ : Node(KQualType, Child->hasRHSComponent(), Child->hasFunction(),<br>
+ Child->hasArray()),<br>
+ Quals(Quals), Child(Child) {}<br>
+<br>
+ QualType(Node::Kind ChildKind, Node *Child, Qualifiers Quals)<br>
+ : Node(ChildKind, Child->hasRHSComponent(), Child->hasFunction(),<br>
+ Child->hasArray()),<br>
+ Quals(Quals), Child(Child) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ Child->printLeft(S);<br>
+ printQuals(S);<br>
+ }<br>
+<br>
+ void printRight(OutputStream &S) const override { Child->printRight(S); }<br>
+};<br>
+<br>
+class ConversionOperatorType final : public Node {<br>
+ const Node *Ty;<br>
+<br>
+public:<br>
+ ConversionOperatorType(Node *Ty) : Node(KConversionOperatorType), Ty(Ty) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "operator ";<br>
+ Ty->print(S);<br>
+ }<br>
+};<br>
+<br>
+class PostfixQualifiedType final : public Node {<br>
+ const Node *Ty;<br>
+ const StringView Postfix;<br>
+<br>
+public:<br>
+ PostfixQualifiedType(Node *Ty, StringView Postfix)<br>
+ : Node(KPostfixQualifiedType), Ty(Ty), Postfix(Postfix) {}<br>
+<br>
+ void printLeft(OutputStream &s) const override {<br>
+ Ty->printLeft(s);<br>
+ s += Postfix;<br>
+ }<br>
+<br>
+ void printRight(OutputStream &S) const override { Ty->printRight(S); }<br>
+};<br>
+<br>
+class NameType final : public Node {<br>
+ const StringView Name;<br>
+<br>
+public:<br>
+ NameType(StringView Name) : Node(KNameType), Name(Name) {}<br>
+<br>
+ StringView getName() const { return Name; }<br>
+ StringView getBaseName() const override { return Name; }<br>
+<br>
+ void printLeft(OutputStream &s) const override { s += Name; }<br>
+};<br>
+<br>
+class ObjCProtoName : public Node {<br>
+ Node *Ty;<br>
+ Node *Protocol;<br>
+<br>
+ friend class PointerType;<br>
+<br>
+public:<br>
+ ObjCProtoName(Node *Ty, Node *Protocol)<br>
+ : Node(KObjCProtoName), Ty(Ty), Protocol(Protocol) {}<br>
+<br>
+ bool isObjCObject() const {<br>
+ return Ty->K == KNameType &&<br>
+ static_cast<NameType *>(Ty)->getName() == "objc_object";<br>
+ }<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ Ty->printLeft(S);<br>
+ S += "<";<br>
+ Protocol->printLeft(S);<br>
+ S += ">";<br>
+ }<br>
+};<br>
+<br>
+class PointerType final : public Node {<br>
+ const Node *Pointee;<br>
+<br>
+public:<br>
+ PointerType(Node *Pointee)<br>
+ : Node(KPointerType, Pointee->hasRHSComponent()), Pointee(Pointee) {}<br>
+<br>
+ void printLeft(OutputStream &s) const override {<br>
+ // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.<br>
+ if (Pointee->K != KObjCProtoName ||<br>
+ !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {<br>
+ Pointee->printLeft(s);<br>
+ if (Pointee->hasArray())<br>
+ s += " ";<br>
+ if (Pointee->hasArray() || Pointee->hasFunction())<br>
+ s += "(";<br>
+ s += "*";<br>
+ } else {<br>
+ const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);<br>
+ s += "id<";<br>
+ objcProto->Protocol->print(s);<br>
+ s += ">";<br>
+ }<br>
+ }<br>
+<br>
+ void printRight(OutputStream &s) const override {<br>
+ if (Pointee->K != KObjCProtoName ||<br>
+ !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {<br>
+ if (Pointee->hasArray() || Pointee->hasFunction())<br>
+ s += ")";<br>
+ Pointee->printRight(s);<br>
+ }<br>
+ }<br>
+};<br>
+<br>
+class LValueReferenceType final : public Node {<br>
+ const Node *Pointee;<br>
+<br>
+public:<br>
+ LValueReferenceType(Node *Pointee)<br>
+ : Node(KLValueReferenceType, Pointee->hasRHSComponent()),<br>
+ Pointee(Pointee) {}<br>
+<br>
+ void printLeft(OutputStream &s) const override {<br>
+ Pointee->printLeft(s);<br>
+ if (Pointee->hasArray())<br>
+ s += " ";<br>
+ if (Pointee->hasArray() || Pointee->hasFunction())<br>
+ s += "(&";<br>
+ else<br>
+ s += "&";<br>
+ }<br>
+ void printRight(OutputStream &s) const override {<br>
+ if (Pointee->hasArray() || Pointee->hasFunction())<br>
+ s += ")";<br>
+ Pointee->printRight(s);<br>
+ }<br>
+};<br>
+<br>
+class RValueReferenceType final : public Node {<br>
+ const Node *Pointee;<br>
+<br>
+public:<br>
+ RValueReferenceType(Node *Pointee)<br>
+ : Node(KRValueReferenceType, Pointee->hasRHSComponent()),<br>
+ Pointee(Pointee) {}<br>
+<br>
+ void printLeft(OutputStream &s) const override {<br>
+ Pointee->printLeft(s);<br>
+ if (Pointee->hasArray())<br>
+ s += " ";<br>
+ if (Pointee->hasArray() || Pointee->hasFunction())<br>
+ s += "(&&";<br>
+ else<br>
+ s += "&&";<br>
+ }<br>
+<br>
+ void printRight(OutputStream &s) const override {<br>
+ if (Pointee->hasArray() || Pointee->hasFunction())<br>
+ s += ")";<br>
+ Pointee->printRight(s);<br>
+ }<br>
+};<br>
+<br>
+class PointerToMemberType final : public Node {<br>
+ const Node *ClassType;<br>
+ const Node *MemberType;<br>
+<br>
+public:<br>
+ PointerToMemberType(Node *ClassType, Node *MemberType)<br>
+ : Node(KPointerToMemberType, MemberType->hasRHSComponent())<wbr>,<br>
+ ClassType(ClassType), MemberType(MemberType) {}<br>
+<br>
+ void printLeft(OutputStream &s) const override {<br>
+ MemberType->printLeft(s);<br>
+ if (MemberType->hasArray() || MemberType->hasFunction())<br>
+ s += "(";<br>
+ else<br>
+ s += " ";<br>
+ ClassType->print(s);<br>
+ s += "::*";<br>
+ }<br>
+<br>
+ void printRight(OutputStream &s) const override {<br>
+ if (MemberType->hasArray() || MemberType->hasFunction())<br>
+ s += ")";<br>
+ MemberType->printRight(s);<br>
+ }<br>
+};<br>
+<br>
+class NodeOrString {<br>
+ const void *First;<br>
+ const void *Second;<br>
+<br>
+public:<br>
+ /* implicit */ NodeOrString(StringView Str) {<br>
+ const char *FirstChar = Str.begin();<br>
+ const char *SecondChar = Str.end();<br>
+ if (SecondChar == nullptr) {<br>
+ assert(FirstChar == SecondChar);<br>
+ ++FirstChar, ++SecondChar;<br>
+ }<br>
+ First = static_cast<const void *>(FirstChar);<br>
+ Second = static_cast<const void *>(SecondChar);<br>
+ }<br>
+<br>
+ /* implicit */ NodeOrString(Node *N)<br>
+ : First(static_cast<const void *>(N)), Second(nullptr) {}<br>
+ NodeOrString() : First(nullptr), Second(nullptr) {}<br>
+<br>
+ bool isString() const { return Second && First; }<br>
+ bool isNode() const { return First && !Second; }<br>
+ bool isEmpty() const { return !First && !Second; }<br>
+<br>
+ StringView asString() const {<br>
+ assert(isString());<br>
+ return StringView(static_cast<const char *>(First),<br>
+ static_cast<const char *>(Second));<br>
+ }<br>
+<br>
+ const Node *asNode() const {<br>
+ assert(isNode());<br>
+ return static_cast<const Node *>(First);<br>
+ }<br>
+};<br>
+<br>
+class ArrayType final : public Node {<br>
+ Node *Base;<br>
+ NodeOrString Dimension;<br>
+<br>
+public:<br>
+ ArrayType(Node *Base, NodeOrString Dimension)<br>
+ : Node(KArrayType, true, false, true), Base(Base), Dimension(Dimension) {}<br>
+<br>
+ // Incomplete array type.<br>
+ ArrayType(Node *Base) : Node(KArrayType, true, false, true), Base(Base) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override { Base->printLeft(S); }<br>
+<br>
+ void printRight(OutputStream &S) const override {<br>
+ if (S.back() != ']')<br>
+ S += " ";<br>
+ S += "[";<br>
+ if (Dimension.isString())<br>
+ S += Dimension.asString();<br>
+ else if (Dimension.isNode())<br>
+ Dimension.asNode()->print(S);<br>
+ S += "]";<br>
+ Base->printRight(S);<br>
+ }<br>
+};<br>
+<br>
+class FunctionType final : public Node {<br>
+ Node *Ret;<br>
+ NodeArray Params;<br>
+<br>
+public:<br>
+ FunctionType(Node *Ret, NodeArray Params)<br>
+ : Node(KFunctionType, true, true), Ret(Ret), Params(Params) {}<br>
+<br>
+ // Handle C++'s ... quirky decl grammer by using the left & right<br>
+ // distinction. Consider:<br>
+ // int (*f(float))(char) {}<br>
+ // f is a function that takes a float and returns a pointer to a function<br>
+ // that takes a char and returns an int. If we're trying to print f, start<br>
+ // by printing out the return types's left, then print our parameters, then<br>
+ // finally print right of the return type.<br>
+ void printLeft(OutputStream &S) const override {<br>
+ Ret->printLeft(S);<br>
+ S += " ";<br>
+ }<br>
+<br>
+ void printRight(OutputStream &S) const override {<br>
+ S += "(";<br>
+ Params.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ Ret->printRight(S);<br>
+ }<br>
+};<br>
+<br>
+class TopLevelFunctionDecl final : public Node {<br>
+ const Node *Ret;<br>
+ const Node *Name;<br>
+ NodeArray Params;<br>
+<br>
+public:<br>
+ TopLevelFunctionDecl(Node *Ret, Node *Name, NodeArray Params)<br>
+ : Node(KTopLevelFunctionDecl, true, true), Ret(Ret), Name(Name),<br>
+ Params(Params) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (Ret) {<br>
+ Ret->printLeft(S);<br>
+ if (!Ret->hasRHSComponent())<br>
+ S += " ";<br>
+ }<br>
+ Name->print(S);<br>
+ }<br>
+<br>
+ void printRight(OutputStream &S) const override {<br>
+ S += "(";<br>
+ Params.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ if (Ret)<br>
+ Ret->printRight(S);<br>
+ }<br>
+};<br>
+<br>
+enum FunctionRefQual : unsigned char {<br>
+ FrefQualNone,<br>
+ FrefQualLValue,<br>
+ FrefQualRValue,<br>
+};<br>
+<br>
+class FunctionRefQualType : public Node {<br>
+ Node *Fn;<br>
+ FunctionRefQual Quals;<br>
+<br>
+ friend class FunctionQualType;<br>
+<br>
+public:<br>
+ FunctionRefQualType(Node *Fn, FunctionRefQual Quals)<br>
+ : Node(KFunctionRefQualType, true, true), Fn(Fn), Quals(Quals) {}<br>
+<br>
+ void printQuals(OutputStream &S) const {<br>
+ if (Quals == FrefQualLValue)<br>
+ S += " &";<br>
+ else<br>
+ S += " &&";<br>
+ }<br>
+<br>
+ void printLeft(OutputStream &S) const override { Fn->printLeft(S); }<br>
+<br>
+ void printRight(OutputStream &S) const override {<br>
+ Fn->printRight(S);<br>
+ printQuals(S);<br>
+ }<br>
+};<br>
+<br>
+class FunctionQualType final : public QualType {<br>
+public:<br>
+ FunctionQualType(Node *Child, Qualifiers Quals)<br>
+ : QualType(KFunctionQualType, Child, Quals) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override { Child->printLeft(S); }<br>
+<br>
+ void printRight(OutputStream &S) const override {<br>
+ if (Child->K == KFunctionRefQualType) {<br>
+ auto *RefQuals = static_cast<const FunctionRefQualType *>(Child);<br>
+ RefQuals->Fn->printRight(S);<br>
+ printQuals(S);<br>
+ RefQuals->printQuals(S);<br>
+ } else {<br>
+ Child->printRight(S);<br>
+ printQuals(S);<br>
+ }<br>
+ }<br>
+};<br>
+<br>
+class LiteralOperator : public Node {<br>
+ const Node *OpName;<br>
+<br>
+public:<br>
+ LiteralOperator(Node *OpName) : Node(KLiteralOperator), OpName(OpName) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "operator\"\" ";<br>
+ OpName->print(S);<br>
+ }<br>
+};<br>
+<br>
+class SpecialName final : public Node {<br>
+ const StringView Special;<br>
+ const Node *Child;<br>
+<br>
+public:<br>
+ SpecialName(StringView Special, Node *Child)<br>
+ : Node(KSpecialName), Special(Special), Child(Child) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += Special;<br>
+ Child->print(S);<br>
+ }<br>
+};<br>
+<br>
+class CtorVtableSpecialName final : public Node {<br>
+ const Node *FirstType;<br>
+ const Node *SecondType;<br>
+<br>
+public:<br>
+ CtorVtableSpecialName(Node *FirstType, Node *SecondType)<br>
+ : Node(KCtorVtableSpecialName), FirstType(FirstType),<br>
+ SecondType(SecondType) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "construction vtable for ";<br>
+ FirstType->print(S);<br>
+ S += "-in-";<br>
+ SecondType->print(S);<br>
+ }<br>
+};<br>
+<br>
+class QualifiedName final : public Node {<br>
+ // qualifier::name<br>
+ const Node *Qualifier;<br>
+ const Node *Name;<br>
+<br>
+ mutable OutputStream::StreamStringView Cache;<br>
+<br>
+public:<br>
+ QualifiedName(Node *Qualifier, Node *Name)<br>
+ : Node(KQualifiedName), Qualifier(Qualifier), Name(Name) {}<br>
+<br>
+ StringView getBaseName() const override { return Name->getBaseName(); }<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (!Cache.empty()) {<br>
+ S += Cache;<br>
+ return;<br>
+ }<br>
+<br>
+ OutputStream::StreamPosition Start = S.getCurrentPosition();<br>
+ if (Qualifier->K != KEmptyName) {<br>
+ Qualifier->print(S);<br>
+ S += "::";<br>
+ }<br>
+ Name->print(S);<br>
+ Cache = S.<wbr>makeStringViewFromPastPosition<wbr>(Start);<br>
+ }<br>
+};<br>
+<br>
+class EmptyName : public Node {<br>
+public:<br>
+ EmptyName() : Node(KEmptyName) {}<br>
+ void printLeft(OutputStream &) const override {}<br>
+};<br>
+<br>
+class VectorType final : public Node {<br>
+ const Node *BaseType;<br>
+ const NodeOrString Dimension;<br>
+ const bool IsPixel;<br>
+<br>
+public:<br>
+ VectorType(NodeOrString Dimension)<br>
+ : Node(KVectorType), BaseType(nullptr), Dimension(Dimension),<br>
+ IsPixel(true) {}<br>
+ VectorType(Node *BaseType, NodeOrString Dimension)<br>
+ : Node(KVectorType), BaseType(BaseType), Dimension(Dimension),<br>
+ IsPixel(false) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (IsPixel) {<br>
+ S += "pixel vector[";<br>
+ S += Dimension.asString();<br>
+ S += "]";<br>
+ } else {<br>
+ BaseType->print(S);<br>
+ S += " vector[";<br>
+ if (Dimension.isNode())<br>
+ Dimension.asNode()->print(S);<br>
+ else if (Dimension.isString())<br>
+ S += Dimension.asString();<br>
+ S += "]";<br>
+ }<br>
+ }<br>
+};<br>
+<br>
+class TemplateParams final : public Node {<br>
+ NodeArray Params;<br>
+<br>
+ mutable OutputStream::StreamStringView Cache;<br>
+<br>
+public:<br>
+ TemplateParams(NodeArray Params) : Node(KTemplateParams), Params(Params) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (!Cache.empty()) {<br>
+ S += Cache;<br>
+ return;<br>
+ }<br>
+<br>
+ OutputStream::StreamPosition Start = S.getCurrentPosition();<br>
+<br>
+ S += "<";<br>
+ Params.printWithSeperator(S, ", ");<br>
+ if (S.back() == '>')<br>
+ S += " ";<br>
+ S += ">";<br>
+<br>
+ Cache = S.<wbr>makeStringViewFromPastPosition<wbr>(Start);<br>
+ }<br>
+};<br>
+<br>
+class NameWithTemplateArgs final : public Node {<br>
+ // name<template_args><br>
+ Node *Name;<br>
+ Node *TemplateArgs;<br>
+<br>
+public:<br>
+ NameWithTemplateArgs(Node *Name, Node *TemplateArgs)<br>
+ : Node(KNameWithTemplateArgs), Name(Name), TemplateArgs(TemplateArgs) {}<br>
+<br>
+ StringView getBaseName() const override { return Name->getBaseName(); }<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ Name->print(S);<br>
+ TemplateArgs->print(S);<br>
+ }<br>
+};<br>
+<br>
+class GlobalQualifiedName final : public Node {<br>
+ Node *Child;<br>
+<br>
+public:<br>
+ GlobalQualifiedName(Node *Child) : Node(KGlobalQualifiedName), Child(Child) {}<br>
+<br>
+ StringView getBaseName() const override { return Child->getBaseName(); }<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "::";<br>
+ Child->print(S);<br>
+ }<br>
+};<br>
+<br>
+class StdQualifiedName final : public Node {<br>
+ Node *Child;<br>
+<br>
+public:<br>
+ StdQualifiedName(Node *Child) : Node(KStdQualifiedName), Child(Child) {}<br>
+<br>
+ StringView getBaseName() const override { return Child->getBaseName(); }<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "std::";<br>
+ Child->print(S);<br>
+ }<br>
+};<br>
+<br>
+enum class SpecialSubKind {<br>
+ allocator,<br>
+ basic_string,<br>
+ string,<br>
+ istream,<br>
+ ostream,<br>
+ iostream,<br>
+};<br>
+<br>
+class ExpandedSpecialSubstitution final : public Node {<br>
+ SpecialSubKind SSK;<br>
+<br>
+public:<br>
+ ExpandedSpecialSubstitution(<wbr>SpecialSubKind SSK)<br>
+ : Node(<wbr>KExpandedSpecialSubstitution), SSK(SSK) {}<br>
+<br>
+ StringView getBaseName() const override {<br>
+ switch (SSK) {<br>
+ case SpecialSubKind::allocator:<br>
+ return StringView("allocator");<br>
+ case SpecialSubKind::basic_string:<br>
+ return StringView("basic_string");<br>
+ case SpecialSubKind::string:<br>
+ return StringView("basic_string");<br>
+ case SpecialSubKind::istream:<br>
+ return StringView("basic_istream");<br>
+ case SpecialSubKind::ostream:<br>
+ return StringView("basic_ostream");<br>
+ case SpecialSubKind::iostream:<br>
+ return StringView("basic_iostream");<br>
+ }<br>
+ }<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ switch (SSK) {<br>
+ case SpecialSubKind::allocator:<br>
+ S += "std::basic_string<char, std::char_traits<char>, "<br>
+ "std::allocator<char> >";<br>
+ break;<br>
+ case SpecialSubKind::basic_string:<br>
+ case SpecialSubKind::string:<br>
+ S += "std::basic_string<char, std::char_traits<char>, "<br>
+ "std::allocator<char> >";<br>
+ break;<br>
+ case SpecialSubKind::istream:<br>
+ S += "std::basic_istream<char, std::char_traits<char> >";<br>
+ break;<br>
+ case SpecialSubKind::ostream:<br>
+ S += "std::basic_ostream<char, std::char_traits<char> >";<br>
+ break;<br>
+ case SpecialSubKind::iostream:<br>
+ S += "std::basic_iostream<char, std::char_traits<char> >";<br>
+ break;<br>
+ }<br>
+ }<br>
+};<br>
+<br>
+class SpecialSubstitution final : public Node {<br>
+public:<br>
+ SpecialSubKind SSK;<br>
+<br>
+ SpecialSubstitution(<wbr>SpecialSubKind SSK)<br>
+ : Node(KSpecialSubstitution), SSK(SSK) {}<br>
+<br>
+ StringView getBaseName() const override {<br>
+ switch (SSK) {<br>
+ case SpecialSubKind::allocator:<br>
+ return StringView("allocator");<br>
+ case SpecialSubKind::basic_string:<br>
+ return StringView("basic_string");<br>
+ case SpecialSubKind::string:<br>
+ return StringView("string");<br>
+ case SpecialSubKind::istream:<br>
+ return StringView("istream");<br>
+ case SpecialSubKind::ostream:<br>
+ return StringView("ostream");<br>
+ case SpecialSubKind::iostream:<br>
+ return StringView("iostream");<br>
+ }<br>
+ }<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ switch (SSK) {<br>
+ case SpecialSubKind::allocator:<br>
+ S += "std::allocator";<br>
+ break;<br>
+ case SpecialSubKind::basic_string:<br>
+ S += "std::basic_string";<br>
+ break;<br>
+ case SpecialSubKind::string:<br>
+ S += "std::string";<br>
+ break;<br>
+ case SpecialSubKind::istream:<br>
+ S += "std::istream";<br>
+ break;<br>
+ case SpecialSubKind::ostream:<br>
+ S += "std::ostream";<br>
+ break;<br>
+ case SpecialSubKind::iostream:<br>
+ S += "std::iostream";<br>
+ break;<br>
+ }<br>
+ }<br>
+};<br>
+<br>
+class CtorDtorName final : public Node {<br>
+ const Node *Basename;<br>
+ const bool IsDtor;<br>
+<br>
+public:<br>
+ CtorDtorName(Node *Basename, bool IsDtor)<br>
+ : Node(KCtorDtorName), Basename(Basename), IsDtor(IsDtor) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (IsDtor)<br>
+ S += "~";<br>
+ S += Basename->getBaseName();<br>
+ }<br>
+};<br>
+<br>
+class DtorName : public Node {<br>
+ const Node *Base;<br>
+<br>
+public:<br>
+ DtorName(Node *Base) : Node(KDtorName), Base(Base) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "~";<br>
+ Base->printLeft(S);<br>
+ }<br>
+};<br>
+<br>
+class UnnamedTypeName : public Node {<br>
+ const StringView Count;<br>
+<br>
+public:<br>
+ UnnamedTypeName(StringView Count) : Node(KUnnamedTypeName), Count(Count) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "'unnamed";<br>
+ S += Count;<br>
+ S += "\'";<br>
+ }<br>
+};<br>
+<br>
+class LambdaTypeName : public Node {<br>
+ NodeArray Params;<br>
+ StringView Count;<br>
+<br>
+public:<br>
+ LambdaTypeName(NodeArray Params, StringView Count)<br>
+ : Node(KLambdaTypeName), Params(Params), Count(Count) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "\'lambda";<br>
+ S += Count;<br>
+ S += "\'(";<br>
+ Params.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+// -- Expression Nodes --<br>
+<br>
+struct Expr : public Node {<br>
+ Expr() : Node(KExpr) {}<br>
+};<br>
+<br>
+class BinaryExpr : public Expr {<br>
+ const Node *LHS;<br>
+ const StringView InfixOperator;<br>
+ const Node *RHS;<br>
+<br>
+public:<br>
+ BinaryExpr(Node *LHS, StringView InfixOperator, Node *RHS)<br>
+ : LHS(LHS), InfixOperator(InfixOperator), RHS(RHS) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ // might be a template argument expression, then we need to disambiguate<br>
+ // with parens.<br>
+ if (InfixOperator == ">")<br>
+ S += "(";<br>
+<br>
+ S += "(";<br>
+ LHS->print(S);<br>
+ S += ") ";<br>
+ S += InfixOperator;<br>
+ S += " (";<br>
+ RHS->print(S);<br>
+ S += ")";<br>
+<br>
+ if (InfixOperator == ">")<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class ArraySubscriptExpr : public Expr {<br>
+ const Node *Op1;<br>
+ const Node *Op2;<br>
+<br>
+public:<br>
+ ArraySubscriptExpr(Node *Op1, Node *Op2) : Op1(Op1), Op2(Op2) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "(";<br>
+ Op1->print(S);<br>
+ S += ")[";<br>
+ Op2->print(S);<br>
+ S += "]";<br>
+ }<br>
+};<br>
+<br>
+class PostfixExpr : public Expr {<br>
+ const Node *Child;<br>
+ const StringView Operand;<br>
+<br>
+public:<br>
+ PostfixExpr(Node *Child, StringView Operand)<br>
+ : Child(Child), Operand(Operand) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "(";<br>
+ Child->print(S);<br>
+ S += ")";<br>
+ S += Operand;<br>
+ }<br>
+};<br>
+<br>
+class ConditionalExpr : public Expr {<br>
+ const Node *Cond;<br>
+ const Node *Then;<br>
+ const Node *Else;<br>
+<br>
+public:<br>
+ ConditionalExpr(Node *Cond, Node *Then, Node *Else)<br>
+ : Cond(Cond), Then(Then), Else(Else) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "(";<br>
+ Cond->print(S);<br>
+ S += ") ? (";<br>
+ Then->print(S);<br>
+ S += ") : (";<br>
+ Else->print(S);<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class MemberExpr : public Expr {<br>
+ const Node *LHS;<br>
+ const StringView Kind;<br>
+ const Node *RHS;<br>
+<br>
+public:<br>
+ MemberExpr(Node *LHS, StringView Kind, Node *RHS)<br>
+ : LHS(LHS), Kind(Kind), RHS(RHS) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ LHS->print(S);<br>
+ S += Kind;<br>
+ RHS->print(S);<br>
+ }<br>
+};<br>
+<br>
+class EnclosingExpr : public Expr {<br>
+ const StringView Prefix;<br>
+ const Node *Infix;<br>
+ const StringView Postfix;<br>
+<br>
+public:<br>
+ EnclosingExpr(StringView Prefix, Node *Infix, StringView Postfix)<br>
+ : Prefix(Prefix), Infix(Infix), Postfix(Postfix) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += Prefix;<br>
+ Infix->print(S);<br>
+ S += Postfix;<br>
+ }<br>
+};<br>
+<br>
+class CastExpr : public Expr {<br>
+ // cast_kind<to>(from)<br>
+ const StringView CastKind;<br>
+ const Node *To;<br>
+ const Node *From;<br>
+<br>
+public:<br>
+ CastExpr(StringView CastKind, Node *To, Node *From)<br>
+ : CastKind(CastKind), To(To), From(From) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += CastKind;<br>
+ S += "<";<br>
+ To->printLeft(S);<br>
+ S += ">(";<br>
+ From->printLeft(S);<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class SizeofParamPackExpr : public Expr {<br>
+ NodeArray Args;<br>
+<br>
+public:<br>
+ SizeofParamPackExpr(NodeArray Args) : Args(Args) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "sizeof...(";<br>
+ Args.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class CallExpr : public Expr {<br>
+ const Node *Callee;<br>
+ NodeArray Args;<br>
+<br>
+public:<br>
+ CallExpr(Node *Callee, NodeArray Args) : Callee(Callee), Args(Args) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ Callee->print(S);<br>
+ S += "(";<br>
+ Args.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class NewExpr : public Expr {<br>
+ // new (expr_list) type(init_list)<br>
+ NodeArray ExprList;<br>
+ Node *Type;<br>
+ NodeArray InitList;<br>
+ bool IsGlobal; // ::operator new ?<br>
+ bool IsArray; // new[] ?<br>
+public:<br>
+ NewExpr(NodeArray ExprList, Node *Type, NodeArray InitList, bool IsGlobal,<br>
+ bool IsArray)<br>
+ : ExprList(ExprList), Type(Type), InitList(InitList), IsGlobal(IsGlobal),<br>
+ IsArray(IsArray) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (IsGlobal)<br>
+ S += "::operator ";<br>
+ S += "new";<br>
+ if (IsArray)<br>
+ S += "[]";<br>
+ if (!ExprList.empty()) {<br>
+ S += "(";<br>
+ ExprList.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ }<br>
+ Type->print(S);<br>
+ if (!InitList.empty()) {<br>
+ S += "(";<br>
+ InitList.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ }<br>
+ }<br>
+};<br>
+<br>
+class DeleteExpr : public Expr {<br>
+ Node *Op;<br>
+ bool IsGlobal;<br>
+ bool IsArray;<br>
+<br>
+public:<br>
+ DeleteExpr(Node *Op, bool IsGlobal, bool IsArray)<br>
+ : Op(Op), IsGlobal(IsGlobal), IsArray(IsArray) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (IsGlobal)<br>
+ S += "::";<br>
+ S += "delete";<br>
+ if (IsArray)<br>
+ S += "[] ";<br>
+ Op->print(S);<br>
+ }<br>
+};<br>
+<br>
+class PrefixExpr : public Expr {<br>
+ StringView Prefix;<br>
+ Node *Child;<br>
+<br>
+public:<br>
+ PrefixExpr(StringView Prefix, Node *Child) : Prefix(Prefix), Child(Child) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += Prefix;<br>
+ S += "(";<br>
+ Child->print(S);<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class FunctionParam : public Expr {<br>
+ StringView Number;<br>
+<br>
+public:<br>
+ FunctionParam(StringView Number) : Number(Number) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "fp";<br>
+ S += Number;<br>
+ }<br>
+};<br>
+<br>
+class ExprList : public Expr {<br>
+ NodeArray SubExprs;<br>
+<br>
+public:<br>
+ ExprList(NodeArray SubExprs) : SubExprs(SubExprs) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "(";<br>
+ SubExprs.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class ConversionExpr : public Expr {<br>
+ NodeArray Expressions;<br>
+ NodeArray Types;<br>
+<br>
+public:<br>
+ ConversionExpr(NodeArray Expressions, NodeArray Types)<br>
+ : Expressions(Expressions), Types(Types) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "(";<br>
+ Expressions.<wbr>printWithSeperator(S, ", ");<br>
+ S += ")(";<br>
+ Types.printWithSeperator(S, ", ");<br>
+ S += ")";<br>
+ }<br>
+};<br>
+<br>
+class ThrowExpr : public Expr {<br>
+ const Node *Op;<br>
+<br>
+public:<br>
+ ThrowExpr(Node *Op) : Op(Op) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "throw ";<br>
+ Op->print(S);<br>
+ }<br>
+};<br>
+<br>
+class BoolExpr : public Expr {<br>
+ bool Value;<br>
+<br>
+public:<br>
+ BoolExpr(bool Value) : Value(Value) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += Value ? StringView("true") : StringView("false");<br>
+ }<br>
+};<br>
+<br>
+class IntegerCastExpr : public Expr {<br>
+ // ty(integer)<br>
+ Node *Ty;<br>
+ StringView Integer;<br>
+<br>
+public:<br>
+ IntegerCastExpr(Node *Ty, StringView Integer) : Ty(Ty), Integer(Integer) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ S += "(";<br>
+ Ty->print(S);<br>
+ S += ")";<br>
+ S += Integer;<br>
+ }<br>
+};<br>
+<br>
+class IntegerExpr : public Expr {<br>
+ StringView Type;<br>
+ StringView Value;<br>
+<br>
+public:<br>
+ IntegerExpr(StringView Type, StringView Value) : Type(Type), Value(Value) {}<br>
+<br>
+ void printLeft(OutputStream &S) const override {<br>
+ if (Type.size() > 3) {<br>
+ S += "(";<br>
+ S += Type;<br>
+ S += ")";<br>
+ }<br>
+<br>
+ if (Value[0] == 'n') {<br>
+ S += "-";<br>
+ S += Value.dropFront(1);<br>
+ } else<br>
+ S += Value;<br>
+<br>
+ if (Type.size() <= 3)<br>
+ S += Type;<br>
+ }<br>
+};<br>
+<br>
+template <class Float> struct FloatData;<br>
+<br>
+template <class Float> class FloatExpr : public Expr {<br>
+ const StringView Contents;<br>
+<br>
+public:<br>
+ FloatExpr(StringView Contents) : Contents(Contents) {}<br>
+<br>
+ void printLeft(OutputStream &s) const override {<br>
+ const char *first = Contents.begin();<br>
+ const char *last = Contents.end() + 1;<br>
+<br>
+ const size_t N = FloatData<Float>::mangled_<wbr>size;<br>
+ if (static_cast<std::size_t>(last - first) > N) {<br>
+ last = first + N;<br>
+ union {<br>
+ Float value;<br>
+ char buf[sizeof(Float)];<br>
+ };<br>
+ const char *t = first;<br>
+ char *e = buf;<br>
+ for (; t != last; ++t, ++e) {<br>
+ unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0')<br>
+ : static_cast<unsigned>(*t - 'a' + 10);<br>
+ ++t;<br>
+ unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0')<br>
+ : static_cast<unsigned>(*t - 'a' + 10);<br>
+ *e = static_cast<char>((d1 << 4) + d0);<br>
+ }<br>
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__<br>
+ std::reverse(buf, e);<br>
+#endif<br>
+ char num[FloatData<Float>::max_<wbr>demangled_size] = {0};<br>
+ int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value);<br>
+ s += StringView(num, num + n);<br>
+ }<br>
+ }<br>
+};<br>
+<br>
template <std::size_t N><br>
class arena<br>
{<br>
@@ -148,168 +1511,118 @@ operator!=(const short_alloc<T, N>& x, c<br>
return !(x == y);<br>
}<br>
<br>
-template <class T><br>
-class malloc_alloc<br>
-{<br>
-public:<br>
- typedef T value_type;<br>
- typedef T& reference;<br>
- typedef const T& const_reference;<br>
- typedef T* pointer;<br>
- typedef const T* const_pointer;<br>
- typedef std::size_t size_type;<br>
- typedef std::ptrdiff_t difference_type;<br>
-<br>
- malloc_alloc() = default;<br>
- template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {}<br>
-<br>
- T* allocate(std::size_t n)<br>
- {<br>
- return static_cast<T*>(std::malloc(n*<wbr>sizeof(T)));<br>
- }<br>
- void deallocate(T* p, std::size_t) noexcept<br>
- {<br>
- std::free(p);<br>
- }<br>
-<br>
- template <class U> struct rebind { using other = malloc_alloc<U>; };<br>
- template <class U, class... Args><br>
- void construct(U* p, Args&&... args)<br>
- {<br>
- ::new ((void*)p) U(std::forward<Args>(args)...)<wbr>;<br>
- }<br>
- void destroy(T* p)<br>
- {<br>
- p->~T();<br>
- }<br>
-};<br>
-<br>
-template <class T, class U><br>
-inline<br>
-bool<br>
-operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept<br>
-{<br>
- return true;<br>
-}<br>
-<br>
-template <class T, class U><br>
-inline<br>
-bool<br>
-operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept<br>
-{<br>
- return !(x == y);<br>
-}<br>
-<br>
const size_t bs = 4 * 1024;<br>
template <class T> using Alloc = short_alloc<T, bs>;<br>
template <class T> using Vector = std::vector<T, Alloc<T>>;<br>
<br>
-template <class StrT><br>
-struct string_pair<br>
-{<br>
- StrT first;<br>
- StrT second;<br>
+class BumpPointerAllocator {<br>
+ struct BlockMeta {<br>
+ BlockMeta* Next;<br>
+ size_t Current;<br>
+ };<br>
+<br>
+ static constexpr size_t AllocSize = 4096;<br>
+ static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);<br>
+<br>
+ alignas(16) char InitialBuffer[AllocSize];<br>
+ BlockMeta* BlockList = nullptr;<br>
+<br>
+ void grow() {<br>
+ char* NewMeta = new char[AllocSize];<br>
+ BlockList = new (NewMeta) BlockMeta{BlockList, 0};<br>
+ }<br>
+<br>
+ void* allocateMassive(size_t NBytes) {<br>
+ NBytes += sizeof(BlockMeta);<br>
+ BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(<wbr>new char[NBytes]);<br>
+ BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};<br>
+ return static_cast<void*>(NewMeta + 1);<br>
+ }<br>
<br>
- string_pair() = default;<br>
- string_pair(StrT f) : first(std::move(f)) {}<br>
- string_pair(StrT f, StrT s)<br>
- : first(std::move(f)), second(std::move(s)) {}<br>
- template <size_t N><br>
- string_pair(const char (&s)[N]) : first(s, N-1) {}<br>
+public:<br>
+ BumpPointerAllocator()<br>
+ : BlockList(new (InitialBuffer) BlockMeta{nullptr, 0}) {}<br>
<br>
- size_t size() const {return first.size() + second.size();}<br>
- bool empty() const { return first.empty() && second.empty(); }<br>
- StrT full() const {return first + second;}<br>
- StrT move_full() {return std::move(first) + std::move(second);}<br>
+ void* allocate(size_t N) {<br>
+ N = (N + 15u) & ~15u;<br>
+ if (N + BlockList->Current >= UsableAllocSize) {<br>
+ if (N > UsableAllocSize)<br>
+ return allocateMassive(N);<br>
+ grow();<br>
+ }<br>
+ BlockList->Current += N;<br>
+ return static_cast<void*>(<wbr>reinterpret_cast<char*>(<wbr>BlockList + 1) +<br>
+ BlockList->Current - N);<br>
+ }<br>
+<br>
+ ~BumpPointerAllocator() {<br>
+ while (BlockList) {<br>
+ BlockMeta* Tmp = BlockList;<br>
+ BlockList = BlockList->Next;<br>
+ if (reinterpret_cast<char*>(Tmp) != InitialBuffer)<br>
+ delete[] reinterpret_cast<char*>(Tmp);<br>
+ }<br>
+ }<br>
};<br>
<br>
struct Db<br>
{<br>
- typedef std::basic_string<char, std::char_traits<char>,<br>
- malloc_alloc<char>> String;<br>
- typedef Vector<string_pair<String>> sub_type;<br>
+ typedef Vector<Node*> sub_type;<br>
typedef Vector<sub_type> template_param_type;<br>
sub_type names;<br>
template_param_type subs;<br>
Vector<template_param_type> template_param;<br>
- unsigned cv = 0;<br>
- unsigned ref = 0;<br>
+ Qualifiers cv = QualNone;<br>
+ FunctionRefQual ref = FrefQualNone;<br>
unsigned encoding_depth = 0;<br>
bool parsed_ctor_dtor_cv = false;<br>
bool tag_templates = true;<br>
bool fix_forward_references = false;<br>
bool try_to_parse_template_args = true;<br>
<br>
+ BumpPointerAllocator ASTAllocator;<br>
+<br>
template <size_t N><br>
Db(arena<N>& ar) :<br>
names(ar),<br>
subs(0, names, ar),<br>
template_param(0, subs, ar)<br>
{}<br>
-};<br>
-<br>
<br>
-const char* parse_type(const char* first, const char* last, Db& db);<br>
-const char* parse_encoding(const char* first, const char* last, Db& db);<br>
-const char* parse_name(const char* first, const char* last, Db& db,<br>
- bool* ends_with_template_args = 0);<br>
-const char* parse_expression(const char* first, const char* last, Db& db);<br>
-const char* parse_template_args(const char* first, const char* last, Db& db);<br>
-const char* parse_operator_name(const char* first, const char* last, Db& db);<br>
-const char* parse_unqualified_name(const char* first, const char* last, Db& db);<br>
-const char* parse_decltype(const char* first, const char* last, Db& db);<br>
+ template <class T, class... Args> T* make(Args&& ...args)<br>
+ {<br>
+ return new (ASTAllocator.allocate(sizeof(<wbr>T)))<br>
+ T(std::forward<Args>(args)...)<wbr>;<br>
+ }<br>
<br>
-template <class C><br>
-void<br>
-print_stack(const C& db)<br>
-{<br>
- fprintf(stderr, "---------\n");<br>
- fprintf(stderr, "names:\n");<br>
- for (auto& s : db.names)<br>
- fprintf(stderr, "{%s#%s}\n", s.first.c_str(), s.second.c_str());<br>
- int i = -1;<br>
- fprintf(stderr, "subs:\n");<br>
- for (auto& v : db.subs)<br>
+ template <class It> NodeArray makeNodeArray(It begin, It end)<br>
{<br>
- if (i >= 0)<br>
- fprintf(stderr, "S%i_ = {", i);<br>
- else<br>
- fprintf(stderr, "S_ = {");<br>
- for (auto& s : v)<br>
- fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());<br>
- fprintf(stderr, "}\n");<br>
- ++i;<br>
- }<br>
- fprintf(stderr, "template_param:\n");<br>
- for (auto& t : db.template_param)<br>
- {<br>
- fprintf(stderr, "--\n");<br>
- i = -1;<br>
- for (auto& v : t)<br>
- {<br>
- if (i >= 0)<br>
- fprintf(stderr, "T%i_ = {", i);<br>
- else<br>
- fprintf(stderr, "T_ = {");<br>
- for (auto& s : v)<br>
- fprintf(stderr, "{%s#%s}", s.first.c_str(), s.second.c_str());<br>
- fprintf(stderr, "}\n");<br>
- ++i;<br>
- }<br>
+ size_t sz = static_cast<size_t>(end - begin);<br>
+ void* mem = ASTAllocator.allocate(sizeof(<wbr>Node*) * sz);<br>
+ Node** data = new (mem) Node*[sz];<br>
+ std::copy(begin, end, data);<br>
+ return NodeArray(data, sz);<br>
}<br>
- fprintf(stderr, "---------\n\n");<br>
-}<br>
<br>
-template <class C><br>
-void<br>
-print_state(const char* msg, const char* first, const char* last, const C& db)<br>
-{<br>
- fprintf(stderr, "%s: ", msg);<br>
- for (; first != last; ++first)<br>
- fprintf(stderr, "%c", *first);<br>
- fprintf(stderr, "\n");<br>
- print_stack(db);<br>
-}<br>
+ NodeArray popTrailingNodeArray(size_t FromPosition)<br>
+ {<br>
+ assert(FromPosition <= names.size());<br>
+ NodeArray res = makeNodeArray(<br>
+ names.begin() + (long)FromPosition, names.end());<br>
+ names.erase(names.begin() + (long)FromPosition, names.end());<br>
+ return res;<br>
+ }<br>
+};<br>
+<br>
+const char* parse_type(const char* first, const char* last, Db& db);<br>
+const char* parse_encoding(const char* first, const char* last, Db& db);<br>
+const char* parse_name(const char* first, const char* last, Db& db,<br>
+ bool* ends_with_template_args = 0);<br>
+const char* parse_expression(const char* first, const char* last, Db& db);<br>
+const char* parse_template_args(const char* first, const char* last, Db& db);<br>
+const char* parse_operator_name(const char* first, const char* last, Db& db);<br>
+const char* parse_unqualified_name(const char* first, const char* last, Db& db);<br>
+const char* parse_decltype(const char* first, const char* last, Db& db);<br>
<br>
// <number> ::= [n] <non-negative decimal integer><br>
<br>
@@ -339,30 +1652,30 @@ parse_number(const char* first, const ch<br>
}<br>
<br>
template <class Float><br>
-struct float_data;<br>
+struct FloatData;<br>
<br>
template <><br>
-struct float_data<float><br>
+struct FloatData<float><br>
{<br>
static const size_t mangled_size = 8;<br>
static const size_t max_demangled_size = 24;<br>
static constexpr const char* spec = "%af";<br>
};<br>
<br>
-constexpr const char* float_data<float>::spec;<br>
+constexpr const char* FloatData<float>::spec;<br>
<br>
template <><br>
-struct float_data<double><br>
+struct FloatData<double><br>
{<br>
static const size_t mangled_size = 16;<br>
static const size_t max_demangled_size = 32;<br>
static constexpr const char* spec = "%a";<br>
};<br>
<br>
-constexpr const char* float_data<double>::spec;<br>
+constexpr const char* FloatData<double>::spec;<br>
<br>
template <><br>
-struct float_data<long double><br>
+struct FloatData<long double><br>
{<br>
#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \<br>
defined(__wasm__)<br>
@@ -376,46 +1689,27 @@ struct float_data<long double><br>
static constexpr const char* spec = "%LaL";<br>
};<br>
<br>
-constexpr const char* float_data<long double>::spec;<br>
+constexpr const char* FloatData<long double>::spec;<br>
<br>
template <class Float><br>
const char*<br>
parse_floating_number(const char* first, const char* last, Db& db)<br>
{<br>
- const size_t N = float_data<Float>::mangled_<wbr>size;<br>
- if (static_cast<std::size_t>(last - first) > N)<br>
+ const size_t N = FloatData<Float>::mangled_<wbr>size;<br>
+ if (static_cast<std::size_t>(last - first) <= N)<br>
+ return first;<br>
+ last = first + N;<br>
+ const char* t = first;<br>
+ for (; t != last; ++t)<br>
{<br>
- last = first + N;<br>
- union<br>
- {<br>
- Float value;<br>
- char buf[sizeof(Float)];<br>
- };<br>
- const char* t = first;<br>
- char* e = buf;<br>
- for (; t != last; ++t, ++e)<br>
- {<br>
- if (!isxdigit(*t))<br>
- return first;<br>
- unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :<br>
- static_cast<unsigned>(*t - 'a' + 10);<br>
- ++t;<br>
- unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') :<br>
- static_cast<unsigned>(*t - 'a' + 10);<br>
- *e = static_cast<char>((d1 << 4) + d0);<br>
- }<br>
- if (*t == 'E')<br>
- {<br>
-#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__<br>
- std::reverse(buf, e);<br>
-#endif<br>
- char num[float_data<Float>::max_<wbr>demangled_size] = {0};<br>
- int n = snprintf(num, sizeof(num), float_data<Float>::spec, value);<br>
- if (static_cast<std::size_t>(n) >= sizeof(num))<br>
- return first;<br>
- db.names.push_back(Db::String(<wbr>num, static_cast<std::size_t>(n)));<br>
- first = t+1;<br>
- }<br>
+ if (!isxdigit(*t))<br>
+ return first;<br>
+ }<br>
+ if (*t == 'E')<br>
+ {<br>
+ db.names.push_back(<br>
+ db.make<FloatExpr<Float>>(<wbr>StringView(first, t)));<br>
+ first = t + 1;<br>
}<br>
return first;<br>
}<br>
@@ -440,11 +1734,11 @@ parse_source_name(const char* first, con<br>
}<br>
if (static_cast<size_t>(last - t) >= n)<br>
{<br>
- Db::String r(t, n);<br>
+ StringView r(t, t + n);<br>
if (r.substr(0, 10) == "_GLOBAL__N")<br>
- db.names.push_back("(anonymous namespace)");<br>
+ db.names.push_back(db.make<<wbr>NameType>("(anonymous namespace)"));<br>
else<br>
- db.names.push_back(std::move(<wbr>r));<br>
+ db.names.push_back(db.make<<wbr>NameType>(r));<br>
first = t + n;<br>
}<br>
}<br>
@@ -473,27 +1767,32 @@ parse_substitution(const char* first, co<br>
switch (first[1])<br>
{<br>
case 'a':<br>
- db.names.push_back("std::<wbr>allocator");<br>
+ db.names.push_back(<br>
+ db.make<SpecialSubstitution>(<br>
+ SpecialSubKind::allocator));<br>
first += 2;<br>
break;<br>
case 'b':<br>
- db.names.push_back("std::<wbr>basic_string");<br>
+ db.names.push_back(<br>
+ db.make<SpecialSubstitution>(<wbr>SpecialSubKind::basic_string))<wbr>;<br>
first += 2;<br>
break;<br>
case 's':<br>
- db.names.push_back("std::<wbr>string");<br>
+ db.names.push_back(<br>
+ db.make<SpecialSubstitution>(<br>
+ SpecialSubKind::string));<br>
first += 2;<br>
break;<br>
case 'i':<br>
- db.names.push_back("std::<wbr>istream");<br>
+ db.names.push_back(db.make<<wbr>SpecialSubstitution>(<wbr>SpecialSubKind::istream));<br>
first += 2;<br>
break;<br>
case 'o':<br>
- db.names.push_back("std::<wbr>ostream");<br>
+ db.names.push_back(db.make<<wbr>SpecialSubstitution>(<wbr>SpecialSubKind::ostream));<br>
first += 2;<br>
break;<br>
case 'd':<br>
- db.names.push_back("std::<wbr>iostream");<br>
+ db.names.push_back(db.make<<wbr>SpecialSubstitution>(<wbr>SpecialSubKind::iostream));<br>
first += 2;<br>
break;<br>
case '_':<br>
@@ -578,87 +1877,87 @@ parse_builtin_type(const char* first, co<br>
switch (*first)<br>
{<br>
case 'v':<br>
- db.names.push_back("void");<br>
+ db.names.push_back(db.make<<wbr>NameType>("void"));<br>
++first;<br>
break;<br>
case 'w':<br>
- db.names.push_back("wchar_t");<br>
+ db.names.push_back(db.make<<wbr>NameType>("wchar_t"));<br>
++first;<br>
break;<br>
case 'b':<br>
- db.names.push_back("bool");<br>
+ db.names.push_back(db.make<<wbr>NameType>("bool"));<br>
++first;<br>
break;<br>
case 'c':<br>
- db.names.push_back("char");<br>
+ db.names.push_back(db.make<<wbr>NameType>("char"));<br>
++first;<br>
break;<br>
case 'a':<br>
- db.names.push_back("signed char");<br>
+ db.names.push_back(db.make<<wbr>NameType>("signed char"));<br>
++first;<br>
break;<br>
case 'h':<br>
- db.names.push_back("unsigned char");<br>
+ db.names.push_back(db.make<<wbr>NameType>("unsigned char"));<br>
++first;<br>
break;<br>
case 's':<br>
- db.names.push_back("short");<br>
+ db.names.push_back(db.make<<wbr>NameType>("short"));<br>
++first;<br>
break;<br>
case 't':<br>
- db.names.push_back("unsigned short");<br>
+ db.names.push_back(db.make<<wbr>NameType>("unsigned short"));<br>
++first;<br>
break;<br>
case 'i':<br>
- db.names.push_back("int");<br>
+ db.names.push_back(db.make<<wbr>NameType>("int"));<br>
++first;<br>
break;<br>
case 'j':<br>
- db.names.push_back("unsigned int");<br>
+ db.names.push_back(db.make<<wbr>NameType>("unsigned int"));<br>
++first;<br>
break;<br>
case 'l':<br>
- db.names.push_back("long");<br>
+ db.names.push_back(db.make<<wbr>NameType>("long"));<br>
++first;<br>
break;<br>
case 'm':<br>
- db.names.push_back("unsigned long");<br>
+ db.names.push_back(db.make<<wbr>NameType>("unsigned long"));<br>
++first;<br>
break;<br>
case 'x':<br>
- db.names.push_back("long long");<br>
+ db.names.push_back(db.make<<wbr>NameType>("long long"));<br>
++first;<br>
break;<br>
case 'y':<br>
- db.names.push_back("unsigned long long");<br>
+ db.names.push_back(db.make<<wbr>NameType>("unsigned long long"));<br>
++first;<br>
break;<br>
case 'n':<br>
- db.names.push_back("__int128")<wbr>;<br>
+ db.names.push_back(db.make<<wbr>NameType>("__int128"));<br>
++first;<br>
break;<br>
case 'o':<br>
- db.names.push_back("unsigned __int128");<br>
+ db.names.push_back(db.make<<wbr>NameType>("unsigned __int128"));<br>
++first;<br>
break;<br>
case 'f':<br>
- db.names.push_back("float");<br>
+ db.names.push_back(db.make<<wbr>NameType>("float"));<br>
++first;<br>
break;<br>
case 'd':<br>
- db.names.push_back("double");<br>
+ db.names.push_back(db.make<<wbr>NameType>("double"));<br>
++first;<br>
break;<br>
case 'e':<br>
- db.names.push_back("long double");<br>
+ db.names.push_back(db.make<<wbr>NameType>("long double"));<br>
++first;<br>
break;<br>
case 'g':<br>
- db.names.push_back("__<wbr>float128");<br>
+ db.names.push_back(db.make<<wbr>NameType>("__float128"));<br>
++first;<br>
break;<br>
case 'z':<br>
- db.names.push_back("...");<br>
+ db.names.push_back(db.make<<wbr>NameType>("..."));<br>
++first;<br>
break;<br>
case 'u':<br>
@@ -674,39 +1973,39 @@ parse_builtin_type(const char* first, co<br>
switch (first[1])<br>
{<br>
case 'd':<br>
- db.names.push_back("decimal64"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("decimal64"));<br>
first += 2;<br>
break;<br>
case 'e':<br>
- db.names.push_back("<wbr>decimal128");<br>
+ db.names.push_back(db.make<<wbr>NameType>("decimal128"));<br>
first += 2;<br>
break;<br>
case 'f':<br>
- db.names.push_back("decimal32"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("decimal32"));<br>
first += 2;<br>
break;<br>
case 'h':<br>
- db.names.push_back("decimal16"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("decimal16"));<br>
first += 2;<br>
break;<br>
case 'i':<br>
- db.names.push_back("char32_t")<wbr>;<br>
+ db.names.push_back(db.make<<wbr>NameType>("char32_t"));<br>
first += 2;<br>
break;<br>
case 's':<br>
- db.names.push_back("char16_t")<wbr>;<br>
+ db.names.push_back(db.make<<wbr>NameType>("char16_t"));<br>
first += 2;<br>
break;<br>
case 'a':<br>
- db.names.push_back("auto");<br>
+ db.names.push_back(db.make<<wbr>NameType>("auto"));<br>
first += 2;<br>
break;<br>
case 'c':<br>
- db.names.push_back("decltype(<wbr>auto)");<br>
+ db.names.push_back(db.make<<wbr>NameType>("decltype(auto)"));<br>
first += 2;<br>
break;<br>
case 'n':<br>
- db.names.push_back("std::<wbr>nullptr_t");<br>
+ db.names.push_back(db.make<<wbr>NameType>("std::nullptr_t"));<br>
first += 2;<br>
break;<br>
}<br>
@@ -717,27 +2016,27 @@ parse_builtin_type(const char* first, co<br>
return first;<br>
}<br>
<br>
-// <CV-qualifiers> ::= [r] [V] [K]<br>
+// <CV-Qualifiers> ::= [r] [V] [K]<br>
<br>
const char*<br>
-parse_cv_qualifiers(const char* first, const char* last, unsigned& cv)<br>
+parse_cv_qualifiers(const char* first, const char* last, Qualifiers& cv)<br>
{<br>
- cv = 0;<br>
+ cv = QualNone;<br>
if (first != last)<br>
{<br>
if (*first == 'r')<br>
{<br>
- cv |= 4;<br>
+ addQualifiers(cv, QualRestrict);<br>
++first;<br>
}<br>
if (*first == 'V')<br>
{<br>
- cv |= 2;<br>
+ addQualifiers(cv, QualVolatile);<br>
++first;<br>
}<br>
if (*first == 'K')<br>
{<br>
- cv |= 1;<br>
+ addQualifiers(cv, QualConst);<br>
++first;<br>
}<br>
}<br>
@@ -766,7 +2065,7 @@ parse_template_param(const char* first,<br>
}<br>
else<br>
{<br>
- db.names.push_back("T_");<br>
+ db.names.push_back(db.make<<wbr>NameType>("T_"));<br>
first += 2;<br>
db.fix_forward_references = true;<br>
}<br>
@@ -791,7 +2090,8 @@ parse_template_param(const char* first,<br>
}<br>
else<br>
{<br>
- db.names.push_back(Db::String(<wbr>first, t+1));<br>
+ db.names.push_back(<br>
+ db.make<NameType>(StringView(<wbr>first, t + 1)));<br>
first = t+1;<br>
db.fix_forward_references = true;<br>
}<br>
@@ -816,11 +2116,12 @@ parse_const_cast_expr(const char* first,<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto expr = db.names.back().move_full();<br>
+ auto from_expr = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";<br>
+ db.names.back() = db.make<CastExpr>(<br>
+ "const_cast", db.names.back(), from_expr);<br>
first = t1;<br>
}<br>
}<br>
@@ -843,11 +2144,12 @@ parse_dynamic_cast_expr(const char* firs<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto expr = db.names.back().move_full();<br>
+ auto from_expr = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";<br>
+ db.names.back() = db.make<CastExpr>(<br>
+ "dynamic_cast", db.names.back(), from_expr);<br>
first = t1;<br>
}<br>
}<br>
@@ -870,11 +2172,12 @@ parse_reinterpret_cast_expr(<wbr>const char*<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto expr = db.names.back().move_full();<br>
+ auto from_expr = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";<br>
+ db.names.back() = db.make<CastExpr>(<br>
+ "reinterpret_cast", db.names.back(), from_expr);<br>
first = t1;<br>
}<br>
}<br>
@@ -897,9 +2200,10 @@ parse_static_cast_expr(const char* first<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto expr = db.names.back().move_full();<br>
+ auto from_expr = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";<br>
+ db.names.back() = db.make<CastExpr>(<br>
+ "static_cast", db.names.back(), from_expr);<br>
first = t1;<br>
}<br>
}<br>
@@ -933,7 +2237,8 @@ parse_sizeof_type_expr(const char* first<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "sizeof (" + db.names.back().move_full() + ")";<br>
+ db.names.back() = db.make<EnclosingExpr>(<br>
+ "sizeof (", db.names.back(), ")");<br>
first = t;<br>
}<br>
}<br>
@@ -952,7 +2257,8 @@ parse_sizeof_expr_expr(const char* first<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "sizeof (" + db.names.back().move_full() + ")";<br>
+ db.names.back() = db.make<EnclosingExpr>(<br>
+ "sizeof (", db.names.back(), ")");<br>
first = t;<br>
}<br>
}<br>
@@ -969,30 +2275,21 @@ parse_sizeof_param_pack_expr(<wbr>const char*<br>
size_t k0 = db.names.size();<br>
const char* t = parse_template_param(first+2, last, db);<br>
size_t k1 = db.names.size();<br>
- if (t != first+2)<br>
+ if (t != first+2 && k0 <= k1)<br>
{<br>
- Db::String tmp("sizeof...(");<br>
- size_t k = k0;<br>
- if (k != k1)<br>
- {<br>
- tmp += db.names[k].move_full();<br>
- for (++k; k != k1; ++k)<br>
- tmp += ", " + db.names[k].move_full();<br>
- }<br>
- tmp += ")";<br>
- for (; k1 != k0; --k1)<br>
- db.names.pop_back();<br>
- db.names.push_back(std::move(<wbr>tmp));<br>
+ Node* sizeof_expr = db.make<SizeofParamPackExpr>(<br>
+ db.popTrailingNodeArray(k0));<br>
+ db.names.push_back(sizeof_<wbr>expr);<br>
first = t;<br>
}<br>
}<br>
return first;<br>
}<br>
<br>
-// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter<br>
-// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters<br>
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter<br>
-// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters<br>
+// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter<br>
+// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters<br>
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter<br>
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters<br>
<br>
const char*<br>
parse_function_param(const char* first, const char* last, Db& db)<br>
@@ -1001,18 +2298,19 @@ parse_function_param(const char* first,<br>
{<br>
if (first[1] == 'p')<br>
{<br>
- unsigned cv;<br>
+ Qualifiers cv;<br>
const char* t = parse_cv_qualifiers(first+2, last, cv);<br>
const char* t1 = parse_number(t, last);<br>
if (t1 != last && *t1 == '_')<br>
{<br>
- db.names.push_back("fp" + Db::String(t, t1));<br>
+ db.names.push_back(<br>
+ db.make<FunctionParam>(<wbr>StringView(t, t1)));<br>
first = t1+1;<br>
}<br>
}<br>
else if (first[1] == 'L')<br>
{<br>
- unsigned cv;<br>
+ Qualifiers cv;<br>
const char* t0 = parse_number(first+2, last);<br>
if (t0 != last && *t0 == 'p')<br>
{<br>
@@ -1021,7 +2319,8 @@ parse_function_param(const char* first,<br>
const char* t1 = parse_number(t, last);<br>
if (t1 != last && *t1 == '_')<br>
{<br>
- db.names.push_back("fp" + Db::String(t, t1));<br>
+ db.names.push_back(<br>
+ db.make<FunctionParam>(<wbr>StringView(t, t1)));<br>
first = t1+1;<br>
}<br>
}<br>
@@ -1042,7 +2341,8 @@ parse_sizeof_function_param_<wbr>pack_expr(co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";<br>
+ db.names.back() = db.make<EnclosingExpr>(<br>
+ "sizeof...(", db.names.back(), ")");<br>
first = t;<br>
}<br>
}<br>
@@ -1066,7 +2366,8 @@ parse_typeid_expr(const char* first, con<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "typeid(" + db.names.back().move_full() + ")";<br>
+ db.names.back() = db.make<EnclosingExpr>(<br>
+ "typeid(", db.names.back(), ")");<br>
first = t;<br>
}<br>
}<br>
@@ -1085,7 +2386,7 @@ parse_throw_expr(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "throw " + db.names.back().move_full();<br>
+ db.names.back() = db.make<ThrowExpr>(db.names.<wbr>back());<br>
first = t;<br>
}<br>
}<br>
@@ -1107,9 +2408,10 @@ parse_dot_star_expr(const char* first, c<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto expr = db.names.back().move_full();<br>
+ auto rhs_expr = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += ".*" + expr;<br>
+ db.names.back() = db.make<MemberExpr>(<br>
+ db.names.back(), ".*", rhs_expr);<br>
first = t1;<br>
}<br>
}<br>
@@ -1132,9 +2434,10 @@ parse_simple_id(const char* first, const<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto args = db.names.back().move_full();<br>
+ auto args = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += std::move(args);<br>
+ db.names.back() =<br>
+ db.make<NameWithTemplateArgs>(<wbr>db.names.back(), args);<br>
}<br>
first = t1;<br>
}<br>
@@ -1196,7 +2499,8 @@ parse_unresolved_type(const char* first,<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "std::");<br>
+ db.names.back() =<br>
+ db.make<StdQualifiedName>(db.<wbr>names.back());<br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
first = t;<br>
}<br>
@@ -1223,7 +2527,7 @@ parse_destructor_name(const char* first,<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "~");<br>
+ db.names.back() = db.make<DtorName>(db.names.<wbr>back());<br>
first = t;<br>
}<br>
}<br>
@@ -1255,9 +2559,11 @@ parse_base_unresolved_name(<wbr>const char* f<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto args = db.names.back().move_full();<br>
+ auto args = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += std::move(args);<br>
+ db.names.back() =<br>
+ db.make<NameWithTemplateArgs>(<br>
+ db.names.back(), args);<br>
}<br>
}<br>
}<br>
@@ -1281,9 +2587,11 @@ parse_base_unresolved_name(<wbr>const char* f<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto args = db.names.back().move_full();<br>
+ auto args = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += std::move(args);<br>
+ db.names.back() =<br>
+ db.make<NameWithTemplateArgs>(<br>
+ db.names.back(), args);<br>
}<br>
}<br>
}<br>
@@ -1331,7 +2639,8 @@ parse_unresolved_name(const char* first,<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "::");<br>
+ db.names.back() =<br>
+ db.make<GlobalQualifiedName>(<wbr>db.names.back());<br>
}<br>
first = t2;<br>
}<br>
@@ -1349,9 +2658,10 @@ parse_unresolved_name(const char* first,<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto args = db.names.back().move_full();<br>
+ auto args = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += std::move(args);<br>
+ db.names.back() = db.make<NameWithTemplateArgs>(<br>
+ db.names.back(), args);<br>
t = t1;<br>
if (t == last)<br>
{<br>
@@ -1364,9 +2674,10 @@ parse_unresolved_name(const char* first,<br>
t1 = parse_unresolved_qualifier_<wbr>level(t, last, db);<br>
if (t1 == t || t1 == last || db.names.size() < 2)<br>
return first;<br>
- auto s = db.names.back().move_full();<br>
+ auto s = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += "::" + std::move(s);<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), s);<br>
t = t1;<br>
}<br>
++t;<br>
@@ -1379,9 +2690,10 @@ parse_unresolved_name(const char* first,<br>
}<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto s = db.names.back().move_full();<br>
+ auto s = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += "::" + std::move(s);<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), s);<br>
first = t1;<br>
}<br>
else<br>
@@ -1396,9 +2708,11 @@ parse_unresolved_name(const char* first,<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto args = db.names.back().move_full();<br>
+ auto args = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += std::move(args);<br>
+ db.names.back() =<br>
+ db.make<NameWithTemplateArgs>(<br>
+ db.names.back(), args);<br>
t = t1;<br>
}<br>
t1 = parse_base_unresolved_name(t, last, db);<br>
@@ -1410,9 +2724,10 @@ parse_unresolved_name(const char* first,<br>
}<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto s = db.names.back().move_full();<br>
+ auto s = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += "::" + std::move(s);<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), s);<br>
first = t1;<br>
}<br>
else<br>
@@ -1425,16 +2740,19 @@ parse_unresolved_name(const char* first,<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "::");<br>
+ db.names.back() =<br>
+ db.make<GlobalQualifiedName>(<br>
+ db.names.back());<br>
}<br>
while (*t != 'E')<br>
{<br>
t1 = parse_unresolved_qualifier_<wbr>level(t, last, db);<br>
if (t1 == t || t1 == last || db.names.size() < 2)<br>
return first;<br>
- auto s = db.names.back().move_full();<br>
+ auto s = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += "::" + std::move(s);<br>
+ db.names.back() = db.make<QualifiedName>(<br>
+ db.names.back(), s);<br>
t = t1;<br>
}<br>
++t;<br>
@@ -1447,9 +2765,10 @@ parse_unresolved_name(const char* first,<br>
}<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto s = db.names.back().move_full();<br>
+ auto s = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += "::" + std::move(s);<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), s);<br>
first = t1;<br>
}<br>
}<br>
@@ -1473,11 +2792,11 @@ parse_dot_expr(const char* first, const<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first += "." + name;<br>
+ db.names.back() = db.make<MemberExpr>(db.names.<wbr>back(), ".", name);<br>
first = t1;<br>
}<br>
}<br>
@@ -1493,44 +2812,25 @@ parse_call_expr(const char* first, const<br>
if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')<br>
{<br>
const char* t = parse_expression(first+2, last, db);<br>
- if (t != first+2)<br>
+ if (t == last || t == first + 2 || db.names.empty())<br>
+ return first;<br>
+ Node* callee = db.names.back();<br>
+ db.names.pop_back();<br>
+ size_t args_begin = db.names.size();<br>
+ while (*t != 'E')<br>
{<br>
- if (t == last)<br>
- return first;<br>
- if (db.names.empty())<br>
- return first;<br>
- db.names.back().first += db.names.back().second;<br>
- db.names.back().second = Db::String();<br>
- db.names.back().first.append("<wbr>(");<br>
- bool first_expr = true;<br>
- while (*t != 'E')<br>
- {<br>
- const char* t1 = parse_expression(t, last, db);<br>
- if (t1 == t || t1 == last)<br>
- return first;<br>
- if (db.names.empty())<br>
- return first;<br>
- auto tmp = db.names.back().move_full();<br>
- db.names.pop_back();<br>
- if (!tmp.empty())<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- if (!first_expr)<br>
- {<br>
- db.names.back().first.append("<wbr>, ");<br>
- first_expr = false;<br>
- }<br>
- db.names.back().first.append(<wbr>tmp);<br>
- }<br>
- t = t1;<br>
- }<br>
- ++t;<br>
- if (db.names.empty())<br>
+ const char* t1 = parse_expression(t, last, db);<br>
+ if (t1 == last || t1 == t)<br>
return first;<br>
- db.names.back().first.append("<wbr>)");<br>
- first = t;<br>
+ t = t1;<br>
}<br>
+ if (db.names.size() < args_begin)<br>
+ return first;<br>
+ ++t;<br>
+ CallExpr* the_call = db.make<CallExpr>(<br>
+ callee, db.popTrailingNodeArray(args_<wbr>begin));<br>
+ db.names.push_back(the_call);<br>
+ first = t;<br>
}<br>
return first;<br>
}<br>
@@ -1559,31 +2859,18 @@ parse_new_expr(const char* first, const<br>
t += 2;<br>
if (t == last)<br>
return first;<br>
- bool has_expr_list = false;<br>
- bool first_expr = true;<br>
+ size_t first_expr_in_list = db.names.size();<br>
+ NodeArray ExprList, init_list;<br>
while (*t != '_')<br>
{<br>
const char* t1 = parse_expression(t, last, db);<br>
if (t1 == t || t1 == last)<br>
return first;<br>
- has_expr_list = true;<br>
- if (!first_expr)<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- auto tmp = db.names.back().move_full();<br>
- db.names.pop_back();<br>
- if (!tmp.empty())<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- db.names.back().first.append("<wbr>, ");<br>
- db.names.back().first.append(<wbr>tmp);<br>
- first_expr = false;<br>
- }<br>
- }<br>
t = t1;<br>
}<br>
+ if (first_expr_in_list < db.names.size())<br>
+ return first;<br>
+ ExprList = db.popTrailingNodeArray(first_<wbr>expr_in_list);<br>
++t;<br>
const char* t1 = parse_type(t, last, db);<br>
if (t1 == t || t1 == last)<br>
@@ -1594,65 +2881,25 @@ parse_new_expr(const char* first, const<br>
{<br>
t += 2;<br>
has_init = true;<br>
- first_expr = true;<br>
+ size_t init_list_begin = db.names.size();<br>
while (*t != 'E')<br>
{<br>
t1 = parse_expression(t, last, db);<br>
if (t1 == t || t1 == last)<br>
return first;<br>
- if (!first_expr)<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- auto tmp = db.names.back().move_full();<br>
- db.names.pop_back();<br>
- if (!tmp.empty())<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- db.names.back().first.append("<wbr>, ");<br>
- db.names.back().first.append(<wbr>tmp);<br>
- first_expr = false;<br>
- }<br>
- }<br>
t = t1;<br>
}<br>
- }<br>
- if (*t != 'E')<br>
- return first;<br>
- Db::String init_list;<br>
- if (has_init)<br>
- {<br>
- if (db.names.empty())<br>
+ if (init_list_begin < db.names.size())<br>
return first;<br>
- init_list = db.names.back().move_full();<br>
- db.names.pop_back();<br>
+ init_list = db.popTrailingNodeArray(init_<wbr>list_begin);<br>
}<br>
- if (db.names.empty())<br>
+ if (*t != 'E')<br>
return first;<br>
- auto type = db.names.back().move_full();<br>
+ auto type = db.names.back();<br>
db.names.pop_back();<br>
- Db::String expr_list;<br>
- if (has_expr_list)<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- expr_list = db.names.back().move_full();<br>
- db.names.pop_back();<br>
- }<br>
- Db::String r;<br>
- if (parsed_gs)<br>
- r = "::";<br>
- if (is_array)<br>
- r += "[] ";<br>
- else<br>
- r += " ";<br>
- if (has_expr_list)<br>
- r += "(" + expr_list + ") ";<br>
- r += type;<br>
- if (has_init)<br>
- r += " (" + init_list + ")";<br>
- db.names.push_back(std::move(<wbr>r));<br>
+ db.names.push_back(<br>
+ db.make<NewExpr>(ExprList, type, init_list,<br>
+ parsed_gs, is_array));<br>
first = t+1;<br>
}<br>
}<br>
@@ -1669,10 +2916,12 @@ parse_conversion_expr(const char* first,<br>
{<br>
bool try_to_parse_template_args = db.try_to_parse_template_args;<br>
db.try_to_parse_template_args = false;<br>
+ size_t type_begin = db.names.size();<br>
const char* t = parse_type(first+2, last, db);<br>
db.try_to_parse_template_args = try_to_parse_template_args;<br>
if (t != first+2 && t != last)<br>
{<br>
+ size_t ExprList_begin = db.names.size();<br>
if (*t != '_')<br>
{<br>
const char* t1 = parse_expression(t, last, db);<br>
@@ -1685,41 +2934,30 @@ parse_conversion_expr(const char* first,<br>
++t;<br>
if (t == last)<br>
return first;<br>
- if (*t == 'E')<br>
- db.names.emplace_back();<br>
- else<br>
+ if (*t != 'E')<br>
{<br>
- bool first_expr = true;<br>
while (*t != 'E')<br>
{<br>
const char* t1 = parse_expression(t, last, db);<br>
if (t1 == t || t1 == last)<br>
return first;<br>
- if (!first_expr)<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- auto tmp = db.names.back().move_full();<br>
- db.names.pop_back();<br>
- if (!tmp.empty())<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- db.names.back().first.append("<wbr>, ");<br>
- db.names.back().first.append(<wbr>tmp);<br>
- first_expr = false;<br>
- }<br>
- }<br>
t = t1;<br>
}<br>
}<br>
++t;<br>
}<br>
- if (db.names.size() < 2)<br>
+ if (db.names.size() < ExprList_begin)<br>
return first;<br>
- auto tmp = db.names.back().move_full();<br>
- db.names.pop_back();<br>
- db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";<br>
+ NodeArray expressions = db.makeNodeArray(<br>
+ db.names.begin() + (long)ExprList_begin, db.names.end());<br>
+ NodeArray types = db.makeNodeArray(<br>
+ db.names.begin() + (long)type_begin,<br>
+ db.names.begin() + (long)ExprList_begin);<br>
+ auto* conv_expr = db.make<ConversionExpr>(<br>
+ types, expressions);<br>
+ db.names.erase(<br>
+ db.names.begin() + (long)type_begin, db.names.end());<br>
+ db.names.push_back(conv_expr);<br>
first = t;<br>
}<br>
}<br>
@@ -1741,10 +2979,10 @@ parse_arrow_expr(const char* first, cons<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto tmp = db.names.back().move_full();<br>
+ auto tmp = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += "->";<br>
- db.names.back().first += tmp;<br>
+ db.names.back() = db.make<MemberExpr>(<br>
+ db.names.back(), "->", tmp);<br>
first = t1;<br>
}<br>
}<br>
@@ -1772,11 +3010,13 @@ parse_function_type(const char* first, c<br>
return first;<br>
}<br>
const char* t1 = parse_type(t, last, db);<br>
- if (t1 != t)<br>
+ if (t1 != t && !db.names.empty())<br>
{<br>
+ Node* ret_type = db.names.back();<br>
+ db.names.pop_back();<br>
+ size_t params_begin = db.names.size();<br>
t = t1;<br>
- Db::String sig("(");<br>
- int ref_qual = 0;<br>
+ FunctionRefQual RefQuals = FrefQualNone;<br>
while (true)<br>
{<br>
if (t == last)<br>
@@ -1797,45 +3037,30 @@ parse_function_type(const char* first, c<br>
}<br>
if (*t == 'R' && t+1 != last && t[1] == 'E')<br>
{<br>
- ref_qual = 1;<br>
+ RefQuals = FrefQualLValue;<br>
++t;<br>
continue;<br>
}<br>
if (*t == 'O' && t+1 != last && t[1] == 'E')<br>
{<br>
- ref_qual = 2;<br>
+ RefQuals = FrefQualRValue;<br>
++t;<br>
continue;<br>
}<br>
size_t k0 = db.names.size();<br>
t1 = parse_type(t, last, db);<br>
size_t k1 = db.names.size();<br>
- if (t1 == t || t1 == last)<br>
+ if (t1 == t || t1 == last || k1 < k0)<br>
return first;<br>
- for (size_t k = k0; k < k1; ++k)<br>
- {<br>
- if (sig.size() > 1)<br>
- sig += ", ";<br>
- sig += db.names[k].move_full();<br>
- }<br>
- for (size_t k = k0; k < k1; ++k)<br>
- db.names.pop_back();<br>
t = t1;<br>
}<br>
- sig += ")";<br>
- switch (ref_qual)<br>
- {<br>
- case 1:<br>
- sig += " &";<br>
- break;<br>
- case 2:<br>
- sig += " &&";<br>
- break;<br>
- }<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first += " ";<br>
- db.names.back().second.insert(<wbr>0, sig);<br>
+ Node* fty = db.make<FunctionType>(<br>
+ ret_type, db.popTrailingNodeArray(<wbr>params_begin));<br>
+ if (RefQuals)<br>
+ fty = db.make<FunctionRefQualType>(<wbr>fty, RefQuals);<br>
+ db.names.push_back(fty);<br>
first = t;<br>
}<br>
}<br>
@@ -1860,17 +3085,9 @@ parse_pointer_to_member_type(<wbr>const char*<br>
return first;<br>
auto func = std::move(db.names.back());<br>
db.names.pop_back();<br>
- auto class_type = std::move(db.names.back());<br>
- if (!func.second.empty() && func.second.front() == '(')<br>
- {<br>
- db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*";<br>
- db.names.back().second = ")" + std::move(func.second);<br>
- }<br>
- else<br>
- {<br>
- db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*";<br>
- db.names.back().second = std::move(func.second);<br>
- }<br>
+ auto ClassType = std::move(db.names.back());<br>
+ db.names.back() =<br>
+ db.make<PointerToMemberType>(<wbr>ClassType, func);<br>
first = t2;<br>
}<br>
}<br>
@@ -1893,9 +3110,7 @@ parse_array_type(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- if (db.names.back().second.<wbr>substr(0, 2) == " [")<br>
- db.names.back().second.erase(<wbr>0, 1);<br>
- db.names.back().second.insert(<wbr>0, " []");<br>
+ db.names.back() = db.make<ArrayType>(db.names.<wbr>back());<br>
first = t;<br>
}<br>
}<br>
@@ -1909,9 +3124,9 @@ parse_array_type(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- if (db.names.back().second.<wbr>substr(0, 2) == " [")<br>
- db.names.back().second.erase(<wbr>0, 1);<br>
- db.names.back().second.insert(<wbr>0, " [" + Db::String(first+1, t) + "]");<br>
+ db.names.back() =<br>
+ db.make<ArrayType>(db.names.<wbr>back(),<br>
+ StringView(first + 1, t));<br>
first = t2;<br>
}<br>
}<br>
@@ -1926,13 +3141,11 @@ parse_array_type(const char* first, cons<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto type = std::move(db.names.back());<br>
+ auto base_type = std::move(db.names.back());<br>
db.names.pop_back();<br>
- auto expr = std::move(db.names.back());<br>
- db.names.back().first = std::move(type.first);<br>
- if (type.second.substr(0, 2) == " [")<br>
- type.second.erase(0, 1);<br>
- db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second);<br>
+ auto dimension_expr = std::move(db.names.back());<br>
+ db.names.back() =<br>
+ db.make<ArrayType>(base_type, dimension_expr);<br>
first = t2;<br>
}<br>
}<br>
@@ -1959,7 +3172,8 @@ parse_decltype(const char* first, const<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "decltype(" + db.names.back().move_full() + ")";<br>
+ db.names.back() = db.make<EnclosingExpr>(<br>
+ "decltype(", db.names.back(), ")");<br>
first = t+1;<br>
}<br>
}<br>
@@ -1997,21 +3211,24 @@ parse_vector_type(const char* first, con<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first += " vector[" + Db::String(num, sz) + "]";<br>
+ db.names.back() =<br>
+ db.make<VectorType>(db.names.<wbr>back(),<br>
+ StringView(num, num + sz));<br>
first = t1;<br>
}<br>
}<br>
else<br>
{<br>
++t;<br>
- db.names.push_back("pixel vector[" + Db::String(num, sz) + "]");<br>
+ db.names.push_back(<br>
+ db.make<VectorType>(<wbr>StringView(num, num + sz)));<br>
first = t;<br>
}<br>
}<br>
}<br>
else<br>
{<br>
- Db::String num;<br>
+ Node* num = nullptr;<br>
const char* t1 = first+2;<br>
if (*t1 != '_')<br>
{<br>
@@ -2020,7 +3237,7 @@ parse_vector_type(const char* first, con<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- num = db.names.back().move_full();<br>
+ num = db.names.back();<br>
db.names.pop_back();<br>
t1 = t;<br>
}<br>
@@ -2032,9 +3249,15 @@ parse_vector_type(const char* first, con<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first += " vector[" + num + "]";<br>
+ if (num)<br>
+ db.names.back() =<br>
+ db.make<VectorType>(db.names.<wbr>back(), num);<br>
+ else<br>
+ db.names.back() =<br>
+ db.make<VectorType>(db.names.<wbr>back(), StringView());<br>
first = t;<br>
- }<br>
+ } else if (num)<br>
+ db.names.push_back(num);<br>
}<br>
}<br>
}<br>
@@ -2050,7 +3273,7 @@ parse_vector_type(const char* first, con<br>
// ::= <template-template-param> <template-args><br>
// ::= <decltype><br>
// ::= <substitution><br>
-// ::= <CV-qualifiers> <type><br>
+// ::= <CV-Qualifiers> <type><br>
// ::= P <type> # pointer-to<br>
// ::= R <type> # reference-to<br>
// ::= O <type> # rvalue reference-to (C++0x)<br>
@@ -2075,7 +3298,7 @@ parse_type(const char* first, const char<br>
case 'V':<br>
case 'K':<br>
{<br>
- unsigned cv = 0;<br>
+ Qualifiers cv = QualNone;<br>
const char* t = parse_cv_qualifiers(first, last, cv);<br>
if (t != first)<br>
{<br>
@@ -2090,35 +3313,13 @@ parse_type(const char* first, const char<br>
db.subs.emplace_back(db.names.<wbr>get_allocator());<br>
for (size_t k = k0; k < k1; ++k)<br>
{<br>
- if (is_function)<br>
- {<br>
- size_t p = db.names[k].second.size();<br>
- if (db.names[k].second[p - 2] == '&' &&<br>
- db.names[k].second[p - 1] == '&')<br>
- p -= 2;<br>
- else if (db.names[k].second.back() == '&')<br>
- p -= 1;<br>
- if (cv & 1)<br>
- {<br>
- db.names[k].second.insert(p, " const");<br>
- p += 6;<br>
- }<br>
- if (cv & 2)<br>
- {<br>
- db.names[k].second.insert(p, " volatile");<br>
- p += 9;<br>
- }<br>
- if (cv & 4)<br>
- db.names[k].second.insert(p, " restrict");<br>
- }<br>
- else<br>
- {<br>
- if (cv & 1)<br>
- db.names[k].first.append(" const");<br>
- if (cv & 2)<br>
- db.names[k].first.append(" volatile");<br>
- if (cv & 4)<br>
- db.names[k].first.append(" restrict");<br>
+ if (cv) {<br>
+ if (is_function)<br>
+ db.names[k] = db.make<FunctionQualType>(<br>
+ db.names[k], cv);<br>
+ else<br>
+ db.names[k] =<br>
+ db.make<QualType>(db.names[k], cv);<br>
}<br>
db.subs.back().push_back(db.<wbr>names[k]);<br>
}<br>
@@ -2154,7 +3355,8 @@ parse_type(const char* first, const char<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.append(" complex");<br>
+ db.names.back() = db.make<PostfixQualifiedType>(<br>
+ db.names.back(), " complex");<br>
first = t;<br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
}<br>
@@ -2175,7 +3377,8 @@ parse_type(const char* first, const char<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.append(" imaginary");<br>
+ db.names.back() = db.make<PostfixQualifiedType>(<br>
+ db.names.back(), " imaginary");<br>
first = t;<br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
}<br>
@@ -2200,18 +3403,8 @@ parse_type(const char* first, const char<br>
db.subs.emplace_back(db.names.<wbr>get_allocator());<br>
for (size_t k = k0; k < k1; ++k)<br>
{<br>
- if (db.names[k].second.substr(0, 2) == " [")<br>
- {<br>
- db.names[k].first += " (";<br>
- db.names[k].second.insert(0, ")");<br>
- }<br>
- else if (!db.names[k].second.empty() &&<br>
- db.names[k].second.front() == '(')<br>
- {<br>
- db.names[k].first += "(";<br>
- db.names[k].second.insert(0, ")");<br>
- }<br>
- db.names[k].first.append("&&")<wbr>;<br>
+ db.names[k] =<br>
+ db.make<RValueReferenceType>(<wbr>db.names[k]);<br>
db.subs.back().push_back(db.<wbr>names[k]);<br>
}<br>
first = t;<br>
@@ -2228,25 +3421,7 @@ parse_type(const char* first, const char<br>
db.subs.emplace_back(db.names.<wbr>get_allocator());<br>
for (size_t k = k0; k < k1; ++k)<br>
{<br>
- if (db.names[k].second.substr(0, 2) == " [")<br>
- {<br>
- db.names[k].first += " (";<br>
- db.names[k].second.insert(0, ")");<br>
- }<br>
- else if (!db.names[k].second.empty() &&<br>
- db.names[k].second.front() == '(')<br>
- {<br>
- db.names[k].first += "(";<br>
- db.names[k].second.insert(0, ")");<br>
- }<br>
- if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<")<br>
- {<br>
- db.names[k].first.append("*");<br>
- }<br>
- else<br>
- {<br>
- db.names[k].first.replace(0, 11, "id");<br>
- }<br>
+ db.names[k] = db.make<PointerType>(db.names[<wbr>k]);<br>
db.subs.back().push_back(db.<wbr>names[k]);<br>
}<br>
first = t;<br>
@@ -2263,18 +3438,8 @@ parse_type(const char* first, const char<br>
db.subs.emplace_back(db.names.<wbr>get_allocator());<br>
for (size_t k = k0; k < k1; ++k)<br>
{<br>
- if (db.names[k].second.substr(0, 2) == " [")<br>
- {<br>
- db.names[k].first += " (";<br>
- db.names[k].second.insert(0, ")");<br>
- }<br>
- else if (!db.names[k].second.empty() &&<br>
- db.names[k].second.front() == '(')<br>
- {<br>
- db.names[k].first += "(";<br>
- db.names[k].second.insert(0, ")");<br>
- }<br>
- db.names[k].first.append("&");<br>
+ db.names[k] =<br>
+ db.make<LValueReferenceType>(<wbr>db.names[k]);<br>
db.subs.back().push_back(db.<wbr>names[k]);<br>
}<br>
first = t;<br>
@@ -2296,10 +3461,14 @@ parse_type(const char* first, const char<br>
const char* t1 = parse_template_args(t, last, db);<br>
if (t1 != t)<br>
{<br>
- auto args = db.names.back().move_full();<br>
+ auto args = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += std::move(args);<br>
- db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
+ db.names.back() = db.make<<br>
+ NameWithTemplateArgs>(<br>
+ db.names.back(), args);<br>
+ db.subs.push_back(Db::sub_<wbr>type(<br>
+ 1, db.names.back(),<br>
+ db.names.get_allocator()));<br>
t = t1;<br>
}<br>
}<br>
@@ -2318,24 +3487,25 @@ parse_type(const char* first, const char<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto type = db.names.back().move_full();<br>
+ auto type = db.names.back();<br>
db.names.pop_back();<br>
- if (db.names.back().first.substr(<wbr>0, 9) != "objcproto")<br>
+ if (db.names.back()->K != Node::KNameType ||<br>
+ !static_cast<NameType*>(db.<wbr>names.back())->getName().<wbr>startsWith("objcproto"))<br>
{<br>
- db.names.back() = type + " " + db.names.back().move_full();<br>
+ db.names.back() = db.make<VendorExtQualType>(<wbr>type, db.names.back());<br>
}<br>
else<br>
{<br>
- auto proto = db.names.back().move_full();<br>
+ auto* proto = static_cast<NameType*>(db.<wbr>names.back());<br>
db.names.pop_back();<br>
- t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db);<br>
- if (t != proto.data() + 9)<br>
+ t = parse_source_name(proto-><wbr>getName().begin() + 9, proto->getName().end(), db);<br>
+ if (t != proto->getName().begin() + 9)<br>
{<br>
- db.names.back() = type + "<" + db.names.back().move_full() + ">";<br>
+ db.names.back() = db.make<ObjCProtoName>(type, db.names.back());<br>
}<br>
else<br>
{<br>
- db.names.push_back(type + " " + proto);<br>
+ db.names.push_back(db.make<<wbr>VendorExtQualType>(type, proto));<br>
}<br>
}<br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
@@ -2371,9 +3541,11 @@ parse_type(const char* first, const char<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto template_args = db.names.back().move_full();<br>
+ auto template_args = db.names.back();<br>
db.names.pop_back();<br>
- db.names.back().first += template_args;<br>
+ db.names.back() = db.make<<br>
+ NameWithTemplateArgs>(<br>
+ db.names.back(), template_args);<br>
// Need to create substitution for <template-template-param> <template-args><br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
first = t;<br>
@@ -2520,20 +3692,20 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'a':<br>
- db.names.push_back("operator&&<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator&&"));<br>
first += 2;<br>
break;<br>
case 'd':<br>
case 'n':<br>
- db.names.push_back("operator&"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator&"));<br>
first += 2;<br>
break;<br>
case 'N':<br>
- db.names.push_back("operator&=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator&="));<br>
first += 2;<br>
break;<br>
case 'S':<br>
- db.names.push_back("operator="<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator="));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2542,15 +3714,15 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'l':<br>
- db.names.push_back("operator()<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator()"));<br>
first += 2;<br>
break;<br>
case 'm':<br>
- db.names.push_back("operator,"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator,"));<br>
first += 2;<br>
break;<br>
case 'o':<br>
- db.names.push_back("operator~"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator~"));<br>
first += 2;<br>
break;<br>
case 'v':<br>
@@ -2563,7 +3735,8 @@ parse_operator_name(const char* first, c<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "operator ");<br>
+ db.names.back() =<br>
+ db.make<<wbr>ConversionOperatorType>(db.<wbr>names.back());<br>
db.parsed_ctor_dtor_cv = true;<br>
first = t;<br>
}<br>
@@ -2575,23 +3748,23 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'a':<br>
- db.names.push_back("operator delete[]");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator delete[]"));<br>
first += 2;<br>
break;<br>
case 'e':<br>
- db.names.push_back("operator*"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator*"));<br>
first += 2;<br>
break;<br>
case 'l':<br>
- db.names.push_back("operator delete");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator delete"));<br>
first += 2;<br>
break;<br>
case 'v':<br>
- db.names.push_back("operator/"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator/"));<br>
first += 2;<br>
break;<br>
case 'V':<br>
- db.names.push_back("operator/=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator/="));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2600,15 +3773,15 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'o':<br>
- db.names.push_back("operator^"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator^"));<br>
first += 2;<br>
break;<br>
case 'O':<br>
- db.names.push_back("operator^=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator^="));<br>
first += 2;<br>
break;<br>
case 'q':<br>
- db.names.push_back("operator==<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator=="));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2617,11 +3790,11 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'e':<br>
- db.names.push_back("operator>=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator>="));<br>
first += 2;<br>
break;<br>
case 't':<br>
- db.names.push_back("operator>"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator>"));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2629,7 +3802,7 @@ parse_operator_name(const char* first, c<br>
case 'i':<br>
if (first[1] == 'x')<br>
{<br>
- db.names.push_back("operator[]<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator[]"));<br>
first += 2;<br>
}<br>
break;<br>
@@ -2637,7 +3810,7 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'e':<br>
- db.names.push_back("operator<=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator<="));<br>
first += 2;<br>
break;<br>
case 'i':<br>
@@ -2647,21 +3820,22 @@ parse_operator_name(const char* first, c<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "operator\"\" ");<br>
+ db.names.back() =<br>
+ db.make<LiteralOperator>(db.<wbr>names.back());<br>
first = t;<br>
}<br>
}<br>
break;<br>
case 's':<br>
- db.names.push_back("operator<<<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator<<"));<br>
first += 2;<br>
break;<br>
case 'S':<br>
- db.names.push_back("operator<<<wbr>=");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator<<="));<br>
first += 2;<br>
break;<br>
case 't':<br>
- db.names.push_back("operator<"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator<"));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2670,23 +3844,23 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'i':<br>
- db.names.push_back("operator-"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator-"));<br>
first += 2;<br>
break;<br>
case 'I':<br>
- db.names.push_back("operator-=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator-="));<br>
first += 2;<br>
break;<br>
case 'l':<br>
- db.names.push_back("operator*"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator*"));<br>
first += 2;<br>
break;<br>
case 'L':<br>
- db.names.push_back("operator*=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator*="));<br>
first += 2;<br>
break;<br>
case 'm':<br>
- db.names.push_back("operator--<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator--"));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2695,23 +3869,23 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'a':<br>
- db.names.push_back("operator new[]");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator new[]"));<br>
first += 2;<br>
break;<br>
case 'e':<br>
- db.names.push_back("operator!=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator!="));<br>
first += 2;<br>
break;<br>
case 'g':<br>
- db.names.push_back("operator-"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator-"));<br>
first += 2;<br>
break;<br>
case 't':<br>
- db.names.push_back("operator!"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator!"));<br>
first += 2;<br>
break;<br>
case 'w':<br>
- db.names.push_back("operator new");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator new"));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2720,15 +3894,15 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'o':<br>
- db.names.push_back("operator||<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator||"));<br>
first += 2;<br>
break;<br>
case 'r':<br>
- db.names.push_back("operator|"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator|"));<br>
first += 2;<br>
break;<br>
case 'R':<br>
- db.names.push_back("operator|=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator|="));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2737,27 +3911,27 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'm':<br>
- db.names.push_back("operator-><wbr>*");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator->*"));<br>
first += 2;<br>
break;<br>
case 'l':<br>
- db.names.push_back("operator+"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator+"));<br>
first += 2;<br>
break;<br>
case 'L':<br>
- db.names.push_back("operator+=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator+="));<br>
first += 2;<br>
break;<br>
case 'p':<br>
- db.names.push_back("operator++<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator++"));<br>
first += 2;<br>
break;<br>
case 's':<br>
- db.names.push_back("operator+"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator+"));<br>
first += 2;<br>
break;<br>
case 't':<br>
- db.names.push_back("operator-><wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator->"));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2765,7 +3939,7 @@ parse_operator_name(const char* first, c<br>
case 'q':<br>
if (first[1] == 'u')<br>
{<br>
- db.names.push_back("operator?"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator?"));<br>
first += 2;<br>
}<br>
break;<br>
@@ -2773,19 +3947,19 @@ parse_operator_name(const char* first, c<br>
switch (first[1])<br>
{<br>
case 'm':<br>
- db.names.push_back("operator%"<wbr>);<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator%"));<br>
first += 2;<br>
break;<br>
case 'M':<br>
- db.names.push_back("operator%=<wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator%="));<br>
first += 2;<br>
break;<br>
case 's':<br>
- db.names.push_back("operator>><wbr>");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator>>"));<br>
first += 2;<br>
break;<br>
case 'S':<br>
- db.names.push_back("operator>><wbr>=");<br>
+ db.names.push_back(db.make<<wbr>NameType>("operator>>="));<br>
first += 2;<br>
break;<br>
}<br>
@@ -2798,7 +3972,8 @@ parse_operator_name(const char* first, c<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "operator ");<br>
+ db.names.back() =<br>
+ db.make<<wbr>ConversionOperatorType>(db.<wbr>names.back());<br>
first = t;<br>
}<br>
}<br>
@@ -2809,23 +3984,13 @@ parse_operator_name(const char* first, c<br>
}<br>
<br>
const char*<br>
-parse_integer_literal(const char* first, const char* last, const Db::String& lit, Db& db)<br>
+parse_integer_literal(const char* first, const char* last, StringView lit, Db& db)<br>
{<br>
const char* t = parse_number(first, last);<br>
if (t != first && t != last && *t == 'E')<br>
{<br>
- if (lit.size() > 3)<br>
- db.names.push_back("(" + lit + ")");<br>
- else<br>
- db.names.emplace_back();<br>
- if (*first == 'n')<br>
- {<br>
- db.names.back().first += '-';<br>
- ++first;<br>
- }<br>
- db.names.back().first.append(<wbr>first, t);<br>
- if (lit.size() <= 3)<br>
- db.names.back().first += lit;<br>
+ db.names.push_back(<br>
+ db.make<IntegerExpr>(lit, StringView(first, t)));<br>
first = t+1;<br>
}<br>
return first;<br>
@@ -2858,11 +4023,11 @@ parse_expr_primary(const char* first, co<br>
switch (first[2])<br>
{<br>
case '0':<br>
- db.names.push_back("false");<br>
+ db.names.push_back(db.make<<wbr>BoolExpr>(0));<br>
first += 4;<br>
break;<br>
case '1':<br>
- db.names.push_back("true");<br>
+ db.names.push_back(db.make<<wbr>BoolExpr>(1));<br>
first += 4;<br>
break;<br>
}<br>
@@ -3007,7 +4172,8 @@ parse_expr_primary(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "(" + db.names.back().move_full() + ")" + Db::String(t, n);<br>
+ db.names.back() = db.make<IntegerCastExpr>(<br>
+ db.names.back(), StringView(t, n));<br>
first = n+1;<br>
break;<br>
}<br>
@@ -3024,69 +4190,22 @@ parse_expr_primary(const char* first, co<br>
return first;<br>
}<br>
<br>
-template <class String><br>
-String<br>
-base_name(String& s)<br>
+Node* maybe_change_special_sub_name(<wbr>Node* inp, Db& db)<br>
{<br>
- if (s.empty())<br>
- return s;<br>
- if (s == "std::string")<br>
- {<br>
- s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >";<br>
- return "basic_string";<br>
- }<br>
- if (s == "std::istream")<br>
- {<br>
- s = "std::basic_istream<char, std::char_traits<char> >";<br>
- return "basic_istream";<br>
- }<br>
- if (s == "std::ostream")<br>
- {<br>
- s = "std::basic_ostream<char, std::char_traits<char> >";<br>
- return "basic_ostream";<br>
- }<br>
- if (s == "std::iostream")<br>
- {<br>
- s = "std::basic_iostream<char, std::char_traits<char> >";<br>
- return "basic_iostream";<br>
- }<br>
- const char* const pf = s.data();<br>
- const char* pe = pf + s.size();<br>
- if (pe[-1] == '>')<br>
- {<br>
- unsigned c = 1;<br>
- while (true)<br>
- {<br>
- if (--pe == pf)<br>
- return String();<br>
- if (pe[-1] == '<')<br>
- {<br>
- if (--c == 0)<br>
- {<br>
- --pe;<br>
- break;<br>
- }<br>
- }<br>
- else if (pe[-1] == '>')<br>
- ++c;<br>
- }<br>
+ if (inp->K != Node::KSpecialSubstitution)<br>
+ return inp;<br>
+ auto Kind = static_cast<<wbr>SpecialSubstitution*>(inp)-><wbr>SSK;<br>
+ switch (Kind)<br>
+ {<br>
+ case SpecialSubKind::string:<br>
+ case SpecialSubKind::istream:<br>
+ case SpecialSubKind::ostream:<br>
+ case SpecialSubKind::iostream:<br>
+ return db.make<<wbr>ExpandedSpecialSubstitution>(<wbr>Kind);<br>
+ default:<br>
+ break;<br>
}<br>
- if (pe - pf <= 1)<br>
- return String();<br>
- const char* p0 = pe - 1;<br>
- for (; p0 != pf; --p0)<br>
- {<br>
- if (*p0 == ':')<br>
- {<br>
- ++p0;<br>
- break;<br>
- }<br>
- if (!isalpha(*p0) && !isdigit(*p0) && *p0 != '_')<br>
- {<br>
- return String();<br>
- }<br>
- }<br>
- return String(p0, pe);<br>
+ return inp;<br>
}<br>
<br>
// <ctor-dtor-name> ::= C1 # complete object constructor<br>
@@ -3114,7 +4233,10 @@ parse_ctor_dtor_name(const char* first,<br>
case '5':<br>
if (db.names.empty())<br>
return first;<br>
- db.names.push_back(base_name(<wbr>db.names.back().first));<br>
+ db.names.back() =<br>
+ maybe_change_special_sub_name(<wbr>db.names.back(), db);<br>
+ db.names.push_back(<br>
+ db.make<CtorDtorName>(db.<wbr>names.back(), false));<br>
first += 2;<br>
db.parsed_ctor_dtor_cv = true;<br>
break;<br>
@@ -3129,7 +4251,8 @@ parse_ctor_dtor_name(const char* first,<br>
case '5':<br>
if (db.names.empty())<br>
return first;<br>
- db.names.push_back("~" + base_name(db.names.back().<wbr>first));<br>
+ db.names.push_back(<br>
+ db.make<CtorDtorName>(db.<wbr>names.back(), true));<br>
first += 2;<br>
db.parsed_ctor_dtor_cv = true;<br>
break;<br>
@@ -3157,106 +4280,63 @@ parse_unnamed_type_name(const char* firs<br>
{<br>
case 't':<br>
{<br>
- db.names.push_back(Db::String(<wbr>"'unnamed"));<br>
const char* t0 = first+2;<br>
if (t0 == last)<br>
- {<br>
- db.names.pop_back();<br>
return first;<br>
- }<br>
+ StringView count;<br>
if (std::isdigit(*t0))<br>
{<br>
const char* t1 = t0 + 1;<br>
while (t1 != last && std::isdigit(*t1))<br>
++t1;<br>
- db.names.back().first.append(<wbr>t0, t1);<br>
+ count = StringView(t0, t1);<br>
t0 = t1;<br>
}<br>
- db.names.back().first.push_<wbr>back('\'');<br>
if (t0 == last || *t0 != '_')<br>
- {<br>
- db.names.pop_back();<br>
return first;<br>
- }<br>
+ db.names.push_back(db.make<<wbr>UnnamedTypeName>(count));<br>
first = t0 + 1;<br>
}<br>
break;<br>
case 'l':<br>
{<br>
- size_t lambda_pos = db.names.size();<br>
- db.names.push_back(Db::String(<wbr>"'lambda'("));<br>
+ size_t begin_pos = db.names.size();<br>
const char* t0 = first+2;<br>
+ NodeArray lambda_params;<br>
if (first[2] == 'v')<br>
{<br>
- db.names.back().first += ')';<br>
++t0;<br>
}<br>
else<br>
{<br>
- bool is_first_it = true;<br>
while (true)<br>
{<br>
- long k0 = static_cast<long>(db.names.<wbr>size());<br>
const char* t1 = parse_type(t0, last, db);<br>
- long k1 = static_cast<long>(db.names.<wbr>size());<br>
if (t1 == t0)<br>
break;<br>
- if (k0 >= k1)<br>
- return first;<br>
- // If the call to parse_type above found a pack expansion<br>
- // substitution, then multiple names could have been<br>
- // inserted into the name table. Walk through the names,<br>
- // appending each onto the lambda's parameter list.<br>
- std::for_each(db.names.begin() + k0, db.names.begin() + k1,<br>
- [&](Db::sub_type::value_type &pair) {<br>
- if (pair.empty())<br>
- return;<br>
- auto &lambda = db.names[lambda_pos].first;<br>
- if (!is_first_it)<br>
- lambda.append(", ");<br>
- is_first_it = false;<br>
- lambda.append(pair.move_full()<wbr>);<br>
- });<br>
- db.names.erase(db.names.begin(<wbr>) + k0, db.names.end());<br>
t0 = t1;<br>
}<br>
- if (is_first_it)<br>
- {<br>
- if (!db.names.empty())<br>
- db.names.pop_back();<br>
+ if (db.names.size() < begin_pos)<br>
return first;<br>
- }<br>
- if (db.names.empty() || db.names.size() - 1 != lambda_pos)<br>
- return first;<br>
- db.names.back().first.append("<wbr>)");<br>
+ lambda_params = db.popTrailingNodeArray(begin_<wbr>pos);<br>
}<br>
if (t0 == last || *t0 != 'E')<br>
- {<br>
- if (!db.names.empty())<br>
- db.names.pop_back();<br>
- return first;<br>
- }<br>
+ return first;<br>
++t0;<br>
if (t0 == last)<br>
- {<br>
- if(!db.names.empty())<br>
- db.names.pop_back();<br>
return first;<br>
- }<br>
+ StringView count;<br>
if (std::isdigit(*t0))<br>
{<br>
const char* t1 = t0 + 1;<br>
while (t1 != last && std::isdigit(*t1))<br>
++t1;<br>
- db.names.back().first.insert(<wbr>db.names.back().first.begin()+<wbr>7, t0, t1);<br>
+ count = StringView(t0, t1);<br>
t0 = t1;<br>
}<br>
if (t0 == last || *t0 != '_')<br>
- {<br>
- if(!db.names.empty())<br>
- db.names.pop_back();<br>
return first;<br>
- }<br>
+ db.names.push_back(db.make<<wbr>LambdaTypeName>(lambda_params, count));<br>
first = t0 + 1;<br>
}<br>
break;<br>
@@ -3337,7 +4417,8 @@ parse_unscoped_name(const char* first, c<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "std::");<br>
+ db.names.back() =<br>
+ db.make<StdQualifiedName>(db.<wbr>names.back());<br>
}<br>
first = t1;<br>
}<br>
@@ -3357,7 +4438,8 @@ parse_alignof_type(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first = "alignof (" + db.names.back().move_full() + ")";<br>
+ db.names.back() =<br>
+ db.make<EnclosingExpr>("<wbr>alignof (", db.names.back(), ")");<br>
first = t;<br>
}<br>
}<br>
@@ -3376,7 +4458,8 @@ parse_alignof_expr(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first = "alignof (" + db.names.back().move_full() + ")";<br>
+ db.names.back() =<br>
+ db.make<EnclosingExpr>("<wbr>alignof (", db.names.back(), ")");<br>
first = t;<br>
}<br>
}<br>
@@ -3391,28 +4474,29 @@ parse_noexcept_expression(<wbr>const char* fi<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first = "noexcept (" + db.names.back().move_full() + ")";<br>
+ db.names.back() =<br>
+ db.make<EnclosingExpr>("<wbr>noexcept (", db.names.back(), ")");<br>
first = t1;<br>
}<br>
return first;<br>
}<br>
<br>
const char*<br>
-parse_prefix_expression(const char* first, const char* last, const Db::String& op, Db& db)<br>
+parse_prefix_expression(const char* first, const char* last, StringView op, Db& db)<br>
{<br>
const char* t1 = parse_expression(first, last, db);<br>
if (t1 != first)<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first = op + "(" + db.names.back().move_full() + ")";<br>
+ db.names.back() = db.make<PrefixExpr>(op, db.names.back());<br>
first = t1;<br>
}<br>
return first;<br>
}<br>
<br>
const char*<br>
-parse_binary_expression(const char* first, const char* last, const Db::String& op, Db& db)<br>
+parse_binary_expression(const char* first, const char* last, StringView op, Db& db)<br>
{<br>
const char* t1 = parse_expression(first, last, db);<br>
if (t1 != first)<br>
@@ -3422,20 +4506,12 @@ parse_binary_expression(const char* firs<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto op2 = db.names.back().move_full();<br>
+ auto op2 = db.names.back();<br>
db.names.pop_back();<br>
- auto op1 = db.names.back().move_full();<br>
- auto& nm = db.names.back().first;<br>
- nm.clear();<br>
- if (op == ">")<br>
- nm += '(';<br>
- nm += "(" + op1 + ") " + op + " (" + op2 + ")";<br>
- if (op == ">")<br>
- nm += ')';<br>
+ auto op1 = db.names.back();<br>
+ db.names.back() = db.make<BinaryExpr>(op1, op, op2);<br>
first = t2;<br>
}<br>
- else if(!db.names.empty())<br>
- db.names.pop_back();<br>
}<br>
return first;<br>
}<br>
@@ -3573,8 +4649,8 @@ parse_expression(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first = (parsed_gs ? Db::String("::") : Db::String()) +<br>
- "delete[] " + db.names.back().move_full();<br>
+ db.names.back() = db.make<DeleteExpr>(<br>
+ db.names.back(), parsed_gs, /*is_array=*/true);<br>
first = t1;<br>
}<br>
}<br>
@@ -3594,8 +4670,8 @@ parse_expression(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first = (parsed_gs ? Db::String("::") : Db::String()) +<br>
- "delete " + db.names.back().move_full();<br>
+ db.names.back() = db.make<DeleteExpr>(<br>
+ db.names.back(), parsed_gs, /*is_array=*/false);<br>
first = t1;<br>
}<br>
}<br>
@@ -3666,10 +4742,11 @@ parse_expression(const char* first, cons<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto op2 = db.names.back().move_full();<br>
+ auto op2 = db.names.back();<br>
db.names.pop_back();<br>
- auto op1 = db.names.back().move_full();<br>
- db.names.back() = "(" + op1 + ")[" + op2 + "]";<br>
+ auto op1 = db.names.back();<br>
+ db.names.back() =<br>
+ db.make<ArraySubscriptExpr>(<wbr>op1, op2);<br>
first = t2;<br>
}<br>
else if (!db.names.empty())<br>
@@ -3739,7 +4816,8 @@ parse_expression(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "(" + db.names.back().move_full() + ")--";<br>
+ db.names.back() =<br>
+ db.make<PostfixExpr>(db.names.<wbr>back(), "--");<br>
first = t1;<br>
}<br>
}<br>
@@ -3829,7 +4907,8 @@ parse_expression(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back() = "(" + db.names.back().move_full() + ")++";<br>
+ db.names.back() =<br>
+ db.make<PostfixExpr>(db.names.<wbr>back(), "++");<br>
first = t1;<br>
}<br>
}<br>
@@ -3858,12 +4937,13 @@ parse_expression(const char* first, cons<br>
{<br>
if (db.names.size() < 3)<br>
return first;<br>
- auto op3 = db.names.back().move_full();<br>
+ auto op3 = db.names.back();<br>
db.names.pop_back();<br>
- auto op2 = db.names.back().move_full();<br>
+ auto op2 = db.names.back();<br>
db.names.pop_back();<br>
- auto op1 = db.names.back().move_full();<br>
- db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")";<br>
+ auto op1 = db.names.back();<br>
+ db.names.back() =<br>
+ db.make<ConditionalExpr>(op1, op2, op3);<br>
first = t3;<br>
}<br>
else<br>
@@ -3948,7 +5028,7 @@ parse_expression(const char* first, cons<br>
first = parse_typeid_expr(first, last, db);<br>
break;<br>
case 'r':<br>
- db.names.push_back("throw");<br>
+ db.names.push_back(db.make<<wbr>NameType>("throw"));<br>
first += 2;<br>
break;<br>
case 'w':<br>
@@ -4037,7 +5117,7 @@ parse_template_args(const char* first, c<br>
if (db.tag_templates)<br>
db.template_param.back().<wbr>clear();<br>
const char* t = first+1;<br>
- Db::String args("<");<br>
+ size_t begin_idx = db.names.size();<br>
while (*t != 'E')<br>
{<br>
if (db.tag_templates)<br>
@@ -4047,7 +5127,7 @@ parse_template_args(const char* first, c<br>
size_t k1 = db.names.size();<br>
if (db.tag_templates)<br>
db.template_param.pop_back();<br>
- if (t1 == t || t1 == last)<br>
+ if (t1 == t || t1 == last || k0 > k1)<br>
return first;<br>
if (db.tag_templates)<br>
{<br>
@@ -4055,30 +5135,18 @@ parse_template_args(const char* first, c<br>
for (size_t k = k0; k < k1; ++k)<br>
db.template_param.back().back(<wbr>).push_back(db.names[k]);<br>
}<br>
- for (size_t k = k0; k < k1; ++k)<br>
- {<br>
- if (args.size() > 1)<br>
- args += ", ";<br>
- args += db.names[k].move_full();<br>
- }<br>
- for (; k1 > k0; --k1)<br>
- if (!db.names.empty())<br>
- db.names.pop_back();<br>
t = t1;<br>
}<br>
first = t + 1;<br>
- if (args.back() != '>')<br>
- args += ">";<br>
- else<br>
- args += " >";<br>
- db.names.push_back(std::move(<wbr>args));<br>
-<br>
+ TemplateParams* tp = db.make<TemplateParams>(<br>
+ db.popTrailingNodeArray(begin_<wbr>idx));<br>
+ db.names.push_back(tp);<br>
}<br>
return first;<br>
}<br>
<br>
-// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E<br>
-// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E<br>
+// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E<br>
+// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E<br>
//<br>
// <prefix> ::= <prefix> <unqualified-name><br>
// ::= <template-prefix> <template-args><br>
@@ -4099,32 +5167,29 @@ parse_nested_name(const char* first, con<br>
{<br>
if (first != last && *first == 'N')<br>
{<br>
- unsigned cv;<br>
+ Qualifiers cv;<br>
const char* t0 = parse_cv_qualifiers(first+1, last, cv);<br>
if (t0 == last)<br>
return first;<br>
- db.ref = 0;<br>
+ db.ref = FrefQualNone;<br>
if (*t0 == 'R')<br>
{<br>
- db.ref = 1;<br>
+ db.ref = FrefQualLValue;<br>
++t0;<br>
}<br>
else if (*t0 == 'O')<br>
{<br>
- db.ref = 2;<br>
+ db.ref = FrefQualRValue;<br>
++t0;<br>
}<br>
- db.names.emplace_back();<br>
+ db.names.push_back(db.make<<wbr>EmptyName>());<br>
if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')<br>
{<br>
t0 += 2;<br>
- db.names.back().first = "std";<br>
+ db.names.back() = db.make<NameType>("std");<br>
}<br>
if (t0 == last)<br>
- {<br>
- db.names.pop_back();<br>
return first;<br>
- }<br>
bool pop_subs = false;<br>
bool component_ends_with_template_<wbr>args = false;<br>
while (*t0 != 'E')<br>
@@ -4139,17 +5204,18 @@ parse_nested_name(const char* first, con<br>
t1 = parse_substitution(t0, last, db);<br>
if (t1 != t0 && t1 != last)<br>
{<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
- if (db.names.empty())<br>
- return first;<br>
- if (!db.names.back().first.empty(<wbr>))<br>
+ if (db.names.back()->K != Node::KEmptyName)<br>
{<br>
- db.names.back().first += "::" + name;<br>
- db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
+ db.names.back() = db.make<QualifiedName>(<br>
+ db.names.back(), name);<br>
+ db.subs.push_back(<br>
+ Db::sub_type(1, db.names.back(),<br>
+ db.names.get_allocator()));<br>
}<br>
else<br>
- db.names.back().first = name;<br>
+ db.names.back() = name;<br>
pop_subs = true;<br>
t0 = t1;<br>
}<br>
@@ -4160,14 +5226,13 @@ parse_nested_name(const char* first, con<br>
t1 = parse_template_param(t0, last, db);<br>
if (t1 != t0 && t1 != last)<br>
{<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
- if (db.names.empty())<br>
- return first;<br>
- if (!db.names.back().first.empty(<wbr>))<br>
- db.names.back().first += "::" + name;<br>
+ if (db.names.back()->K != Node::KEmptyName)<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), name);<br>
else<br>
- db.names.back().first = name;<br>
+ db.names.back() = name;<br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
pop_subs = true;<br>
t0 = t1;<br>
@@ -4181,14 +5246,13 @@ parse_nested_name(const char* first, con<br>
t1 = parse_decltype(t0, last, db);<br>
if (t1 != t0 && t1 != last)<br>
{<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
- if (db.names.empty())<br>
- return first;<br>
- if (!db.names.back().first.empty(<wbr>))<br>
- db.names.back().first += "::" + name;<br>
+ if (db.names.back()->K != Node::KEmptyName)<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), name);<br>
else<br>
- db.names.back().first = name;<br>
+ db.names.back() = name;<br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
pop_subs = true;<br>
t0 = t1;<br>
@@ -4200,12 +5264,12 @@ parse_nested_name(const char* first, con<br>
t1 = parse_template_args(t0, last, db);<br>
if (t1 != t0 && t1 != last)<br>
{<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
- if (db.names.empty())<br>
- return first;<br>
- db.names.back().first += name;<br>
- db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
+ db.names.back() = db.make<NameWithTemplateArgs>(<br>
+ db.names.back(), name);<br>
+ db.subs.push_back(Db::sub_<wbr>type(<br>
+ 1, db.names.back(), db.names.get_allocator()));<br>
t0 = t1;<br>
component_ends_with_template_<wbr>args = true;<br>
}<br>
@@ -4221,14 +5285,13 @@ parse_nested_name(const char* first, con<br>
t1 = parse_unqualified_name(t0, last, db);<br>
if (t1 != t0 && t1 != last)<br>
{<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
- if (db.names.empty())<br>
- return first;<br>
- if (!db.names.back().first.empty(<wbr>))<br>
- db.names.back().first += "::" + name;<br>
+ if (db.names.back()->K != Node::KEmptyName)<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), name);<br>
else<br>
- db.names.back().first = name;<br>
+ db.names.back() = name;<br>
db.subs.push_back(Db::sub_<wbr>type(1, db.names.back(), db.names.get_allocator()));<br>
pop_subs = true;<br>
t0 = t1;<br>
@@ -4304,7 +5367,8 @@ parse_local_name(const char* first, cons<br>
first = parse_discriminator(t+1, last);<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.append("<wbr>::string literal");<br>
+ db.names.back() = db.make<QualifiedName>(<br>
+ db.names.back(), db.make<NameType>("string literal"));<br>
break;<br>
case 'd':<br>
if (++t != last)<br>
@@ -4319,12 +5383,12 @@ parse_local_name(const char* first, cons<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.append("<wbr>::");<br>
- db.names.back().first.append(<wbr>name);<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), name);<br>
first = t1;<br>
}<br>
else if (!db.names.empty())<br>
@@ -4342,12 +5406,12 @@ parse_local_name(const char* first, cons<br>
first = parse_discriminator(t1, last);<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto name = db.names.back().move_full();<br>
+ auto name = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.append("<wbr>::");<br>
- db.names.back().first.append(<wbr>name);<br>
+ db.names.back() =<br>
+ db.make<QualifiedName>(db.<wbr>names.back(), name);<br>
}<br>
else if (!db.names.empty())<br>
db.names.pop_back();<br>
@@ -4411,11 +5475,13 @@ parse_name(const char* first, const char<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto tmp = db.names.back().move_full();<br>
+ auto tmp = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first += tmp;<br>
+ db.names.back() =<br>
+ db.make<NameWithTemplateArgs>(<br>
+ db.names.back(), tmp);<br>
first = t1;<br>
if (ends_with_template_args)<br>
*ends_with_template_args = true;<br>
@@ -4435,11 +5501,13 @@ parse_name(const char* first, const char<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto tmp = db.names.back().move_full();<br>
+ auto tmp = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first += tmp;<br>
+ db.names.back() =<br>
+ db.make<NameWithTemplateArgs>(<br>
+ db.names.back(), tmp);<br>
first = t1;<br>
if (ends_with_template_args)<br>
*ends_with_template_args = true;<br>
@@ -4527,7 +5595,8 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "vtable for ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("vtable for ", db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4538,7 +5607,8 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "VTT for ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("VTT for ", db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4549,7 +5619,8 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "typeinfo for ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("typeinfo for ", db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4560,7 +5631,8 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "typeinfo name for ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("typeinfo name for ", db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4578,7 +5650,9 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "covariant return thunk to ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("<wbr>covariant return thunk to ",<br>
+ db.names.back());<br>
first = t;<br>
}<br>
}<br>
@@ -4596,13 +5670,12 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.size() < 2)<br>
return first;<br>
- auto left = db.names.back().move_full();<br>
+ auto left = db.names.back();<br>
db.names.pop_back();<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first = "construction vtable for " +<br>
- std::move(left) + "-in-" +<br>
- db.names.back().move_full();<br>
+ db.names.back() = db.make<CtorVtableSpecialName><wbr>(<br>
+ left, db.names.back());<br>
first = t1;<br>
}<br>
}<br>
@@ -4614,8 +5687,10 @@ parse_special_name(const char* first, co<br>
if (t != first + 2)<br>
{<br>
if (db.names.empty())<br>
- return first;<br>
- db.names.back().first.insert(<wbr>0, "thread-local wrapper routine for ");<br>
+ return first;<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("thread-<wbr>local wrapper routine for ",<br>
+ db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4625,8 +5700,9 @@ parse_special_name(const char* first, co<br>
if (t != first + 2)<br>
{<br>
if (db.names.empty())<br>
- return first;<br>
- db.names.back().first.insert(<wbr>0, "thread-local initialization routine for ");<br>
+ return first;<br>
+ db.names.back() = db.make<SpecialName>(<br>
+ "thread-local initialization routine for ", db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4643,12 +5719,16 @@ parse_special_name(const char* first, co<br>
return first;<br>
if (first[1] == 'v')<br>
{<br>
- db.names.back().first.insert(<wbr>0, "virtual thunk to ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("virtual thunk to ",<br>
+ db.names.back());<br>
first = t;<br>
}<br>
else<br>
{<br>
- db.names.back().first.insert(<wbr>0, "non-virtual thunk to ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("non-<wbr>virtual thunk to ",<br>
+ db.names.back());<br>
first = t;<br>
}<br>
}<br>
@@ -4666,7 +5746,8 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "guard variable for ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("guard variable for ", db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4677,7 +5758,9 @@ parse_special_name(const char* first, co<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "reference temporary for ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("<wbr>reference temporary for ",<br>
+ db.names.back());<br>
first = t;<br>
}<br>
break;<br>
@@ -4735,8 +5818,10 @@ parse_encoding(const char* first, const<br>
bool ends_with_template_args = false;<br>
const char* t = parse_name(first, last, db,<br>
&ends_with_template_args);<br>
- unsigned cv = <a href="http://db.cv" rel="noreferrer" target="_blank">db.cv</a>;<br>
- unsigned ref = db.ref;<br>
+ if (db.names.empty())<br>
+ return first;<br>
+ Qualifiers cv = <a href="http://db.cv" rel="noreferrer" target="_blank">db.cv</a>;<br>
+ FunctionRefQual ref = db.ref;<br>
if (t != first)<br>
{<br>
if (t != last && *t != 'E' && *t != '.')<br>
@@ -4744,87 +5829,59 @@ parse_encoding(const char* first, const<br>
save_value<bool> sb2(db.tag_templates);<br>
db.tag_templates = false;<br>
const char* t2;<br>
- Db::String ret2;<br>
if (db.names.empty())<br>
return first;<br>
- const Db::String& nm = db.names.back().first;<br>
- if (nm.empty())<br>
+ if (!db.names.back())<br>
return first;<br>
+ Node* return_type = nullptr;<br>
if (!db.parsed_ctor_dtor_cv && ends_with_template_args)<br>
{<br>
t2 = parse_type(t, last, db);<br>
if (t2 == t)<br>
return first;<br>
- if (db.names.size() < 2)<br>
+ if (db.names.size() < 1)<br>
return first;<br>
- auto ret1 = std::move(db.names.back().<wbr>first);<br>
- ret2 = std::move(db.names.back().<wbr>second);<br>
- if (ret2.empty())<br>
- ret1 += ' ';<br>
+ return_type = db.names.back();<br>
db.names.pop_back();<br>
- if (db.names.empty())<br>
- return first;<br>
-<br>
- db.names.back().first.insert(<wbr>0, ret1);<br>
t = t2;<br>
}<br>
- db.names.back().first += '(';<br>
+<br>
+ Node* result = nullptr;<br>
+<br>
if (t != last && *t == 'v')<br>
{<br>
++t;<br>
+ Node* name = db.names.back();<br>
+ db.names.pop_back();<br>
+ result = db.make<TopLevelFunctionDecl>(<br>
+ return_type, name, NodeArray());<br>
}<br>
else<br>
{<br>
- bool first_arg = true;<br>
+ size_t params_begin = db.names.size();<br>
while (true)<br>
{<br>
- size_t k0 = db.names.size();<br>
t2 = parse_type(t, last, db);<br>
- size_t k1 = db.names.size();<br>
if (t2 == t)<br>
break;<br>
- if (k1 > k0)<br>
- {<br>
- Db::String tmp;<br>
- for (size_t k = k0; k < k1; ++k)<br>
- {<br>
- if (!tmp.empty())<br>
- tmp += ", ";<br>
- tmp += db.names[k].move_full();<br>
- }<br>
- for (size_t k = k0; k < k1; ++k) {<br>
- if (db.names.empty())<br>
- return first;<br>
- db.names.pop_back();<br>
- }<br>
- if (!tmp.empty())<br>
- {<br>
- if (db.names.empty())<br>
- return first;<br>
- if (!first_arg)<br>
- db.names.back().first += ", ";<br>
- else<br>
- first_arg = false;<br>
- db.names.back().first += tmp;<br>
- }<br>
- }<br>
t = t2;<br>
}<br>
+ if (db.names.size() < params_begin)<br>
+ return first;<br>
+ NodeArray params =<br>
+ db.popTrailingNodeArray(<wbr>params_begin);<br>
+ if (db.names.empty())<br>
+ return first;<br>
+ Node* name = db.names.back();<br>
+ db.names.pop_back();<br>
+ result = db.make<TopLevelFunctionDecl>(<br>
+ return_type, name, params);<br>
}<br>
- if (db.names.empty())<br>
- return first;<br>
- db.names.back().first += ')';<br>
- if (cv & 1)<br>
- db.names.back().first.append(" const");<br>
- if (cv & 2)<br>
- db.names.back().first.append(" volatile");<br>
- if (cv & 4)<br>
- db.names.back().first.append(" restrict");<br>
- if (ref == 1)<br>
- db.names.back().first.append(" &");<br>
- else if (ref == 2)<br>
- db.names.back().first.append(" &&");<br>
- db.names.back().first += ret2;<br>
+ if (ref != FrefQualNone)<br>
+ result = db.make<FunctionRefQualType>(<wbr>result, ref);<br>
+ if (cv != QualNone)<br>
+ result = db.make<FunctionQualType>(<wbr>result, cv);<br>
+ db.names.push_back(result);<br>
first = t;<br>
}<br>
else<br>
@@ -4846,6 +5903,7 @@ parse_block_invoke(const char* first, co<br>
{<br>
if (last - first >= 13)<br>
{<br>
+ // FIXME: strcmp?<br>
const char test[] = "_block_invoke";<br>
const char* t = first;<br>
for (int i = 0; i < 13; ++i, ++t)<br>
@@ -4868,7 +5926,9 @@ parse_block_invoke(const char* first, co<br>
}<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first.insert(<wbr>0, "invocation function for block in ");<br>
+ db.names.back() =<br>
+ db.make<SpecialName>("<wbr>invocation function for block in ",<br>
+ db.names.back());<br>
first = t;<br>
}<br>
return first;<br>
@@ -4884,7 +5944,8 @@ parse_dot_suffix(const char* first, cons<br>
{<br>
if (db.names.empty())<br>
return first;<br>
- db.names.back().first += " (" + Db::String(first, last) + ")";<br>
+ db.names.back() =<br>
+ db.make<DotSuffix>(db.names.<wbr>back(), StringView(first, last));<br>
first = last;<br>
}<br>
return first;<br>
@@ -4963,6 +6024,7 @@ __cxa_demangle(const char *mangled_name,<br>
size_t len = std::strlen(mangled_name);<br>
demangle(mangled_name, mangled_name + len, db,<br>
internal_status);<br>
+<br>
if (internal_status == success && db.fix_forward_references &&<br>
!db.template_param.empty() && !db.template_param.front().<wbr>empty())<br>
{<br>
@@ -4974,30 +6036,25 @@ __cxa_demangle(const char *mangled_name,<br>
if (db.fix_forward_references)<br>
internal_status = invalid_mangled_name;<br>
}<br>
+<br>
if (internal_status == success)<br>
{<br>
- size_t sz = db.names.back().size() + 1;<br>
- if (sz > internal_size)<br>
+ if (!buf)<br>
{<br>
- char* newbuf = static_cast<char*>(std::<wbr>realloc(buf, sz));<br>
- if (newbuf == nullptr)<br>
- {<br>
- internal_status = memory_alloc_failure;<br>
- buf = nullptr;<br>
- }<br>
- else<br>
- {<br>
- buf = newbuf;<br>
- if (n != nullptr)<br>
- *n = sz;<br>
- }<br>
+ internal_size = 1024;<br>
+ buf = static_cast<char*>(std::<wbr>malloc(internal_size));<br>
}<br>
- if (buf != nullptr)<br>
+<br>
+ if (buf)<br>
{<br>
- db.names.back().first += db.names.back().second;<br>
- std::memcpy(buf, db.names.back().first.data(), sz-1);<br>
- buf[sz-1] = char(0);<br>
+ OutputStream s(buf, internal_size);<br>
+ db.names.back()->print(s);<br>
+ s += '\0';<br>
+ if (n) *n = s.getCurrentPosition();<br>
+ buf = s.getBuffer();<br>
}<br>
+ else<br>
+ internal_status = memory_alloc_failure;<br>
}<br>
else<br>
buf = nullptr;<br>
<br>
Modified: libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/test/test_demangle.pass.cpp?rev=309340&r1=309339&r2=309340&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/libcxxabi/trunk/test/<wbr>test_demangle.pass.cpp?rev=<wbr>309340&r1=309339&r2=309340&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp (original)<br>
+++ libcxxabi/trunk/test/test_<wbr>demangle.pass.cpp Thu Jul 27 17:43:49 2017<br>
@@ -29600,8 +29600,7 @@ const char* cases[][2] =<br>
{"i", "int"},<br>
<br>
{"PKFvRiE", "void (*)(int&) const"},<br>
- // FIXME(compnerd) pretty print this as void (*)(unsigned long &) volatile &&<br>
- {"PVFvRmOE", "void (*)(unsigned long&) volatile&&"},<br>
+ {"PVFvRmOE", "void (*)(unsigned long&) volatile &&"},<br>
{"PFvRmOE", "void (*)(unsigned long&) &&"},<br>
{"_ZTW1x", "thread-local wrapper routine for x"},<br>
{"_ZTHN3fooE", "thread-local initialization routine for foo"},<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>