summaryrefslogtreecommitdiffstats
path: root/lib/libcxxabi/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libcxxabi/src')
-rw-r--r--lib/libcxxabi/src/CMakeLists.txt42
-rw-r--r--lib/libcxxabi/src/cxa_default_handlers.cpp19
-rw-r--r--lib/libcxxabi/src/cxa_demangle.cpp8246
-rw-r--r--lib/libcxxabi/src/cxa_exception.cpp9
-rw-r--r--lib/libcxxabi/src/cxa_handlers.cpp22
-rw-r--r--lib/libcxxabi/src/cxa_personality.cpp25
-rw-r--r--lib/libcxxabi/src/demangle/Compiler.h34
-rw-r--r--lib/libcxxabi/src/demangle/StringView.h98
-rw-r--r--lib/libcxxabi/src/demangle/Utility.h191
-rw-r--r--lib/libcxxabi/src/fallback_malloc.cpp3
-rw-r--r--lib/libcxxabi/src/include/atomic_support.h181
-rw-r--r--lib/libcxxabi/src/include/refstring.h9
-rw-r--r--lib/libcxxabi/src/private_typeinfo.cpp69
-rw-r--r--lib/libcxxabi/src/stdlib_exception.cpp1
-rw-r--r--lib/libcxxabi/src/stdlib_new_delete.cpp1
15 files changed, 4128 insertions, 4822 deletions
diff --git a/lib/libcxxabi/src/CMakeLists.txt b/lib/libcxxabi/src/CMakeLists.txt
index 240f6d0d103..776c5129433 100644
--- a/lib/libcxxabi/src/CMakeLists.txt
+++ b/lib/libcxxabi/src/CMakeLists.txt
@@ -61,12 +61,19 @@ if (LIBCXXABI_USE_LLVM_UNWINDER)
# Prefer using the in-tree version of libunwind, either shared or static. If
# none are found fall back to using -lunwind.
# FIXME: Is it correct to prefer the static version of libunwind?
- if (NOT LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_shared OR HAVE_LIBUNWIND))
- list(APPEND LIBCXXABI_LIBRARIES unwind_shared)
- elseif (LIBCXXABI_ENABLE_STATIC_UNWINDER AND (TARGET unwind_static OR HAVE_LIBUNWIND))
- list(APPEND LIBCXXABI_LIBRARIES unwind_static)
+ if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND))
+ list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_shared)
+ elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND))
+ list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind_static)
else()
- list(APPEND LIBCXXABI_LIBRARIES unwind)
+ list(APPEND LIBCXXABI_SHARED_LIBRARIES unwind)
+ endif()
+ if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND))
+ list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind_shared)
+ elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND))
+ # We handle this by directly merging libunwind objects into libc++abi.
+ else()
+ list(APPEND LIBCXXABI_STATIC_LIBRARIES unwind)
endif()
else()
add_library_flags_if(LIBCXXABI_HAS_GCC_S_LIB gcc_s)
@@ -122,12 +129,13 @@ set_target_properties(cxxabi_objects
POSITION_INDEPENDENT_CODE
ON)
-set(LIBCXXABI_TARGETS)
-
# Build the shared library.
if (LIBCXXABI_ENABLE_SHARED)
add_library(cxxabi_shared SHARED $<TARGET_OBJECTS:cxxabi_objects>)
- target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES})
+ if(COMMAND llvm_setup_rpath)
+ llvm_setup_rpath(cxxabi_shared)
+ endif()
+ target_link_libraries(cxxabi_shared ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_SHARED_LIBRARIES})
set_target_properties(cxxabi_shared
PROPERTIES
CXX_EXTENSIONS
@@ -146,19 +154,22 @@ if (LIBCXXABI_ENABLE_SHARED)
"1"
VERSION
"1.0")
- list(APPEND LIBCXXABI_TARGETS "cxxabi_shared")
+ list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_shared")
+ if (LIBCXXABI_INSTALL_SHARED_LIBRARY)
+ list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_shared")
+ endif()
endif()
# Build the static library.
if (LIBCXXABI_ENABLE_STATIC)
set(cxxabi_static_sources $<TARGET_OBJECTS:cxxabi_objects>)
- if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_ENABLE_STATIC_UNWINDER)
+ if (LIBCXXABI_USE_LLVM_UNWINDER AND LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY)
if (TARGET unwind_static OR HAVE_LIBUNWIND)
list(APPEND cxxabi_static_sources $<TARGET_OBJECTS:unwind_objects>)
endif()
endif()
add_library(cxxabi_static STATIC ${cxxabi_static_sources})
- target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES})
+ target_link_libraries(cxxabi_static ${LIBCXXABI_LIBRARIES} ${LIBCXXABI_STATIC_LIBRARIES})
set_target_properties(cxxabi_static
PROPERTIES
CXX_EXTENSIONS
@@ -173,14 +184,17 @@ if (LIBCXXABI_ENABLE_STATIC)
"c++abi"
POSITION_INDEPENDENT_CODE
ON)
- list(APPEND LIBCXXABI_TARGETS "cxxabi_static")
+ list(APPEND LIBCXXABI_BUILD_TARGETS "cxxabi_static")
+ if (LIBCXXABI_INSTALL_STATIC_LIBRARY)
+ list(APPEND LIBCXXABI_INSTALL_TARGETS "cxxabi_static")
+ endif()
endif()
# Add a meta-target for both libraries.
-add_custom_target(cxxabi DEPENDS ${LIBCXXABI_TARGETS})
+add_custom_target(cxxabi DEPENDS ${LIBCXXABI_BUILD_TARGETS})
if (LIBCXXABI_INSTALL_LIBRARY)
- install(TARGETS ${LIBCXXABI_TARGETS}
+ install(TARGETS ${LIBCXXABI_INSTALL_TARGETS}
LIBRARY DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi
ARCHIVE DESTINATION ${LIBCXXABI_INSTALL_PREFIX}lib${LIBCXXABI_LIBDIR_SUFFIX} COMPONENT cxxabi
)
diff --git a/lib/libcxxabi/src/cxa_default_handlers.cpp b/lib/libcxxabi/src/cxa_default_handlers.cpp
index f2e36b4bc83..0fa169f0640 100644
--- a/lib/libcxxabi/src/cxa_default_handlers.cpp
+++ b/lib/libcxxabi/src/cxa_default_handlers.cpp
@@ -18,7 +18,9 @@
#include "cxa_handlers.hpp"
#include "cxa_exception.hpp"
#include "private_typeinfo.h"
+#include "include/atomic_support.h"
+#if !defined(LIBCXXABI_SILENT_TERMINATE)
static const char* cause = "uncaught";
__attribute__((noreturn))
@@ -84,7 +86,6 @@ static void demangling_unexpected_handler()
std::terminate();
}
-#if !defined(LIBCXXABI_SILENT_TERMINATE)
static std::terminate_handler default_terminate_handler = demangling_terminate_handler;
static std::terminate_handler default_unexpected_handler = demangling_unexpected_handler;
#else
@@ -101,10 +102,6 @@ std::terminate_handler __cxa_terminate_handler = default_terminate_handler;
_LIBCXXABI_DATA_VIS
std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler;
-// In the future these will become:
-// std::atomic<std::terminate_handler> __cxa_terminate_handler(default_terminate_handler);
-// std::atomic<std::unexpected_handler> __cxa_unexpected_handler(default_unexpected_handler);
-
namespace std
{
@@ -113,10 +110,8 @@ set_unexpected(unexpected_handler func) _NOEXCEPT
{
if (func == 0)
func = default_unexpected_handler;
- return __atomic_exchange_n(&__cxa_unexpected_handler, func,
- __ATOMIC_ACQ_REL);
-// Using of C++11 atomics this should be rewritten
-// return __cxa_unexpected_handler.exchange(func, memory_order_acq_rel);
+ return __libcpp_atomic_exchange(&__cxa_unexpected_handler, func,
+ _AO_Acq_Rel);
}
terminate_handler
@@ -124,10 +119,8 @@ set_terminate(terminate_handler func) _NOEXCEPT
{
if (func == 0)
func = default_terminate_handler;
- return __atomic_exchange_n(&__cxa_terminate_handler, func,
- __ATOMIC_ACQ_REL);
-// Using of C++11 atomics this should be rewritten
-// return __cxa_terminate_handler.exchange(func, memory_order_acq_rel);
+ return __libcpp_atomic_exchange(&__cxa_terminate_handler, func,
+ _AO_Acq_Rel);
}
}
diff --git a/lib/libcxxabi/src/cxa_demangle.cpp b/lib/libcxxabi/src/cxa_demangle.cpp
index 9cfd99607bf..1007d7efaef 100644
--- a/lib/libcxxabi/src/cxa_demangle.cpp
+++ b/lib/libcxxabi/src/cxa_demangle.cpp
@@ -9,168 +9,32 @@
// FIXME: (possibly) incomplete list of features that clang mangles that this
// file does not yet support:
-// - enable_if attribute
-// - decomposition declarations
// - C++ modules TS
#define _LIBCPP_NO_EXCEPTIONS
#include "__cxxabi_config.h"
-#include <vector>
-#include <algorithm>
-#include <numeric>
+#include "demangle/Compiler.h"
+#include "demangle/StringView.h"
+#include "demangle/Utility.h"
+
+#include <cassert>
+#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <cctype>
-
-#ifdef _MSC_VER
-// snprintf is implemented in VS 2015
-#if _MSC_VER < 1900
-#define snprintf _snprintf_s
-#endif
-#endif
-
-namespace __cxxabiv1
-{
-
-namespace
-{
-
-enum
-{
- unknown_error = -4,
- invalid_args = -3,
- invalid_mangled_name,
- memory_alloc_failure,
- success
-};
-
-class StringView {
- const char *First;
- const char *Last;
-
-public:
- template <size_t N>
- StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
- StringView(const char *First_, const char *Last_) : First(First_), Last(Last_) {}
- StringView() : First(nullptr), Last(nullptr) {}
-
- StringView substr(size_t From, size_t To) {
- if (To >= size())
- To = size() - 1;
- if (From >= size())
- From = size() - 1;
- return StringView(First + From, First + To);
- }
-
- StringView dropFront(size_t N) const {
- if (N >= size())
- N = size() - 1;
- return StringView(First + N, Last);
- }
-
- bool startsWith(StringView Str) const {
- if (Str.size() > size())
- return false;
- return std::equal(Str.begin(), Str.end(), begin());
- }
-
- const char &operator[](size_t Idx) const { return *(begin() + Idx); }
-
- const char *begin() const { return First; }
- const char *end() const { return Last; }
- size_t size() const { return static_cast<size_t>(Last - First); }
-};
-
-bool operator==(const StringView &LHS, const StringView &RHS) {
- return LHS.size() == RHS.size() &&
- std::equal(LHS.begin(), LHS.end(), RHS.begin());
-}
-
-// Stream that AST nodes write their string representation into after the AST
-// has been parsed.
-class OutputStream {
- char *Buffer;
- size_t CurrentPosition;
- size_t BufferCapacity;
-
- // Ensure there is at least n more positions in buffer.
- void grow(size_t N) {
- if (N + CurrentPosition >= BufferCapacity) {
- BufferCapacity *= 2;
- if (BufferCapacity < N + CurrentPosition)
- BufferCapacity = N + CurrentPosition;
- Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
- }
- }
-
-public:
- OutputStream(char *StartBuf, size_t Size)
- : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
-
- OutputStream &operator+=(StringView R) {
- size_t Size = R.size();
- if (Size == 0)
- return *this;
- grow(Size);
- memmove(Buffer + CurrentPosition, R.begin(), Size);
- CurrentPosition += Size;
- return *this;
- }
-
- OutputStream &operator+=(char C) {
- grow(1);
- Buffer[CurrentPosition++] = C;
- return *this;
- }
-
- // Offset of position in buffer, used for building stream_string_view.
- typedef unsigned StreamPosition;
-
- // StringView into a stream, used for caching the ast nodes.
- class StreamStringView {
- StreamPosition First, Last;
-
- friend class OutputStream;
-
- public:
- StreamStringView() : First(0), Last(0) {}
-
- StreamStringView(StreamPosition First_, StreamPosition Last_)
- : First(First_), Last(Last_) {}
-
- bool empty() const { return First == Last; }
- };
-
- OutputStream &operator+=(StreamStringView &s) {
- size_t Sz = static_cast<size_t>(s.Last - s.First);
- if (Sz == 0)
- return *this;
- grow(Sz);
- memmove(Buffer + CurrentPosition, Buffer + s.First, Sz);
- CurrentPosition += Sz;
- return *this;
- }
-
- StreamPosition getCurrentPosition() const {
- return static_cast<StreamPosition>(CurrentPosition);
- }
-
- StreamStringView makeStringViewFromPastPosition(StreamPosition Pos) {
- return StreamStringView(Pos, getCurrentPosition());
- }
-
- char back() const {
- return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
- }
-
- bool empty() const { return CurrentPosition == 0; }
+#include <numeric>
+#include <utility>
+#include <vector>
- char *getBuffer() { return Buffer; }
- char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
- size_t getBufferCapacity() { return BufferCapacity; }
+namespace {
+enum : int {
+ demangle_unknown_error = -4,
+ demangle_invalid_args = -3,
+ demangle_invalid_mangled_name = -2,
+ demangle_memory_alloc_failure = -1,
+ demangle_success = 0,
};
// Base class of all AST nodes. The AST is built by the parser, then is
@@ -178,30 +42,37 @@ public:
class Node {
public:
enum Kind : unsigned char {
+ KNodeArrayNode,
KDotSuffix,
KVendorExtQualType,
KQualType,
KConversionOperatorType,
KPostfixQualifiedType,
+ KElaboratedTypeSpefType,
KNameType,
KAbiTagAttr,
+ KEnableIfAttr,
KObjCProtoName,
KPointerType,
- KLValueReferenceType,
- KRValueReferenceType,
+ KReferenceType,
KPointerToMemberType,
KArrayType,
KFunctionType,
- KTopLevelFunctionDecl,
- KFunctionQualType,
- KFunctionRefQualType,
+ KNoexceptSpec,
+ KDynamicExceptionSpec,
+ KFunctionEncoding,
KLiteralOperator,
KSpecialName,
KCtorVtableSpecialName,
KQualifiedName,
- KEmptyName,
+ KNestedName,
+ KLocalName,
KVectorType,
- KTemplateParams,
+ KParameterPack,
+ KTemplateArgumentPack,
+ KParameterPackExpansion,
+ KTemplateArgs,
+ KForwardTemplateReference,
KNameWithTemplateArgs,
KGlobalQualifiedName,
KStdQualifiedName,
@@ -210,32 +81,70 @@ public:
KCtorDtorName,
KDtorName,
KUnnamedTypeName,
- KLambdaTypeName,
+ KClosureTypeName,
+ KStructuredBindingName,
KExpr,
+ KBracedExpr,
+ KBracedRangeExpr,
};
- const Kind K;
+ Kind K;
-private:
- // If this Node has any RHS part, potentally many Nodes further down.
- const unsigned HasRHSComponent : 1;
- const unsigned HasFunction : 1;
- const unsigned HasArray : 1;
+ /// Three-way bool to track a cached value. Unknown is possible if this node
+ /// has an unexpanded parameter pack below it that may affect this cache.
+ enum class Cache : unsigned char { Yes, No, Unknown, };
-public:
- Node(Kind K_, bool HasRHS_ = false, bool HasFunction_ = false,
- bool HasArray_ = false)
- : K(K_), HasRHSComponent(HasRHS_), HasFunction(HasFunction_),
- HasArray(HasArray_) {}
+ /// Tracks if this node has a component on its right side, in which case we
+ /// need to call printRight.
+ Cache RHSComponentCache;
+
+ /// Track if this node is a (possibly qualified) array type. This can affect
+ /// how we format the output string.
+ Cache ArrayCache;
+
+ /// Track if this node is a (possibly qualified) function type. This can
+ /// affect how we format the output string.
+ Cache FunctionCache;
+
+ Node(Kind K_, Cache RHSComponentCache_ = Cache::No,
+ Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No)
+ : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_),
+ FunctionCache(FunctionCache_) {}
- bool hasRHSComponent() const { return HasRHSComponent; }
- bool hasArray() const { return HasArray; }
- bool hasFunction() const { return HasFunction; }
+ bool hasRHSComponent(OutputStream &S) const {
+ if (RHSComponentCache != Cache::Unknown)
+ return RHSComponentCache == Cache::Yes;
+ return hasRHSComponentSlow(S);
+ }
+
+ bool hasArray(OutputStream &S) const {
+ if (ArrayCache != Cache::Unknown)
+ return ArrayCache == Cache::Yes;
+ return hasArraySlow(S);
+ }
- void print(OutputStream &s) const {
- printLeft(s);
- if (hasRHSComponent())
- printRight(s);
+ bool hasFunction(OutputStream &S) const {
+ if (FunctionCache != Cache::Unknown)
+ return FunctionCache == Cache::Yes;
+ return hasFunctionSlow(S);
+ }
+
+ Kind getKind() const { return K; }
+
+ virtual bool hasRHSComponentSlow(OutputStream &) const { return false; }
+ virtual bool hasArraySlow(OutputStream &) const { return false; }
+ virtual bool hasFunctionSlow(OutputStream &) const { return false; }
+
+ // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to
+ // get at a node that actually represents some concrete syntax.
+ virtual const Node *getSyntaxNode(OutputStream &) const {
+ return this;
+ }
+
+ void print(OutputStream &S) const {
+ printLeft(S);
+ if (RHSComponentCache != Cache::No)
+ printRight(S);
}
// Print the "left" side of this Node into OutputStream.
@@ -244,13 +153,24 @@ public:
// Print the "right". This distinction is necessary to represent C++ types
// that appear on the RHS of their subtype, such as arrays or functions.
// Since most types don't have such a component, provide a default
- // implemenation.
+ // implementation.
virtual void printRight(OutputStream &) const {}
virtual StringView getBaseName() const { return StringView(); }
// Silence compiler warnings, this dtor will never be called.
virtual ~Node() = default;
+
+#ifndef NDEBUG
+ DUMP_METHOD void dump() const {
+ char *Buffer = static_cast<char*>(std::malloc(1024));
+ OutputStream S(Buffer, 1024);
+ print(S);
+ S += '\0';
+ printf("Symbol dump for %p: %s\n", (const void*)this, S.getBuffer());
+ std::free(S.getBuffer());
+ }
+#endif
};
class NodeArray {
@@ -258,22 +178,47 @@ class NodeArray {
size_t NumElements;
public:
- NodeArray() : NumElements(0) {}
+ NodeArray() : Elements(nullptr), NumElements(0) {}
NodeArray(Node **Elements_, size_t NumElements_)
: Elements(Elements_), NumElements(NumElements_) {}
bool empty() const { return NumElements == 0; }
size_t size() const { return NumElements; }
- void printWithSeperator(OutputStream &S, StringView Seperator) const {
+ Node **begin() const { return Elements; }
+ Node **end() const { return Elements + NumElements; }
+
+ Node *operator[](size_t Idx) const { return Elements[Idx]; }
+
+ void printWithComma(OutputStream &S) const {
+ bool FirstElement = true;
for (size_t Idx = 0; Idx != NumElements; ++Idx) {
- if (Idx)
- S += Seperator;
+ size_t BeforeComma = S.getCurrentPosition();
+ if (!FirstElement)
+ S += ", ";
+ size_t AfterComma = S.getCurrentPosition();
Elements[Idx]->print(S);
+
+ // Elements[Idx] is an empty parameter pack expansion, we should erase the
+ // comma we just printed.
+ if (AfterComma == S.getCurrentPosition()) {
+ S.setCurrentPosition(BeforeComma);
+ continue;
+ }
+
+ FirstElement = false;
}
}
};
+struct NodeArrayNode : Node {
+ NodeArray Array;
+ NodeArrayNode(NodeArray Array_) : Node(KNodeArrayNode), Array(Array_) {}
+ void printLeft(OutputStream &S) const override {
+ Array.printWithComma(S);
+ }
+};
+
class DotSuffix final : public Node {
const Node *Prefix;
const StringView Suffix;
@@ -291,20 +236,24 @@ public:
};
class VendorExtQualType final : public Node {
- const Node *Ext;
const Node *Ty;
+ StringView Ext;
public:
- VendorExtQualType(Node *Ext_, Node *Ty_)
- : Node(KVendorExtQualType), Ext(Ext_), Ty(Ty_) {}
+ VendorExtQualType(Node *Ty_, StringView Ext_)
+ : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {}
void printLeft(OutputStream &S) const override {
- Ext->print(S);
+ Ty->print(S);
S += " ";
- Ty->printLeft(S);
+ S += Ext;
}
+};
- void printRight(OutputStream &S) const override { Ty->printRight(S); }
+enum FunctionRefQual : unsigned char {
+ FrefQualNone,
+ FrefQualLValue,
+ FrefQualRValue,
};
enum Qualifiers {
@@ -334,14 +283,19 @@ protected:
public:
QualType(Node *Child_, Qualifiers Quals_)
- : Node(KQualType, Child_->hasRHSComponent(), Child_->hasFunction(),
- Child_->hasArray()),
+ : Node(KQualType, Child_->RHSComponentCache,
+ Child_->ArrayCache, Child_->FunctionCache),
Quals(Quals_), Child(Child_) {}
- QualType(Node::Kind ChildKind_, Node *Child_, Qualifiers Quals_)
- : Node(ChildKind_, Child_->hasRHSComponent(), Child_->hasFunction(),
- Child_->hasArray()),
- Quals(Quals_), Child(Child_) {}
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return Child->hasRHSComponent(S);
+ }
+ bool hasArraySlow(OutputStream &S) const override {
+ return Child->hasArray(S);
+ }
+ bool hasFunctionSlow(OutputStream &S) const override {
+ return Child->hasFunction(S);
+ }
void printLeft(OutputStream &S) const override {
Child->printLeft(S);
@@ -355,7 +309,8 @@ class ConversionOperatorType final : public Node {
const Node *Ty;
public:
- ConversionOperatorType(Node *Ty_) : Node(KConversionOperatorType), Ty(Ty_) {}
+ ConversionOperatorType(Node *Ty_)
+ : Node(KConversionOperatorType), Ty(Ty_) {}
void printLeft(OutputStream &S) const override {
S += "operator ";
@@ -375,8 +330,6 @@ public:
Ty->printLeft(s);
s += Postfix;
}
-
- void printRight(OutputStream &S) const override { Ty->printRight(S); }
};
class NameType final : public Node {
@@ -391,12 +344,28 @@ public:
void printLeft(OutputStream &s) const override { s += Name; }
};
-class AbiTagAttr final : public Node {
- const Node* Base;
- StringView Tag;
+class ElaboratedTypeSpefType : public Node {
+ StringView Kind;
+ Node *Child;
public:
- AbiTagAttr(const Node* Base_, StringView Tag_)
- : Node(KAbiTagAttr), Base(Base_), Tag(Tag_) {}
+ ElaboratedTypeSpefType(StringView Kind_, Node *Child_)
+ : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {}
+
+ void printLeft(OutputStream &S) const override {
+ S += Kind;
+ S += ' ';
+ Child->print(S);
+ }
+};
+
+struct AbiTagAttr : Node {
+ Node *Base;
+ StringView Tag;
+
+ AbiTagAttr(Node* Base_, StringView Tag_)
+ : Node(KAbiTagAttr, Base_->RHSComponentCache,
+ Base_->ArrayCache, Base_->FunctionCache),
+ Base(Base_), Tag(Tag_) {}
void printLeft(OutputStream &S) const override {
Base->printLeft(S);
@@ -406,25 +375,38 @@ public:
}
};
+class EnableIfAttr : public Node {
+ NodeArray Conditions;
+public:
+ EnableIfAttr(NodeArray Conditions_)
+ : Node(KEnableIfAttr), Conditions(Conditions_) {}
+
+ void printLeft(OutputStream &S) const override {
+ S += " [enable_if:";
+ Conditions.printWithComma(S);
+ S += ']';
+ }
+};
+
class ObjCProtoName : public Node {
Node *Ty;
- Node *Protocol;
+ StringView Protocol;
friend class PointerType;
public:
- ObjCProtoName(Node *Ty_, Node *Protocol_)
+ ObjCProtoName(Node *Ty_, StringView Protocol_)
: Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {}
bool isObjCObject() const {
- return Ty->K == KNameType &&
+ return Ty->getKind() == KNameType &&
static_cast<NameType *>(Ty)->getName() == "objc_object";
}
void printLeft(OutputStream &S) const override {
- Ty->printLeft(S);
+ Ty->print(S);
S += "<";
- Protocol->printLeft(S);
+ S += Protocol;
S += ">";
}
};
@@ -434,82 +416,99 @@ class PointerType final : public Node {
public:
PointerType(Node *Pointee_)
- : Node(KPointerType, Pointee_->hasRHSComponent()), Pointee(Pointee_) {}
+ : Node(KPointerType, Pointee_->RHSComponentCache),
+ Pointee(Pointee_) {}
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return Pointee->hasRHSComponent(S);
+ }
void printLeft(OutputStream &s) const override {
// We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>.
- if (Pointee->K != KObjCProtoName ||
+ if (Pointee->getKind() != KObjCProtoName ||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
Pointee->printLeft(s);
- if (Pointee->hasArray())
+ if (Pointee->hasArray(s))
s += " ";
- if (Pointee->hasArray() || Pointee->hasFunction())
+ if (Pointee->hasArray(s) || Pointee->hasFunction(s))
s += "(";
s += "*";
} else {
const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee);
s += "id<";
- objcProto->Protocol->print(s);
+ s += objcProto->Protocol;
s += ">";
}
}
void printRight(OutputStream &s) const override {
- if (Pointee->K != KObjCProtoName ||
+ if (Pointee->getKind() != KObjCProtoName ||
!static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) {
- if (Pointee->hasArray() || Pointee->hasFunction())
+ if (Pointee->hasArray(s) || Pointee->hasFunction(s))
s += ")";
Pointee->printRight(s);
}
}
};
-class LValueReferenceType final : public Node {
- const Node *Pointee;
-
-public:
- LValueReferenceType(Node *Pointee_)
- : Node(KLValueReferenceType, Pointee_->hasRHSComponent()),
- Pointee(Pointee_) {}
-
- void printLeft(OutputStream &s) const override {
- Pointee->printLeft(s);
- if (Pointee->hasArray())
- s += " ";
- if (Pointee->hasArray() || Pointee->hasFunction())
- s += "(&";
- else
- s += "&";
- }
- void printRight(OutputStream &s) const override {
- if (Pointee->hasArray() || Pointee->hasFunction())
- s += ")";
- Pointee->printRight(s);
- }
+enum class ReferenceKind {
+ LValue,
+ RValue,
};
-class RValueReferenceType final : public Node {
+// Represents either a LValue or an RValue reference type.
+class ReferenceType : public Node {
const Node *Pointee;
+ ReferenceKind RK;
+
+ mutable bool Printing = false;
+
+ // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The
+ // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any
+ // other combination collapses to a lvalue ref.
+ std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const {
+ auto SoFar = std::make_pair(RK, Pointee);
+ for (;;) {
+ const Node *SN = SoFar.second->getSyntaxNode(S);
+ if (SN->getKind() != KReferenceType)
+ break;
+ auto *RT = static_cast<const ReferenceType *>(SN);
+ SoFar.second = RT->Pointee;
+ SoFar.first = std::min(SoFar.first, RT->RK);
+ }
+ return SoFar;
+ }
public:
- RValueReferenceType(Node *Pointee_)
- : Node(KRValueReferenceType, Pointee_->hasRHSComponent()),
- Pointee(Pointee_) {}
+ ReferenceType(Node *Pointee_, ReferenceKind RK_)
+ : Node(KReferenceType, Pointee_->RHSComponentCache),
+ Pointee(Pointee_), RK(RK_) {}
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return Pointee->hasRHSComponent(S);
+ }
void printLeft(OutputStream &s) const override {
- Pointee->printLeft(s);
- if (Pointee->hasArray())
+ if (Printing)
+ return;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
+ Collapsed.second->printLeft(s);
+ if (Collapsed.second->hasArray(s))
s += " ";
- if (Pointee->hasArray() || Pointee->hasFunction())
- s += "(&&";
- else
- s += "&&";
- }
+ if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
+ s += "(";
+ s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&");
+ }
void printRight(OutputStream &s) const override {
- if (Pointee->hasArray() || Pointee->hasFunction())
+ if (Printing)
+ return;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ std::pair<ReferenceKind, const Node *> Collapsed = collapse(s);
+ if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s))
s += ")";
- Pointee->printRight(s);
+ Collapsed.second->printRight(s);
}
};
@@ -519,12 +518,16 @@ class PointerToMemberType final : public Node {
public:
PointerToMemberType(Node *ClassType_, Node *MemberType_)
- : Node(KPointerToMemberType, MemberType_->hasRHSComponent()),
+ : Node(KPointerToMemberType, MemberType_->RHSComponentCache),
ClassType(ClassType_), MemberType(MemberType_) {}
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ return MemberType->hasRHSComponent(S);
+ }
+
void printLeft(OutputStream &s) const override {
MemberType->printLeft(s);
- if (MemberType->hasArray() || MemberType->hasFunction())
+ if (MemberType->hasArray(s) || MemberType->hasFunction(s))
s += "(";
else
s += " ";
@@ -533,7 +536,7 @@ public:
}
void printRight(OutputStream &s) const override {
- if (MemberType->hasArray() || MemberType->hasFunction())
+ if (MemberType->hasArray(s) || MemberType->hasFunction(s))
s += ")";
MemberType->printRight(s);
}
@@ -581,10 +584,20 @@ class ArrayType final : public Node {
public:
ArrayType(Node *Base_, NodeOrString Dimension_)
- : Node(KArrayType, true, false, true), Base(Base_), Dimension(Dimension_) {}
+ : Node(KArrayType,
+ /*RHSComponentCache=*/Cache::Yes,
+ /*ArrayCache=*/Cache::Yes),
+ Base(Base_), Dimension(Dimension_) {}
// Incomplete array type.
- ArrayType(Node *Base_) : Node(KArrayType, true, false, true), Base(Base_) {}
+ ArrayType(Node *Base_)
+ : Node(KArrayType,
+ /*RHSComponentCache=*/Cache::Yes,
+ /*ArrayCache=*/Cache::Yes),
+ Base(Base_) {}
+
+ bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+ bool hasArraySlow(OutputStream &) const override { return true; }
void printLeft(OutputStream &S) const override { Base->printLeft(S); }
@@ -604,12 +617,23 @@ public:
class FunctionType final : public Node {
Node *Ret;
NodeArray Params;
+ Qualifiers CVQuals;
+ FunctionRefQual RefQual;
+ Node *ExceptionSpec;
public:
- FunctionType(Node *Ret_, NodeArray Params_)
- : Node(KFunctionType, true, true), Ret(Ret_), Params(Params_) {}
-
- // Handle C++'s ... quirky decl grammer by using the left & right
+ FunctionType(Node *Ret_, NodeArray Params_, Qualifiers CVQuals_,
+ FunctionRefQual RefQual_, Node *ExceptionSpec_)
+ : Node(KFunctionType,
+ /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+ /*FunctionCache=*/Cache::Yes),
+ Ret(Ret_), Params(Params_), CVQuals(CVQuals_), RefQual(RefQual_),
+ ExceptionSpec(ExceptionSpec_) {}
+
+ bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+ bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+ // Handle C++'s ... quirky decl grammar by using the left & right
// distinction. Consider:
// int (*f(float))(char) {}
// f is a function that takes a float and returns a pointer to a function
@@ -623,26 +647,85 @@ public:
void printRight(OutputStream &S) const override {
S += "(";
- Params.printWithSeperator(S, ", ");
+ Params.printWithComma(S);
S += ")";
Ret->printRight(S);
+
+ if (CVQuals & QualConst)
+ S += " const";
+ if (CVQuals & QualVolatile)
+ S += " volatile";
+ if (CVQuals & QualRestrict)
+ S += " restrict";
+
+ if (RefQual == FrefQualLValue)
+ S += " &";
+ else if (RefQual == FrefQualRValue)
+ S += " &&";
+
+ if (ExceptionSpec != nullptr) {
+ S += ' ';
+ ExceptionSpec->print(S);
+ }
}
};
-class TopLevelFunctionDecl final : public Node {
- const Node *Ret;
- const Node *Name;
+class NoexceptSpec : public Node {
+ Node *E;
+public:
+ NoexceptSpec(Node *E_) : Node(KNoexceptSpec), E(E_) {}
+
+ void printLeft(OutputStream &S) const override {
+ S += "noexcept(";
+ E->print(S);
+ S += ")";
+ }
+};
+
+class DynamicExceptionSpec : public Node {
+ NodeArray Types;
+public:
+ DynamicExceptionSpec(NodeArray Types_)
+ : Node(KDynamicExceptionSpec), Types(Types_) {}
+
+ void printLeft(OutputStream &S) const override {
+ S += "throw(";
+ Types.printWithComma(S);
+ S += ')';
+ }
+};
+
+class FunctionEncoding final : public Node {
+ Node *Ret;
+ Node *Name;
NodeArray Params;
+ Node *Attrs;
+ Qualifiers CVQuals;
+ FunctionRefQual RefQual;
public:
- TopLevelFunctionDecl(Node *Ret_, Node *Name_, NodeArray Params_)
- : Node(KTopLevelFunctionDecl, true, true), Ret(Ret_), Name(Name_),
- Params(Params_) {}
+ FunctionEncoding(Node *Ret_, Node *Name_, NodeArray Params_,
+ Node *Attrs_, Qualifiers CVQuals_, FunctionRefQual RefQual_)
+ : Node(KFunctionEncoding,
+ /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::No,
+ /*FunctionCache=*/Cache::Yes),
+ Ret(Ret_), Name(Name_), Params(Params_), Attrs(Attrs_),
+ CVQuals(CVQuals_), RefQual(RefQual_) {}
+
+ Qualifiers getCVQuals() const { return CVQuals; }
+ FunctionRefQual getRefQual() const { return RefQual; }
+ NodeArray getParams() const { return Params; }
+ Node *getReturnType() const { return Ret; }
+
+ bool hasRHSComponentSlow(OutputStream &) const override { return true; }
+ bool hasFunctionSlow(OutputStream &) const override { return true; }
+
+ Node *getName() { return const_cast<Node *>(Name); }
void printLeft(OutputStream &S) const override {
if (Ret) {
Ret->printLeft(S);
- if (!Ret->hasRHSComponent())
+ if (!Ret->hasRHSComponent(S))
S += " ";
}
Name->print(S);
@@ -650,61 +733,25 @@ public:
void printRight(OutputStream &S) const override {
S += "(";
- Params.printWithSeperator(S, ", ");
+ Params.printWithComma(S);
S += ")";
if (Ret)
Ret->printRight(S);
- }
-};
-enum FunctionRefQual : unsigned char {
- FrefQualNone,
- FrefQualLValue,
- FrefQualRValue,
-};
-
-class FunctionRefQualType : public Node {
- Node *Fn;
- FunctionRefQual Quals;
-
- friend class FunctionQualType;
-
-public:
- FunctionRefQualType(Node *Fn_, FunctionRefQual Quals_)
- : Node(KFunctionRefQualType, true, true), Fn(Fn_), Quals(Quals_) {}
+ if (CVQuals & QualConst)
+ S += " const";
+ if (CVQuals & QualVolatile)
+ S += " volatile";
+ if (CVQuals & QualRestrict)
+ S += " restrict";
- void printQuals(OutputStream &S) const {
- if (Quals == FrefQualLValue)
+ if (RefQual == FrefQualLValue)
S += " &";
- else
+ else if (RefQual == FrefQualRValue)
S += " &&";
- }
-
- void printLeft(OutputStream &S) const override { Fn->printLeft(S); }
- void printRight(OutputStream &S) const override {
- Fn->printRight(S);
- printQuals(S);
- }
-};
-
-class FunctionQualType final : public QualType {
-public:
- FunctionQualType(Node *Child_, Qualifiers Quals_)
- : QualType(KFunctionQualType, Child_, Quals_) {}
-
- void printLeft(OutputStream &S) const override { Child->printLeft(S); }
-
- void printRight(OutputStream &S) const override {
- if (Child->K == KFunctionRefQualType) {
- auto *RefQuals = static_cast<const FunctionRefQualType *>(Child);
- RefQuals->Fn->printRight(S);
- printQuals(S);
- RefQuals->printQuals(S);
- } else {
- Child->printRight(S);
- printQuals(S);
- }
+ if (Attrs != nullptr)
+ Attrs->print(S);
}
};
@@ -725,7 +772,7 @@ class SpecialName final : public Node {
const Node *Child;
public:
- SpecialName(StringView Special_, Node *Child_)
+ SpecialName(StringView Special_, Node* Child_)
: Node(KSpecialName), Special(Special_), Child(Child_) {}
void printLeft(OutputStream &S) const override {
@@ -740,8 +787,8 @@ class CtorVtableSpecialName final : public Node {
public:
CtorVtableSpecialName(Node *FirstType_, Node *SecondType_)
- : Node(KCtorVtableSpecialName), FirstType(FirstType_),
- SecondType(SecondType_) {}
+ : Node(KCtorVtableSpecialName),
+ FirstType(FirstType_), SecondType(SecondType_) {}
void printLeft(OutputStream &S) const override {
S += "construction vtable for ";
@@ -751,41 +798,54 @@ public:
}
};
+struct NestedName : Node {
+ Node *Qual;
+ Node *Name;
+
+ NestedName(Node *Qual_, Node *Name_)
+ : Node(KNestedName), Qual(Qual_), Name(Name_) {}
+
+ StringView getBaseName() const override { return Name->getBaseName(); }
+
+ void printLeft(OutputStream &S) const override {
+ Qual->print(S);
+ S += "::";
+ Name->print(S);
+ }
+};
+
+struct LocalName : Node {
+ Node *Encoding;
+ Node *Entity;
+
+ LocalName(Node *Encoding_, Node *Entity_)
+ : Node(KLocalName), Encoding(Encoding_), Entity(Entity_) {}
+
+ void printLeft(OutputStream &S) const override {
+ Encoding->print(S);
+ S += "::";
+ Entity->print(S);
+ }
+};
+
class QualifiedName final : public Node {
// qualifier::name
const Node *Qualifier;
const Node *Name;
- mutable OutputStream::StreamStringView Cache;
-
public:
- QualifiedName(Node *Qualifier_, Node *Name_)
+ QualifiedName(Node* Qualifier_, Node* Name_)
: Node(KQualifiedName), Qualifier(Qualifier_), Name(Name_) {}
StringView getBaseName() const override { return Name->getBaseName(); }
void printLeft(OutputStream &S) const override {
- if (!Cache.empty()) {
- S += Cache;
- return;
- }
-
- OutputStream::StreamPosition Start = S.getCurrentPosition();
- if (Qualifier->K != KEmptyName) {
- Qualifier->print(S);
- S += "::";
- }
+ Qualifier->print(S);
+ S += "::";
Name->print(S);
- Cache = S.makeStringViewFromPastPosition(Start);
}
};
-class EmptyName : public Node {
-public:
- EmptyName() : Node(KEmptyName) {}
- void printLeft(OutputStream &) const override {}
-};
-
class VectorType final : public Node {
const Node *BaseType;
const NodeOrString Dimension;
@@ -796,8 +856,8 @@ public:
: Node(KVectorType), BaseType(nullptr), Dimension(Dimension_),
IsPixel(true) {}
VectorType(Node *BaseType_, NodeOrString Dimension_)
- : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_),
- IsPixel(false) {}
+ : Node(KVectorType), BaseType(BaseType_),
+ Dimension(Dimension_), IsPixel(false) {}
void printLeft(OutputStream &S) const override {
if (IsPixel) {
@@ -816,38 +876,215 @@ public:
}
};
-class TemplateParams final : public Node {
- NodeArray Params;
+/// An unexpanded parameter pack (either in the expression or type context). If
+/// this AST is correct, this node will have a ParameterPackExpansion node above
+/// it.
+///
+/// This node is created when some <template-args> are found that apply to an
+/// <encoding>, and is stored in the TemplateParams table. In order for this to
+/// appear in the final AST, it has to referenced via a <template-param> (ie,
+/// T_).
+class ParameterPack final : public Node {
+ NodeArray Data;
+
+ // Setup OutputStream for a pack expansion unless we're already expanding one.
+ void initializePackExpansion(OutputStream &S) const {
+ if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) {
+ S.CurrentPackMax = static_cast<unsigned>(Data.size());
+ S.CurrentPackIndex = 0;
+ }
+ }
+
+public:
+ ParameterPack(NodeArray Data_) : Node(KParameterPack), Data(Data_) {
+ ArrayCache = FunctionCache = RHSComponentCache = Cache::Unknown;
+ if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+ return P->ArrayCache == Cache::No;
+ }))
+ ArrayCache = Cache::No;
+ if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+ return P->FunctionCache == Cache::No;
+ }))
+ FunctionCache = Cache::No;
+ if (std::all_of(Data.begin(), Data.end(), [](Node* P) {
+ return P->RHSComponentCache == Cache::No;
+ }))
+ RHSComponentCache = Cache::No;
+ }
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasRHSComponent(S);
+ }
+ bool hasArraySlow(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasArray(S);
+ }
+ bool hasFunctionSlow(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() && Data[Idx]->hasFunction(S);
+ }
+ const Node *getSyntaxNode(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this;
+ }
+
+ void printLeft(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ if (Idx < Data.size())
+ Data[Idx]->printLeft(S);
+ }
+ void printRight(OutputStream &S) const override {
+ initializePackExpansion(S);
+ size_t Idx = S.CurrentPackIndex;
+ if (Idx < Data.size())
+ Data[Idx]->printRight(S);
+ }
+};
+
+/// A variadic template argument. This node represents an occurrence of
+/// J<something>E in some <template-args>. It isn't itself unexpanded, unless
+/// one of it's Elements is. The parser inserts a ParameterPack into the
+/// TemplateParams table if the <template-args> this pack belongs to apply to an
+/// <encoding>.
+class TemplateArgumentPack final : public Node {
+ NodeArray Elements;
+public:
+ TemplateArgumentPack(NodeArray Elements_)
+ : Node(KTemplateArgumentPack), Elements(Elements_) {}
+
+ NodeArray getElements() const { return Elements; }
+
+ void printLeft(OutputStream &S) const override {
+ Elements.printWithComma(S);
+ }
+};
- mutable OutputStream::StreamStringView Cache;
+/// A pack expansion. Below this node, there are some unexpanded ParameterPacks
+/// which each have Child->ParameterPackSize elements.
+class ParameterPackExpansion final : public Node {
+ const Node *Child;
public:
- TemplateParams(NodeArray Params_) : Node(KTemplateParams), Params(Params_) {}
+ ParameterPackExpansion(Node* Child_)
+ : Node(KParameterPackExpansion), Child(Child_) {}
+
+ const Node *getChild() const { return Child; }
void printLeft(OutputStream &S) const override {
- if (!Cache.empty()) {
- S += Cache;
+ constexpr unsigned Max = std::numeric_limits<unsigned>::max();
+ SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max);
+ SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max);
+ size_t StreamPos = S.getCurrentPosition();
+
+ // Print the first element in the pack. If Child contains a ParameterPack,
+ // it will set up S.CurrentPackMax and print the first element.
+ Child->print(S);
+
+ // No ParameterPack was found in Child. This can occur if we've found a pack
+ // expansion on a <function-param>.
+ if (S.CurrentPackMax == Max) {
+ S += "...";
return;
}
- OutputStream::StreamPosition Start = S.getCurrentPosition();
+ // We found a ParameterPack, but it has no elements. Erase whatever we may
+ // of printed.
+ if (S.CurrentPackMax == 0) {
+ S.setCurrentPosition(StreamPos);
+ return;
+ }
+ // Else, iterate through the rest of the elements in the pack.
+ for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) {
+ S += ", ";
+ S.CurrentPackIndex = I;
+ Child->print(S);
+ }
+ }
+};
+
+class TemplateArgs final : public Node {
+ NodeArray Params;
+
+public:
+ TemplateArgs(NodeArray Params_) : Node(KTemplateArgs), Params(Params_) {}
+
+ NodeArray getParams() { return Params; }
+
+ void printLeft(OutputStream &S) const override {
S += "<";
- Params.printWithSeperator(S, ", ");
+ Params.printWithComma(S);
if (S.back() == '>')
S += " ";
S += ">";
+ }
+};
- Cache = S.makeStringViewFromPastPosition(Start);
+struct ForwardTemplateReference : Node {
+ size_t Index;
+ Node *Ref = nullptr;
+
+ // If we're currently printing this node. It is possible (though invalid) for
+ // a forward template reference to refer to itself via a substitution. This
+ // creates a cyclic AST, which will stack overflow printing. To fix this, bail
+ // out if more than one print* function is active.
+ mutable bool Printing = false;
+
+ ForwardTemplateReference(size_t Index_)
+ : Node(KForwardTemplateReference, Cache::Unknown, Cache::Unknown,
+ Cache::Unknown),
+ Index(Index_) {}
+
+ bool hasRHSComponentSlow(OutputStream &S) const override {
+ if (Printing)
+ return false;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ return Ref->hasRHSComponent(S);
+ }
+ bool hasArraySlow(OutputStream &S) const override {
+ if (Printing)
+ return false;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ return Ref->hasArray(S);
+ }
+ bool hasFunctionSlow(OutputStream &S) const override {
+ if (Printing)
+ return false;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ return Ref->hasFunction(S);
+ }
+ const Node *getSyntaxNode(OutputStream &S) const override {
+ if (Printing)
+ return this;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ return Ref->getSyntaxNode(S);
+ }
+
+ void printLeft(OutputStream &S) const override {
+ if (Printing)
+ return;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ Ref->printLeft(S);
+ }
+ void printRight(OutputStream &S) const override {
+ if (Printing)
+ return;
+ SwapAndRestore<bool> SavePrinting(Printing, true);
+ Ref->printRight(S);
}
};
-class NameWithTemplateArgs final : public Node {
+struct NameWithTemplateArgs : Node {
// name<template_args>
Node *Name;
Node *TemplateArgs;
-public:
NameWithTemplateArgs(Node *Name_, Node *TemplateArgs_)
: Node(KNameWithTemplateArgs), Name(Name_), TemplateArgs(TemplateArgs_) {}
@@ -863,7 +1100,8 @@ class GlobalQualifiedName final : public Node {
Node *Child;
public:
- GlobalQualifiedName(Node *Child_) : Node(KGlobalQualifiedName), Child(Child_) {}
+ GlobalQualifiedName(Node* Child_)
+ : Node(KGlobalQualifiedName), Child(Child_) {}
StringView getBaseName() const override { return Child->getBaseName(); }
@@ -873,10 +1111,9 @@ public:
}
};
-class StdQualifiedName final : public Node {
+struct StdQualifiedName : Node {
Node *Child;
-public:
StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {}
StringView getBaseName() const override { return Child->getBaseName(); }
@@ -1034,27 +1271,40 @@ public:
}
};
-class LambdaTypeName : public Node {
+class ClosureTypeName : public Node {
NodeArray Params;
StringView Count;
public:
- LambdaTypeName(NodeArray Params_, StringView Count_)
- : Node(KLambdaTypeName), Params(Params_), Count(Count_) {}
+ ClosureTypeName(NodeArray Params_, StringView Count_)
+ : Node(KClosureTypeName), Params(Params_), Count(Count_) {}
void printLeft(OutputStream &S) const override {
S += "\'lambda";
S += Count;
S += "\'(";
- Params.printWithSeperator(S, ", ");
+ Params.printWithComma(S);
S += ")";
}
};
+class StructuredBindingName : public Node {
+ NodeArray Bindings;
+public:
+ StructuredBindingName(NodeArray Bindings_)
+ : Node(KStructuredBindingName), Bindings(Bindings_) {}
+
+ void printLeft(OutputStream &S) const override {
+ S += '[';
+ Bindings.printWithComma(S);
+ S += ']';
+ }
+};
+
// -- Expression Nodes --
struct Expr : public Node {
- Expr() : Node(KExpr) {}
+ Expr(Kind K = KExpr) : Node(K) {}
};
class BinaryExpr : public Expr {
@@ -1190,14 +1440,15 @@ public:
};
class SizeofParamPackExpr : public Expr {
- NodeArray Args;
+ Node *Pack;
public:
- SizeofParamPackExpr(NodeArray Args_) : Args(Args_) {}
+ SizeofParamPackExpr(Node *Pack_) : Pack(Pack_) {}
void printLeft(OutputStream &S) const override {
S += "sizeof...(";
- Args.printWithSeperator(S, ", ");
+ ParameterPackExpansion PPE(Pack);
+ PPE.printLeft(S);
S += ")";
}
};
@@ -1212,7 +1463,7 @@ public:
void printLeft(OutputStream &S) const override {
Callee->print(S);
S += "(";
- Args.printWithSeperator(S, ", ");
+ Args.printWithComma(S);
S += ")";
}
};
@@ -1227,8 +1478,8 @@ class NewExpr : public Expr {
public:
NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_,
bool IsArray_)
- : ExprList(ExprList_), Type(Type_), InitList(InitList_), IsGlobal(IsGlobal_),
- IsArray(IsArray_) {}
+ : ExprList(ExprList_), Type(Type_), InitList(InitList_),
+ IsGlobal(IsGlobal_), IsArray(IsArray_) {}
void printLeft(OutputStream &S) const override {
if (IsGlobal)
@@ -1236,17 +1487,19 @@ public:
S += "new";
if (IsArray)
S += "[]";
+ S += ' ';
if (!ExprList.empty()) {
S += "(";
- ExprList.printWithSeperator(S, ", ");
+ ExprList.printWithComma(S);
S += ")";
}
Type->print(S);
if (!InitList.empty()) {
S += "(";
- InitList.printWithSeperator(S, ", ");
+ InitList.printWithComma(S);
S += ")";
}
+
}
};
@@ -1296,33 +1549,127 @@ public:
}
};
-class ExprList : public Expr {
- NodeArray SubExprs;
+class ConversionExpr : public Expr {
+ const Node *Type;
+ NodeArray Expressions;
public:
- ExprList(NodeArray SubExprs_) : SubExprs(SubExprs_) {}
+ ConversionExpr(const Node *Type_, NodeArray Expressions_)
+ : Type(Type_), Expressions(Expressions_) {}
void printLeft(OutputStream &S) const override {
S += "(";
- SubExprs.printWithSeperator(S, ", ");
+ Type->print(S);
+ S += ")(";
+ Expressions.printWithComma(S);
S += ")";
}
};
-class ConversionExpr : public Expr {
- NodeArray Expressions;
- NodeArray Types;
+class InitListExpr : public Expr {
+ Node *Ty;
+ NodeArray Inits;
+public:
+ InitListExpr(Node *Ty_, NodeArray Inits_) : Ty(Ty_), Inits(Inits_) {}
+ void printLeft(OutputStream &S) const override {
+ if (Ty)
+ Ty->print(S);
+ S += '{';
+ Inits.printWithComma(S);
+ S += '}';
+ }
+};
+
+class BracedExpr : public Expr {
+ Node *Elem;
+ Node *Init;
+ bool IsArray;
public:
- ConversionExpr(NodeArray Expressions_, NodeArray Types_)
- : Expressions(Expressions_), Types(Types_) {}
+ BracedExpr(Node *Elem_, Node *Init_, bool IsArray_)
+ : Expr(KBracedExpr), Elem(Elem_), Init(Init_), IsArray(IsArray_) {}
void printLeft(OutputStream &S) const override {
- S += "(";
- Expressions.printWithSeperator(S, ", ");
- S += ")(";
- Types.printWithSeperator(S, ", ");
- S += ")";
+ if (IsArray) {
+ S += '[';
+ Elem->print(S);
+ S += ']';
+ } else {
+ S += '.';
+ Elem->print(S);
+ }
+ if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+ S += " = ";
+ Init->print(S);
+ }
+};
+
+class BracedRangeExpr : public Expr {
+ Node *First;
+ Node *Last;
+ Node *Init;
+public:
+ BracedRangeExpr(Node *First_, Node *Last_, Node *Init_)
+ : Expr(KBracedRangeExpr), First(First_), Last(Last_), Init(Init_) {}
+
+ void printLeft(OutputStream &S) const override {
+ S += '[';
+ First->print(S);
+ S += " ... ";
+ Last->print(S);
+ S += ']';
+ if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr)
+ S += " = ";
+ Init->print(S);
+ }
+};
+
+struct FoldExpr : Expr {
+ Node *Pack, *Init;
+ StringView OperatorName;
+ bool IsLeftFold;
+
+ FoldExpr(bool IsLeftFold_, StringView OperatorName_, Node *Pack_, Node *Init_)
+ : Pack(Pack_), Init(Init_), OperatorName(OperatorName_),
+ IsLeftFold(IsLeftFold_) {}
+
+ void printLeft(OutputStream &S) const override {
+ auto PrintPack = [&] {
+ S += '(';
+ ParameterPackExpansion(Pack).print(S);
+ S += ')';
+ };
+
+ S += '(';
+
+ if (IsLeftFold) {
+ // init op ... op pack
+ if (Init != nullptr) {
+ Init->print(S);
+ S += ' ';
+ S += OperatorName;
+ S += ' ';
+ }
+ // ... op pack
+ S += "... ";
+ S += OperatorName;
+ S += ' ';
+ PrintPack();
+ } else { // !IsLeftFold
+ // pack op ...
+ PrintPack();
+ S += ' ';
+ S += OperatorName;
+ S += " ...";
+ // pack op ... op init
+ if (Init != nullptr) {
+ S += ' ';
+ S += OperatorName;
+ S += ' ';
+ Init->print(S);
+ }
+ }
+ S += ')';
}
};
@@ -1355,7 +1702,8 @@ class IntegerCastExpr : public Expr {
StringView Integer;
public:
- IntegerCastExpr(Node *Ty_, StringView Integer_) : Ty(Ty_), Integer(Integer_) {}
+ IntegerCastExpr(Node *Ty_, StringView Integer_)
+ : Ty(Ty_), Integer(Integer_) {}
void printLeft(OutputStream &S) const override {
S += "(";
@@ -1438,17 +1786,21 @@ class BumpPointerAllocator {
static constexpr size_t AllocSize = 4096;
static constexpr size_t UsableAllocSize = AllocSize - sizeof(BlockMeta);
- alignas(16) char InitialBuffer[AllocSize];
+ alignas(long double) char InitialBuffer[AllocSize];
BlockMeta* BlockList = nullptr;
void grow() {
- char* NewMeta = new char[AllocSize];
+ char* NewMeta = static_cast<char *>(std::malloc(AllocSize));
+ if (NewMeta == nullptr)
+ std::terminate();
BlockList = new (NewMeta) BlockMeta{BlockList, 0};
}
void* allocateMassive(size_t NBytes) {
NBytes += sizeof(BlockMeta);
- BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(new char[NBytes]);
+ BlockMeta* NewMeta = reinterpret_cast<BlockMeta*>(std::malloc(NBytes));
+ if (NewMeta == nullptr)
+ std::terminate();
BlockList->Next = new (NewMeta) BlockMeta{BlockList->Next, 0};
return static_cast<void*>(NewMeta + 1);
}
@@ -1469,14 +1821,17 @@ public:
BlockList->Current - N);
}
- ~BumpPointerAllocator() {
+ void reset() {
while (BlockList) {
BlockMeta* Tmp = BlockList;
BlockList = BlockList->Next;
if (reinterpret_cast<char*>(Tmp) != InitialBuffer)
- delete[] reinterpret_cast<char*>(Tmp);
+ std::free(Tmp);
}
+ BlockList = new (InitialBuffer) BlockMeta{nullptr, 0};
}
+
+ ~BumpPointerAllocator() { reset(); }
};
template <class T, size_t N>
@@ -1501,10 +1856,15 @@ class PODSmallVector {
size_t S = size();
if (isInline()) {
auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T)));
+ if (Tmp == nullptr)
+ std::terminate();
std::copy(First, Last, Tmp);
First = Tmp;
- } else
+ } else {
First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T)));
+ if (First == nullptr)
+ std::terminate();
+ }
Last = First + S;
Cap = First + NewCap;
}
@@ -1593,1083 +1953,852 @@ public:
}
};
-// Substitution table. This type is used to track the substitutions that are
-// known by the parser.
-template <size_t Size>
-class SubstitutionTable {
- // Substitutions hold the actual entries in the table, and PackIndices tells
- // us which entries are members of which pack. For example, if the
- // substitutions we're tracking are: {int, {float, FooBar}, char}, with
- // {float, FooBar} being a parameter pack, we represent the substitutions as:
- // Substitutions: int, float, FooBar, char
- // PackIndices: 0, 1, 3
- // So, PackIndicies[I] holds the offset of the begin of the Ith pack, and
- // PackIndices[I + 1] holds the offset of the end.
- PODSmallVector<Node*, Size> Substitutions;
- PODSmallVector<unsigned, Size> PackIndices;
+struct Db {
+ const char *First;
+ const char *Last;
-public:
- // Add a substitution that represents a single name to the table. This is
- // modeled as a parameter pack with just one element.
- void pushSubstitution(Node* Entry) {
- pushPack();
- pushSubstitutionIntoPack(Entry);
+ // Name stack, this is used by the parser to hold temporary names that were
+ // parsed. The parser collapses multiple names into new nodes to construct
+ // the AST. Once the parser is finished, names.size() == 1.
+ PODSmallVector<Node *, 32> Names;
+
+ // Substitution table. Itanium supports name substitutions as a means of
+ // compression. The string "S42_" refers to the 44nd entry (base-36) in this
+ // table.
+ PODSmallVector<Node *, 32> Subs;
+
+ // Template parameter table. Like the above, but referenced like "T42_".
+ // This has a smaller size compared to Subs and Names because it can be
+ // stored on the stack.
+ PODSmallVector<Node *, 8> TemplateParams;
+
+ // Set of unresolved forward <template-param> references. These can occur in a
+ // conversion operator's type, and are resolved in the enclosing <encoding>.
+ PODSmallVector<ForwardTemplateReference *, 4> ForwardTemplateRefs;
+
+ bool TryToParseTemplateArgs = true;
+ bool PermitForwardTemplateReferences = false;
+ bool ParsingLambdaParams = false;
+
+ BumpPointerAllocator ASTAllocator;
+
+ Db(const char *First_, const char *Last_) : First(First_), Last(Last_) {}
+
+ void reset(const char *First_, const char *Last_) {
+ First = First_;
+ Last = Last_;
+ Names.clear();
+ Subs.clear();
+ TemplateParams.clear();
+ ParsingLambdaParams = false;
+ TryToParseTemplateArgs = true;
+ PermitForwardTemplateReferences = false;
+ ASTAllocator.reset();
}
- // Add a new empty pack to the table. Subsequent calls to
- // pushSubstitutionIntoPack() will add to this pack.
- void pushPack() {
- PackIndices.push_back(static_cast<unsigned>(Substitutions.size()));
- }
- void pushSubstitutionIntoPack(Node* Entry) {
- assert(!PackIndices.empty() && "No pack to push substitution into!");
- Substitutions.push_back(Entry);
+ template <class T, class... Args> T *make(Args &&... args) {
+ return new (ASTAllocator.allocate(sizeof(T)))
+ T(std::forward<Args>(args)...);
}
- // Remove the last pack from the table.
- void popPack() {
- unsigned Last = PackIndices.back();
- PackIndices.pop_back();
- Substitutions.dropBack(Last);
+ template <class It> NodeArray makeNodeArray(It begin, It end) {
+ size_t sz = static_cast<size_t>(end - begin);
+ void *mem = ASTAllocator.allocate(sizeof(Node *) * sz);
+ Node **data = new (mem) Node *[sz];
+ std::copy(begin, end, data);
+ return NodeArray(data, sz);
}
- // For use in a range-for loop.
- struct NodeRange {
- Node** First;
- Node** Last;
- Node** begin() { return First; }
- Node** end() { return Last; }
- };
-
- // Retrieve the Nth substitution. This is represented as a range, as the
- // substitution could be referring to a parameter pack.
- NodeRange nthSubstitution(size_t N) {
- assert(PackIndices[N] <= Substitutions.size());
- // The Nth parameter pack starts at offset PackIndices[N], and ends at
- // PackIndices[N + 1].
- Node** Begin = Substitutions.begin() + PackIndices[N];
- Node** End;
- if (N + 1 != PackIndices.size()) {
- assert(PackIndices[N + 1] <= Substitutions.size());
- End = Substitutions.begin() + PackIndices[N + 1];
- } else
- End = Substitutions.end();
- assert(Begin <= End);
- return NodeRange{Begin, End};
+ NodeArray popTrailingNodeArray(size_t FromPosition) {
+ assert(FromPosition <= Names.size());
+ NodeArray res =
+ makeNodeArray(Names.begin() + (long)FromPosition, Names.end());
+ Names.dropBack(FromPosition);
+ return res;
}
- size_t size() const { return PackIndices.size(); }
- bool empty() const { return PackIndices.empty(); }
- void clear() {
- Substitutions.clear();
- PackIndices.clear();
+ bool consumeIf(StringView S) {
+ if (StringView(First, Last).startsWith(S)) {
+ First += S.size();
+ return true;
+ }
+ return false;
}
-};
-struct Db
-{
- // Name stack, this is used by the parser to hold temporary names that were
- // parsed. The parser colapses multiple names into new nodes to construct
- // the AST. Once the parser is finished, names.size() == 1.
- PODSmallVector<Node*, 32> Names;
-
- // Substitution table. Itanium supports name substitutions as a means of
- // compression. The string "S42_" refers to the 42nd entry in this table.
- SubstitutionTable<32> Subs;
-
- // Template parameter table. Like the above, but referenced like "T42_".
- // This has a smaller size compared to Subs and Names because it can be
- // stored on the stack.
- SubstitutionTable<4> TemplateParams;
-
- Qualifiers CV = QualNone;
- FunctionRefQual RefQuals = FrefQualNone;
- unsigned EncodingDepth = 0;
- bool ParsedCtorDtorCV = false;
- bool TagTemplates = true;
- bool FixForwardReferences = false;
- bool TryToParseTemplateArgs = true;
-
- BumpPointerAllocator ASTAllocator;
-
- template <class T, class... Args> T* make(Args&& ...args)
- {
- return new (ASTAllocator.allocate(sizeof(T)))
- T(std::forward<Args>(args)...);
+ bool consumeIf(char C) {
+ if (First != Last && *First == C) {
+ ++First;
+ return true;
}
+ return false;
+ }
- template <class It> NodeArray makeNodeArray(It begin, It end)
- {
- size_t sz = static_cast<size_t>(end - begin);
- void* mem = ASTAllocator.allocate(sizeof(Node*) * sz);
- Node** data = new (mem) Node*[sz];
- std::copy(begin, end, data);
- return NodeArray(data, sz);
- }
+ char consume() { return First != Last ? *First++ : '\0'; }
- NodeArray popTrailingNodeArray(size_t FromPosition)
- {
- assert(FromPosition <= Names.size());
- NodeArray res = makeNodeArray(
- Names.begin() + (long)FromPosition, Names.end());
- Names.dropBack(FromPosition);
- return res;
- }
-};
-
-const char* parse_type(const char* first, const char* last, Db& db);
-const char* parse_encoding(const char* first, const char* last, Db& db);
-const char* parse_name(const char* first, const char* last, Db& db,
- bool* ends_with_template_args = 0);
-const char* parse_expression(const char* first, const char* last, Db& db);
-const char* parse_template_args(const char* first, const char* last, Db& db);
-const char* parse_operator_name(const char* first, const char* last, Db& db);
-const char* parse_unqualified_name(const char* first, const char* last, Db& db);
-const char* parse_decltype(const char* first, const char* last, Db& db);
+ char look(unsigned Lookahead = 0) {
+ if (static_cast<size_t>(Last - First) <= Lookahead)
+ return '\0';
+ return First[Lookahead];
+ }
-// <number> ::= [n] <non-negative decimal integer>
+ size_t numLeft() const { return static_cast<size_t>(Last - First); }
+
+ StringView parseNumber(bool AllowNegative = false);
+ Qualifiers parseCVQualifiers();
+ bool parsePositiveInteger(size_t *Out);
+ StringView parseBareSourceName();
+
+ bool parseSeqId(size_t *Out);
+ Node *parseSubstitution();
+ Node *parseTemplateParam();
+ Node *parseTemplateArgs(bool TagTemplates = false);
+ Node *parseTemplateArg();
+
+ /// Parse the <expr> production.
+ Node *parseExpr();
+ Node *parsePrefixExpr(StringView Kind);
+ Node *parseBinaryExpr(StringView Kind);
+ Node *parseIntegerLiteral(StringView Lit);
+ Node *parseExprPrimary();
+ template <class Float> Node *parseFloatingLiteral();
+ Node *parseFunctionParam();
+ Node *parseNewExpr();
+ Node *parseConversionExpr();
+ Node *parseBracedExpr();
+ Node *parseFoldExpr();
+
+ /// Parse the <type> production.
+ Node *parseType();
+ Node *parseFunctionType();
+ Node *parseVectorType();
+ Node *parseDecltype();
+ Node *parseArrayType();
+ Node *parsePointerToMemberType();
+ Node *parseClassEnumType();
+ Node *parseQualifiedType();
+
+ Node *parseEncoding();
+ bool parseCallOffset();
+ Node *parseSpecialName();
+
+ /// Holds some extra information about a <name> that is being parsed. This
+ /// information is only pertinent if the <name> refers to an <encoding>.
+ struct NameState {
+ bool CtorDtorConversion = false;
+ bool EndsWithTemplateArgs = false;
+ Qualifiers CVQualifiers = QualNone;
+ FunctionRefQual ReferenceQualifier = FrefQualNone;
+ size_t ForwardTemplateRefsBegin;
+
+ NameState(Db *Enclosing)
+ : ForwardTemplateRefsBegin(Enclosing->ForwardTemplateRefs.size()) {}
+ };
-const char*
-parse_number(const char* first, const char* last)
-{
- if (first != last)
- {
- const char* t = first;
- if (*t == 'n')
- ++t;
- if (t != last)
- {
- if (*t == '0')
- {
- first = t+1;
- }
- else if ('1' <= *t && *t <= '9')
- {
- first = t+1;
- while (first != last && std::isdigit(*first))
- ++first;
- }
- }
+ bool resolveForwardTemplateRefs(NameState &State) {
+ size_t I = State.ForwardTemplateRefsBegin;
+ size_t E = ForwardTemplateRefs.size();
+ for (; I < E; ++I) {
+ size_t Idx = ForwardTemplateRefs[I]->Index;
+ if (Idx >= TemplateParams.size())
+ return true;
+ ForwardTemplateRefs[I]->Ref = TemplateParams[Idx];
}
- return first;
-}
-
-template <class Float>
-struct FloatData;
+ ForwardTemplateRefs.dropBack(State.ForwardTemplateRefsBegin);
+ return false;
+ }
-template <>
-struct FloatData<float>
-{
- static const size_t mangled_size = 8;
- static const size_t max_demangled_size = 24;
- static constexpr const char* spec = "%af";
+ /// Parse the <name> production>
+ Node *parseName(NameState *State = nullptr);
+ Node *parseLocalName(NameState *State);
+ Node *parseOperatorName(NameState *State);
+ Node *parseUnqualifiedName(NameState *State);
+ Node *parseUnnamedTypeName(NameState *State);
+ Node *parseSourceName(NameState *State);
+ Node *parseUnscopedName(NameState *State);
+ Node *parseNestedName(NameState *State);
+ Node *parseCtorDtorName(Node *&SoFar, NameState *State);
+
+ Node *parseAbiTags(Node *N);
+
+ /// Parse the <unresolved-name> production.
+ Node *parseUnresolvedName();
+ Node *parseSimpleId();
+ Node *parseBaseUnresolvedName();
+ Node *parseUnresolvedType();
+ Node *parseDestructorName();
+
+ /// Top-level entry point into the parser.
+ Node *parse();
};
-constexpr const char* FloatData<float>::spec;
+const char* parse_discriminator(const char* first, const char* last);
-template <>
-struct FloatData<double>
-{
- static const size_t mangled_size = 16;
- static const size_t max_demangled_size = 32;
- static constexpr const char* spec = "%a";
-};
+// <name> ::= <nested-name> // N
+// ::= <local-name> # See Scope Encoding below // Z
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+//
+// <unscoped-template-name> ::= <unscoped-name>
+// ::= <substitution>
+Node *Db::parseName(NameState *State) {
+ consumeIf('L'); // extension
+
+ if (look() == 'N')
+ return parseNestedName(State);
+ if (look() == 'Z')
+ return parseLocalName(State);
+
+ // ::= <unscoped-template-name> <template-args>
+ if (look() == 'S' && look(1) != 't') {
+ Node *S = parseSubstitution();
+ if (S == nullptr)
+ return nullptr;
+ if (look() != 'I')
+ return nullptr;
+ Node *TA = parseTemplateArgs(State != nullptr);
+ if (TA == nullptr)
+ return nullptr;
+ if (State) State->EndsWithTemplateArgs = true;
+ return make<NameWithTemplateArgs>(S, TA);
+ }
-constexpr const char* FloatData<double>::spec;
+ Node *N = parseUnscopedName(State);
+ if (N == nullptr)
+ return nullptr;
+ // ::= <unscoped-template-name> <template-args>
+ if (look() == 'I') {
+ Subs.push_back(N);
+ Node *TA = parseTemplateArgs(State != nullptr);
+ if (TA == nullptr)
+ return nullptr;
+ if (State) State->EndsWithTemplateArgs = true;
+ return make<NameWithTemplateArgs>(N, TA);
+ }
+ // ::= <unscoped-name>
+ return N;
+}
-template <>
-struct FloatData<long double>
-{
-#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
- defined(__wasm__)
- static const size_t mangled_size = 32;
-#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
- static const size_t mangled_size = 16;
-#else
- static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
-#endif
- static const size_t max_demangled_size = 40;
- static constexpr const char* spec = "%LaL";
-};
+// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+// := Z <function encoding> E s [<discriminator>]
+// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+Node *Db::parseLocalName(NameState *State) {
+ if (!consumeIf('Z'))
+ return nullptr;
+ Node *Encoding = parseEncoding();
+ if (Encoding == nullptr || !consumeIf('E'))
+ return nullptr;
+
+ if (consumeIf('s')) {
+ First = parse_discriminator(First, Last);
+ return make<LocalName>(Encoding, make<NameType>("string literal"));
+ }
-constexpr const char* FloatData<long double>::spec;
+ if (consumeIf('d')) {
+ parseNumber(true);
+ if (!consumeIf('_'))
+ return nullptr;
+ Node *N = parseName(State);
+ if (N == nullptr)
+ return nullptr;
+ return make<LocalName>(Encoding, N);
+ }
-template <class Float>
-const char*
-parse_floating_number(const char* first, const char* last, Db& db)
-{
- const size_t N = FloatData<Float>::mangled_size;
- if (static_cast<std::size_t>(last - first) <= N)
- return first;
- last = first + N;
- const char* t = first;
- for (; t != last; ++t)
- {
- if (!isxdigit(*t))
- return first;
- }
- if (*t == 'E')
- {
- db.Names.push_back(
- db.make<FloatExpr<Float>>(StringView(first, t)));
- first = t + 1;
- }
- return first;
+ Node *Entity = parseName(State);
+ if (Entity == nullptr)
+ return nullptr;
+ First = parse_discriminator(First, Last);
+ return make<LocalName>(Encoding, Entity);
}
-// <positive length number> ::= [0-9]*
-const char*
-parse_positive_integer(const char* first, const char* last, size_t* out)
-{
- if (first != last)
- {
- char c = *first;
- if (isdigit(c) && first+1 != last)
- {
- const char* t = first+1;
- size_t n = static_cast<size_t>(c - '0');
- for (c = *t; isdigit(c); c = *t)
- {
- n = n * 10 + static_cast<size_t>(c - '0');
- if (++t == last)
- return first;
- }
- *out = n;
- first = t;
- }
- }
- return first;
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+Node *Db::parseUnscopedName(NameState *State) {
+ if (consumeIf("StL") || consumeIf("St")) {
+ Node *R = parseUnqualifiedName(State);
+ if (R == nullptr)
+ return nullptr;
+ return make<StdQualifiedName>(R);
+ }
+ return parseUnqualifiedName(State);
}
-// extension
-// <abi-tag-seq> ::= <abi-tag>*
-// <abi-tag> ::= B <positive length number> <identifier>
-const char*
-parse_abi_tag_seq(const char* first, const char* last, Db& db)
-{
- while (first != last && *first == 'B' && first+1 != last)
- {
- size_t length;
- const char* t = parse_positive_integer(first+1, last, &length);
- if (t == first+1)
- return first;
- if (static_cast<size_t>(last - t) < length || db.Names.empty())
- return first;
- db.Names.back() = db.make<AbiTagAttr>(
- db.Names.back(), StringView(t, t + length));
- first = t + length;
- }
- return first;
+// <unqualified-name> ::= <operator-name> [abi-tags]
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+// ::= DC <source-name>+ E # structured binding declaration
+Node *Db::parseUnqualifiedName(NameState *State) {
+ // <ctor-dtor-name>s are special-cased in parseNestedName().
+ Node *Result;
+ if (look() == 'U')
+ Result = parseUnnamedTypeName(State);
+ else if (look() >= '1' && look() <= '9')
+ Result = parseSourceName(State);
+ else if (consumeIf("DC")) {
+ size_t BindingsBegin = Names.size();
+ do {
+ Node *Binding = parseSourceName(State);
+ if (Binding == nullptr)
+ return nullptr;
+ Names.push_back(Binding);
+ } while (!consumeIf('E'));
+ Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin));
+ } else
+ Result = parseOperatorName(State);
+ if (Result != nullptr)
+ Result = parseAbiTags(Result);
+ return Result;
}
-// <source-name> ::= <positive length number> <identifier> [<abi-tag-seq>]
-const char*
-parse_source_name(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- size_t length;
- const char* t = parse_positive_integer(first, last, &length);
- if (t == first)
- return first;
- if (static_cast<size_t>(last - t) >= length)
- {
- StringView r(t, t + length);
- if (r.substr(0, 10) == "_GLOBAL__N")
- db.Names.push_back(db.make<NameType>("(anonymous namespace)"));
- else
- db.Names.push_back(db.make<NameType>(r));
- first = t + length;
- first = parse_abi_tag_seq(first, last, db);
- }
+// <unnamed-type-name> ::= Ut [<nonnegative number>] _
+// ::= <closure-type-name>
+//
+// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+//
+// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
+Node *Db::parseUnnamedTypeName(NameState *) {
+ if (consumeIf("Ut")) {
+ StringView Count = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<UnnamedTypeName>(Count);
+ }
+ if (consumeIf("Ul")) {
+ NodeArray Params;
+ SwapAndRestore<bool> SwapParams(ParsingLambdaParams, true);
+ if (!consumeIf("vE")) {
+ size_t ParamsBegin = Names.size();
+ do {
+ Node *P = parseType();
+ if (P == nullptr)
+ return nullptr;
+ Names.push_back(P);
+ } while (!consumeIf('E'));
+ Params = popTrailingNodeArray(ParamsBegin);
}
- return first;
+ StringView Count = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<ClosureTypeName>(Params, Count);
+ }
+ return nullptr;
}
-// <substitution> ::= S <seq-id> _
-// ::= S_
-// <substitution> ::= Sa # ::std::allocator
-// <substitution> ::= Sb # ::std::basic_string
-// <substitution> ::= Ss # ::std::basic_string < char,
-// ::std::char_traits<char>,
-// ::std::allocator<char> >
-// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
-// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
-// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
-
-const char*
-parse_substitution(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'S')
- {
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(
- db.make<SpecialSubstitution>(
- SpecialSubKind::allocator));
- first += 2;
- break;
- case 'b':
- db.Names.push_back(
- db.make<SpecialSubstitution>(SpecialSubKind::basic_string));
- first += 2;
- break;
- case 's':
- db.Names.push_back(
- db.make<SpecialSubstitution>(
- SpecialSubKind::string));
- first += 2;
- break;
- case 'i':
- db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::istream));
- first += 2;
- break;
- case 'o':
- db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::ostream));
- first += 2;
- break;
- case 'd':
- db.Names.push_back(db.make<SpecialSubstitution>(SpecialSubKind::iostream));
- first += 2;
- break;
- case '_':
- if (!db.Subs.empty())
- {
- for (Node* n : db.Subs.nthSubstitution(0))
- db.Names.push_back(n);
- first += 2;
- }
- break;
- default:
- if (std::isdigit(first[1]) || std::isupper(first[1]))
- {
- size_t sub = 0;
- const char* t = first+1;
- if (std::isdigit(*t))
- sub = static_cast<size_t>(*t - '0');
- else
- sub = static_cast<size_t>(*t - 'A') + 10;
- for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t)
- {
- sub *= 36;
- if (std::isdigit(*t))
- sub += static_cast<size_t>(*t - '0');
- else
- sub += static_cast<size_t>(*t - 'A') + 10;
- }
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < db.Subs.size())
- {
- for (Node* n : db.Subs.nthSubstitution(sub))
- db.Names.push_back(n);
- first = t+1;
- }
- }
- break;
- }
- }
- }
- return first;
+// <source-name> ::= <positive length number> <identifier>
+Node *Db::parseSourceName(NameState *) {
+ size_t Length = 0;
+ if (parsePositiveInteger(&Length))
+ return nullptr;
+ if (numLeft() < Length || Length == 0)
+ return nullptr;
+ StringView Name(First, First + Length);
+ First += Length;
+ if (Name.startsWith("_GLOBAL__N"))
+ return make<NameType>("(anonymous namespace)");
+ return make<NameType>(Name);
}
-// <builtin-type> ::= v # void
-// ::= w # wchar_t
-// ::= b # bool
-// ::= c # char
-// ::= a # signed char
-// ::= h # unsigned char
-// ::= s # short
-// ::= t # unsigned short
-// ::= i # int
-// ::= j # unsigned int
-// ::= l # long
-// ::= m # unsigned long
-// ::= x # long long, __int64
-// ::= y # unsigned long long, __int64
-// ::= n # __int128
-// ::= o # unsigned __int128
-// ::= f # float
-// ::= d # double
-// ::= e # long double, __float80
-// ::= g # __float128
-// ::= z # ellipsis
-// ::= Dd # IEEE 754r decimal floating point (64 bits)
-// ::= De # IEEE 754r decimal floating point (128 bits)
-// ::= Df # IEEE 754r decimal floating point (32 bits)
-// ::= Dh # IEEE 754r half-precision floating point (16 bits)
-// ::= Di # char32_t
-// ::= Ds # char16_t
-// ::= Da # auto (in dependent new-expressions)
-// ::= Dc # decltype(auto)
-// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
-// ::= u <source-name> # vendor extended type
-
-const char*
-parse_builtin_type(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'v':
- db.Names.push_back(db.make<NameType>("void"));
- ++first;
- break;
- case 'w':
- db.Names.push_back(db.make<NameType>("wchar_t"));
- ++first;
- break;
- case 'b':
- db.Names.push_back(db.make<NameType>("bool"));
- ++first;
- break;
- case 'c':
- db.Names.push_back(db.make<NameType>("char"));
- ++first;
- break;
- case 'a':
- db.Names.push_back(db.make<NameType>("signed char"));
- ++first;
- break;
- case 'h':
- db.Names.push_back(db.make<NameType>("unsigned char"));
- ++first;
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("short"));
- ++first;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("unsigned short"));
- ++first;
- break;
- case 'i':
- db.Names.push_back(db.make<NameType>("int"));
- ++first;
- break;
- case 'j':
- db.Names.push_back(db.make<NameType>("unsigned int"));
- ++first;
- break;
- case 'l':
- db.Names.push_back(db.make<NameType>("long"));
- ++first;
- break;
- case 'm':
- db.Names.push_back(db.make<NameType>("unsigned long"));
- ++first;
- break;
- case 'x':
- db.Names.push_back(db.make<NameType>("long long"));
- ++first;
- break;
- case 'y':
- db.Names.push_back(db.make<NameType>("unsigned long long"));
- ++first;
- break;
- case 'n':
- db.Names.push_back(db.make<NameType>("__int128"));
- ++first;
- break;
- case 'o':
- db.Names.push_back(db.make<NameType>("unsigned __int128"));
- ++first;
- break;
- case 'f':
- db.Names.push_back(db.make<NameType>("float"));
- ++first;
- break;
- case 'd':
- db.Names.push_back(db.make<NameType>("double"));
- ++first;
- break;
- case 'e':
- db.Names.push_back(db.make<NameType>("long double"));
- ++first;
- break;
- case 'g':
- db.Names.push_back(db.make<NameType>("__float128"));
- ++first;
- break;
- case 'z':
- db.Names.push_back(db.make<NameType>("..."));
- ++first;
- break;
- case 'u':
- {
- const char*t = parse_source_name(first+1, last, db);
- if (t != first+1)
- first = t;
- }
- break;
- case 'D':
- if (first+1 != last)
- {
- switch (first[1])
- {
- case 'd':
- db.Names.push_back(db.make<NameType>("decimal64"));
- first += 2;
- break;
- case 'e':
- db.Names.push_back(db.make<NameType>("decimal128"));
- first += 2;
- break;
- case 'f':
- db.Names.push_back(db.make<NameType>("decimal32"));
- first += 2;
- break;
- case 'h':
- db.Names.push_back(db.make<NameType>("decimal16"));
- first += 2;
- break;
- case 'i':
- db.Names.push_back(db.make<NameType>("char32_t"));
- first += 2;
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("char16_t"));
- first += 2;
- break;
- case 'a':
- db.Names.push_back(db.make<NameType>("auto"));
- first += 2;
- break;
- case 'c':
- db.Names.push_back(db.make<NameType>("decltype(auto)"));
- first += 2;
- break;
- case 'n':
- db.Names.push_back(db.make<NameType>("std::nullptr_t"));
- first += 2;
- break;
- }
- }
- break;
- }
+// <operator-name> ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= li <source-name> # operator ""
+// ::= ls # <<
+// ::= lS # <<=
+// ::= lt # <
+// ::= mi # -
+// ::= mI # -=
+// ::= ml # *
+// ::= mL # *=
+// ::= mm # -- (postfix in <expression> context)
+// ::= na # new[]
+// ::= ne # !=
+// ::= ng # - (unary)
+// ::= nt # !
+// ::= nw # new
+// ::= oo # ||
+// ::= or # |
+// ::= oR # |=
+// ::= pm # ->*
+// ::= pl # +
+// ::= pL # +=
+// ::= pp # ++ (postfix in <expression> context)
+// ::= ps # + (unary)
+// ::= pt # ->
+// ::= qu # ?
+// ::= rm # %
+// ::= rM # %=
+// ::= rs # >>
+// ::= rS # >>=
+// ::= ss # <=> C++2a
+// ::= v <digit> <source-name> # vendor extended operator
+Node *Db::parseOperatorName(NameState *State) {
+ switch (look()) {
+ case 'a':
+ switch (look(1)) {
+ case 'a':
+ First += 2;
+ return make<NameType>("operator&&");
+ case 'd':
+ case 'n':
+ First += 2;
+ return make<NameType>("operator&");
+ case 'N':
+ First += 2;
+ return make<NameType>("operator&=");
+ case 'S':
+ First += 2;
+ return make<NameType>("operator=");
}
- return first;
-}
-
-// <CV-Qualifiers> ::= [r] [V] [K]
-
-const char*
-parse_cv_qualifiers(const char* first, const char* last, Qualifiers& cv)
-{
- cv = QualNone;
- if (first != last)
- {
- if (*first == 'r')
- {
- addQualifiers(cv, QualRestrict);
- ++first;
- }
- if (*first == 'V')
- {
- addQualifiers(cv, QualVolatile);
- ++first;
- }
- if (*first == 'K')
- {
- addQualifiers(cv, QualConst);
- ++first;
- }
+ return nullptr;
+ case 'c':
+ switch (look(1)) {
+ case 'l':
+ First += 2;
+ return make<NameType>("operator()");
+ case 'm':
+ First += 2;
+ return make<NameType>("operator,");
+ case 'o':
+ First += 2;
+ return make<NameType>("operator~");
+ // ::= cv <type> # (cast)
+ case 'v': {
+ First += 2;
+ SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false);
+ // If we're parsing an encoding, State != nullptr and the conversion
+ // operators' <type> could have a <template-param> that refers to some
+ // <template-arg>s further ahead in the mangled name.
+ SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences,
+ PermitForwardTemplateReferences ||
+ State != nullptr);
+ Node* Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ if (State) State->CtorDtorConversion = true;
+ return make<ConversionOperatorType>(Ty);
}
- return first;
-}
-
-// <template-param> ::= T_ # first template parameter
-// ::= T <parameter-2 non-negative number> _
-
-const char*
-parse_template_param(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- if (*first == 'T')
- {
- if (first[1] == '_')
- {
- if (!db.TemplateParams.empty())
- {
- for (Node *t : db.TemplateParams.nthSubstitution(0))
- db.Names.push_back(t);
- first += 2;
- }
- else
- {
- db.Names.push_back(db.make<NameType>("T_"));
- first += 2;
- db.FixForwardReferences = true;
- }
- }
- else if (isdigit(first[1]))
- {
- const char* t = first+1;
- size_t sub = static_cast<size_t>(*t - '0');
- for (++t; t != last && isdigit(*t); ++t)
- {
- sub *= 10;
- sub += static_cast<size_t>(*t - '0');
- }
- if (t == last || *t != '_')
- return first;
- ++sub;
- if (sub < db.TemplateParams.size())
- {
- for (Node *temp : db.TemplateParams.nthSubstitution(sub))
- db.Names.push_back(temp);
- first = t+1;
- }
- else
- {
- db.Names.push_back(
- db.make<NameType>(StringView(first, t + 1)));
- first = t+1;
- db.FixForwardReferences = true;
- }
- }
- }
}
- return first;
-}
-
-// cc <type> <expression> # const_cast<type> (expression)
-
-const char*
-parse_const_cast_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto from_expr = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<CastExpr>(
- "const_cast", db.Names.back(), from_expr);
- first = t1;
- }
- }
+ return nullptr;
+ case 'd':
+ switch (look(1)) {
+ case 'a':
+ First += 2;
+ return make<NameType>("operator delete[]");
+ case 'e':
+ First += 2;
+ return make<NameType>("operator*");
+ case 'l':
+ First += 2;
+ return make<NameType>("operator delete");
+ case 'v':
+ First += 2;
+ return make<NameType>("operator/");
+ case 'V':
+ First += 2;
+ return make<NameType>("operator/=");
}
- return first;
-}
-
-// dc <type> <expression> # dynamic_cast<type> (expression)
-
-const char*
-parse_dynamic_cast_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto from_expr = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<CastExpr>(
- "dynamic_cast", db.Names.back(), from_expr);
- first = t1;
- }
- }
+ return nullptr;
+ case 'e':
+ switch (look(1)) {
+ case 'o':
+ First += 2;
+ return make<NameType>("operator^");
+ case 'O':
+ First += 2;
+ return make<NameType>("operator^=");
+ case 'q':
+ First += 2;
+ return make<NameType>("operator==");
}
- return first;
-}
-
-// rc <type> <expression> # reinterpret_cast<type> (expression)
-
-const char*
-parse_reinterpret_cast_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto from_expr = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<CastExpr>(
- "reinterpret_cast", db.Names.back(), from_expr);
- first = t1;
- }
- }
+ return nullptr;
+ case 'g':
+ switch (look(1)) {
+ case 'e':
+ First += 2;
+ return make<NameType>("operator>=");
+ case 't':
+ First += 2;
+ return make<NameType>("operator>");
}
- return first;
-}
-
-// sc <type> <expression> # static_cast<type> (expression)
-
-const char*
-parse_static_cast_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto from_expr = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<CastExpr>(
- "static_cast", db.Names.back(), from_expr);
- first = t1;
- }
- }
+ return nullptr;
+ case 'i':
+ if (look(1) == 'x') {
+ First += 2;
+ return make<NameType>("operator[]");
}
- return first;
-}
-
-// sp <expression> # pack expansion
-
-const char*
-parse_pack_expansion(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- first = t;
+ return nullptr;
+ case 'l':
+ switch (look(1)) {
+ case 'e':
+ First += 2;
+ return make<NameType>("operator<=");
+ // ::= li <source-name> # operator ""
+ case 'i': {
+ First += 2;
+ Node *SN = parseSourceName(State);
+ if (SN == nullptr)
+ return nullptr;
+ return make<LiteralOperator>(SN);
}
- return first;
+ case 's':
+ First += 2;
+ return make<NameType>("operator<<");
+ case 'S':
+ First += 2;
+ return make<NameType>("operator<<=");
+ case 't':
+ First += 2;
+ return make<NameType>("operator<");
+ }
+ return nullptr;
+ case 'm':
+ switch (look(1)) {
+ case 'i':
+ First += 2;
+ return make<NameType>("operator-");
+ case 'I':
+ First += 2;
+ return make<NameType>("operator-=");
+ case 'l':
+ First += 2;
+ return make<NameType>("operator*");
+ case 'L':
+ First += 2;
+ return make<NameType>("operator*=");
+ case 'm':
+ First += 2;
+ return make<NameType>("operator--");
+ }
+ return nullptr;
+ case 'n':
+ switch (look(1)) {
+ case 'a':
+ First += 2;
+ return make<NameType>("operator new[]");
+ case 'e':
+ First += 2;
+ return make<NameType>("operator!=");
+ case 'g':
+ First += 2;
+ return make<NameType>("operator-");
+ case 't':
+ First += 2;
+ return make<NameType>("operator!");
+ case 'w':
+ First += 2;
+ return make<NameType>("operator new");
+ }
+ return nullptr;
+ case 'o':
+ switch (look(1)) {
+ case 'o':
+ First += 2;
+ return make<NameType>("operator||");
+ case 'r':
+ First += 2;
+ return make<NameType>("operator|");
+ case 'R':
+ First += 2;
+ return make<NameType>("operator|=");
+ }
+ return nullptr;
+ case 'p':
+ switch (look(1)) {
+ case 'm':
+ First += 2;
+ return make<NameType>("operator->*");
+ case 'l':
+ First += 2;
+ return make<NameType>("operator+");
+ case 'L':
+ First += 2;
+ return make<NameType>("operator+=");
+ case 'p':
+ First += 2;
+ return make<NameType>("operator++");
+ case 's':
+ First += 2;
+ return make<NameType>("operator+");
+ case 't':
+ First += 2;
+ return make<NameType>("operator->");
+ }
+ return nullptr;
+ case 'q':
+ if (look(1) == 'u') {
+ First += 2;
+ return make<NameType>("operator?");
+ }
+ return nullptr;
+ case 'r':
+ switch (look(1)) {
+ case 'm':
+ First += 2;
+ return make<NameType>("operator%");
+ case 'M':
+ First += 2;
+ return make<NameType>("operator%=");
+ case 's':
+ First += 2;
+ return make<NameType>("operator>>");
+ case 'S':
+ First += 2;
+ return make<NameType>("operator>>=");
+ }
+ return nullptr;
+ case 's':
+ if (look(1) == 's') {
+ First += 2;
+ return make<NameType>("operator<=>");
+ }
+ return nullptr;
+ // ::= v <digit> <source-name> # vendor extended operator
+ case 'v':
+ if (std::isdigit(look(1))) {
+ First += 2;
+ Node *SN = parseSourceName(State);
+ if (SN == nullptr)
+ return nullptr;
+ return make<ConversionOperatorType>(SN);
+ }
+ return nullptr;
+ }
+ return nullptr;
}
-// st <type> # sizeof (a type)
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// extension ::= C5 # ?
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+// extension ::= D5 # ?
+Node *Db::parseCtorDtorName(Node *&SoFar, NameState *State) {
+ if (SoFar->K == Node::KSpecialSubstitution) {
+ auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK;
+ switch (SSK) {
+ case SpecialSubKind::string:
+ case SpecialSubKind::istream:
+ case SpecialSubKind::ostream:
+ case SpecialSubKind::iostream:
+ SoFar = make<ExpandedSpecialSubstitution>(SSK);
+ default:
+ break;
+ }
+ }
-const char*
-parse_sizeof_type_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 't')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<EnclosingExpr>(
- "sizeof (", db.Names.back(), ")");
- first = t;
- }
+ if (consumeIf('C')) {
+ bool IsInherited = consumeIf('I');
+ if (look() != '1' && look() != '2' && look() != '3' && look() != '5')
+ return nullptr;
+ ++First;
+ if (State) State->CtorDtorConversion = true;
+ if (IsInherited) {
+ if (parseName(State) == nullptr)
+ return nullptr;
}
- return first;
-}
+ return make<CtorDtorName>(SoFar, false);
+ }
-// sz <expr> # sizeof (a expression)
+ if (look() == 'D' &&
+ (look(1) == '0' || look(1) == '1' || look(1) == '2' || look(1) == '5')) {
+ First += 2;
+ if (State) State->CtorDtorConversion = true;
+ return make<CtorDtorName>(SoFar, true);
+ }
-const char*
-parse_sizeof_expr_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'z')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<EnclosingExpr>(
- "sizeof (", db.Names.back(), ")");
- first = t;
- }
- }
- return first;
+ return nullptr;
}
-// sZ <template-param> # size of a parameter pack
+// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+//
+// <prefix> ::= <prefix> <unqualified-name>
+// ::= <template-prefix> <template-args>
+// ::= <template-param>
+// ::= <decltype>
+// ::= # empty
+// ::= <substitution>
+// ::= <prefix> <data-member-prefix>
+// extension ::= L
+//
+// <data-member-prefix> := <member source-name> [<template-args>] M
+//
+// <template-prefix> ::= <prefix> <template unqualified-name>
+// ::= <template-param>
+// ::= <substitution>
+Node *Db::parseNestedName(NameState *State) {
+ if (!consumeIf('N'))
+ return nullptr;
+
+ Qualifiers CVTmp = parseCVQualifiers();
+ if (State) State->CVQualifiers = CVTmp;
+
+ if (consumeIf('O')) {
+ if (State) State->ReferenceQualifier = FrefQualRValue;
+ } else if (consumeIf('R')) {
+ if (State) State->ReferenceQualifier = FrefQualLValue;
+ } else
+ if (State) State->ReferenceQualifier = FrefQualNone;
+
+ Node *SoFar = nullptr;
+ auto PushComponent = [&](Node *Comp) {
+ if (SoFar) SoFar = make<NestedName>(SoFar, Comp);
+ else SoFar = Comp;
+ if (State) State->EndsWithTemplateArgs = false;
+ };
-const char*
-parse_sizeof_param_pack_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
- {
- size_t k0 = db.Names.size();
- const char* t = parse_template_param(first+2, last, db);
- size_t k1 = db.Names.size();
- if (t != first+2 && k0 <= k1)
- {
- Node* sizeof_expr = db.make<SizeofParamPackExpr>(
- db.popTrailingNodeArray(k0));
- db.Names.push_back(sizeof_expr);
- first = t;
- }
- }
- return first;
-}
+ if (consumeIf("St"))
+ SoFar = make<NameType>("std");
-// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter
-// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
-// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter
-// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+ while (!consumeIf('E')) {
+ consumeIf('L'); // extension
-const char*
-parse_function_param(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && *first == 'f')
- {
- if (first[1] == 'p')
- {
- Qualifiers cv;
- const char* t = parse_cv_qualifiers(first+2, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- db.Names.push_back(
- db.make<FunctionParam>(StringView(t, t1)));
- first = t1+1;
- }
- }
- else if (first[1] == 'L')
- {
- Qualifiers cv;
- const char* t0 = parse_number(first+2, last);
- if (t0 != last && *t0 == 'p')
- {
- ++t0;
- const char* t = parse_cv_qualifiers(t0, last, cv);
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- db.Names.push_back(
- db.make<FunctionParam>(StringView(t, t1)));
- first = t1+1;
- }
- }
- }
+ // <data-member-prefix> := <member source-name> [<template-args>] M
+ if (consumeIf('M')) {
+ if (SoFar == nullptr)
+ return nullptr;
+ continue;
}
- return first;
-}
-// sZ <function-param> # size of a function parameter pack
-
-const char*
-parse_sizeof_function_param_pack_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
- {
- const char* t = parse_function_param(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<EnclosingExpr>(
- "sizeof...(", db.Names.back(), ")");
- first = t;
- }
+ // ::= <template-param>
+ if (look() == 'T') {
+ Node *TP = parseTemplateParam();
+ if (TP == nullptr)
+ return nullptr;
+ PushComponent(TP);
+ Subs.push_back(SoFar);
+ continue;
}
- return first;
-}
-// te <expression> # typeid (expression)
-// ti <type> # typeid (type)
+ // ::= <template-prefix> <template-args>
+ if (look() == 'I') {
+ Node *TA = parseTemplateArgs(State != nullptr);
+ if (TA == nullptr || SoFar == nullptr)
+ return nullptr;
+ SoFar = make<NameWithTemplateArgs>(SoFar, TA);
+ if (State) State->EndsWithTemplateArgs = true;
+ Subs.push_back(SoFar);
+ continue;
+ }
-const char*
-parse_typeid_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i'))
- {
- const char* t;
- if (first[1] == 'e')
- t = parse_expression(first+2, last, db);
- else
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<EnclosingExpr>(
- "typeid(", db.Names.back(), ")");
- first = t;
- }
+ // ::= <decltype>
+ if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) {
+ Node *DT = parseDecltype();
+ if (DT == nullptr)
+ return nullptr;
+ PushComponent(DT);
+ Subs.push_back(SoFar);
+ continue;
}
- return first;
-}
-// tw <expression> # throw expression
+ // ::= <substitution>
+ if (look() == 'S' && look(1) != 't') {
+ Node *S = parseSubstitution();
+ if (S == nullptr)
+ return nullptr;
+ PushComponent(S);
+ if (SoFar != S)
+ Subs.push_back(S);
+ continue;
+ }
-const char*
-parse_throw_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<ThrowExpr>(db.Names.back());
- first = t;
- }
+ // Parse an <unqualified-name> thats actually a <ctor-dtor-name>.
+ if (look() == 'C' || (look() == 'D' && look(1) != 'C')) {
+ if (SoFar == nullptr)
+ return nullptr;
+ Node *CtorDtor = parseCtorDtorName(SoFar, State);
+ if (CtorDtor == nullptr)
+ return nullptr;
+ PushComponent(CtorDtor);
+ SoFar = parseAbiTags(SoFar);
+ if (SoFar == nullptr)
+ return nullptr;
+ Subs.push_back(SoFar);
+ continue;
}
- return first;
-}
-// ds <expression> <expression> # expr.*expr
+ // ::= <prefix> <unqualified-name>
+ Node *N = parseUnqualifiedName(State);
+ if (N == nullptr)
+ return nullptr;
+ PushComponent(N);
+ Subs.push_back(SoFar);
+ }
-const char*
-parse_dot_star_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto rhs_expr = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<MemberExpr>(
- db.Names.back(), ".*", rhs_expr);
- first = t1;
- }
- }
- }
- return first;
+ if (SoFar == nullptr || Subs.empty())
+ return nullptr;
+
+ Subs.pop_back();
+ return SoFar;
}
// <simple-id> ::= <source-name> [ <template-args> ]
+Node *Db::parseSimpleId() {
+ Node *SN = parseSourceName(/*NameState=*/nullptr);
+ if (SN == nullptr)
+ return nullptr;
+ if (look() == 'I') {
+ Node *TA = parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ return make<NameWithTemplateArgs>(SN, TA);
+ }
+ return SN;
+}
-const char*
-parse_simple_id(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t = parse_source_name(first, last, db);
- if (t != first)
- {
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(db.Names.back(), args);
- }
- first = t1;
- }
- else
- first = t;
- }
- return first;
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
+Node *Db::parseDestructorName() {
+ Node *Result;
+ if (std::isdigit(look()))
+ Result = parseSimpleId();
+ else
+ Result = parseUnresolvedType();
+ if (Result == nullptr)
+ return nullptr;
+ return make<DtorName>(Result);
}
// <unresolved-type> ::= <template-param>
// ::= <decltype>
// ::= <substitution>
-
-const char*
-parse_unresolved_type(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t = first;
- switch (*first)
- {
- case 'T':
- {
- size_t k0 = db.Names.size();
- t = parse_template_param(first, last, db);
- size_t k1 = db.Names.size();
- if (t != first && k1 == k0 + 1)
- {
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- }
- else
- {
- for (; k1 != k0; --k1)
- db.Names.pop_back();
- }
- break;
- }
- case 'D':
- t = parse_decltype(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- }
- break;
- case 'S':
- t = parse_substitution(first, last, db);
- if (t != first)
- first = t;
- else
- {
- if (last - first > 2 && first[1] == 't')
- {
- t = parse_unqualified_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<StdQualifiedName>(db.Names.back());
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- }
- }
- }
- break;
- }
- }
- return first;
-}
-
-// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
-// ::= <simple-id> # e.g., ~A<2*N>
-
-const char*
-parse_destructor_name(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t = parse_unresolved_type(first, last, db);
- if (t == first)
- t = parse_simple_id(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<DtorName>(db.Names.back());
- first = t;
- }
- }
- return first;
+Node *Db::parseUnresolvedType() {
+ if (look() == 'T') {
+ Node *TP = parseTemplateParam();
+ if (TP == nullptr)
+ return nullptr;
+ Subs.push_back(TP);
+ return TP;
+ }
+ if (look() == 'D') {
+ Node *DT = parseDecltype();
+ if (DT == nullptr)
+ return nullptr;
+ Subs.push_back(DT);
+ return DT;
+ }
+ return parseSubstitution();
}
// <base-unresolved-name> ::= <simple-id> # unresolved name
@@ -2679,1984 +2808,1076 @@ parse_destructor_name(const char* first, const char* last, Db& db)
// ::= on <operator-name> <template-args> # unresolved operator template-id
// ::= dn <destructor-name> # destructor or pseudo-destructor;
// # e.g. ~X or ~X<N-1>
-
-const char*
-parse_base_unresolved_name(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n')
- {
- if (first[0] == 'o')
- {
- const char* t = parse_operator_name(first+2, last, db);
- if (t != first+2)
- {
- first = parse_template_args(t, last, db);
- if (first != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
- }
- }
- }
- else
- {
- const char* t = parse_destructor_name(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- }
- else
- {
- const char* t = parse_simple_id(first, last, db);
- if (t == first)
- {
- t = parse_operator_name(first, last, db);
- if (t != first)
- {
- first = parse_template_args(t, last, db);
- if (first != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
- }
- }
- }
- else
- first = t;
- }
- }
- return first;
-}
-
-// <unresolved-qualifier-level> ::= <simple-id>
-
-const char*
-parse_unresolved_qualifier_level(const char* first, const char* last, Db& db)
-{
- return parse_simple_id(first, last, db);
+Node *Db::parseBaseUnresolvedName() {
+ if (std::isdigit(look()))
+ return parseSimpleId();
+
+ if (consumeIf("dn"))
+ return parseDestructorName();
+
+ consumeIf("on");
+
+ Node *Oper = parseOperatorName(/*NameState=*/nullptr);
+ if (Oper == nullptr)
+ return nullptr;
+ if (look() == 'I') {
+ Node *TA = parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ return make<NameWithTemplateArgs>(Oper, TA);
+ }
+ return Oper;
}
// <unresolved-name>
// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
-// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
// # A::x, N::y, A<T>::z; "gs" means leading "::"
// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
// # T::N::x /decltype(p)::N::x
// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
-
-const char*
-parse_unresolved_name(const char* first, const char* last, Db& db)
-{
- if (last - first > 2)
- {
- const char* t = first;
- bool global = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- global = true;
- t += 2;
- }
- const char* t2 = parse_base_unresolved_name(t, last, db);
- if (t2 != t)
- {
- if (global)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<GlobalQualifiedName>(db.Names.back());
- }
- first = t2;
- }
- else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
- {
- if (t[2] == 'N')
- {
- t += 3;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
- t = t1;
- if (t == last)
- {
- db.Names.pop_back();
- return first;
- }
- }
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.Names.empty())
- db.Names.pop_back();
- return first;
- }
- if (db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- first = t1;
- }
- else
- {
- t += 2;
- const char* t1 = parse_unresolved_type(t, last, db);
- if (t1 != t)
- {
- t = t1;
- t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), args);
- t = t1;
- }
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.Names.empty())
- db.Names.pop_back();
- return first;
- }
- if (db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- first = t1;
- }
- else
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- if (global)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<GlobalQualifiedName>(
- db.Names.back());
- }
- while (*t != 'E')
- {
- t1 = parse_unresolved_qualifier_level(t, last, db);
- if (t1 == t || t1 == last || db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<QualifiedName>(
- db.Names.back(), s);
- t = t1;
- }
- ++t;
- t1 = parse_base_unresolved_name(t, last, db);
- if (t1 == t)
- {
- if (!db.Names.empty())
- db.Names.pop_back();
- return first;
- }
- if (db.Names.size() < 2)
- return first;
- auto s = db.Names.back();
- db.Names.pop_back();
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), s);
- first = t1;
- }
- }
- }
+//
+// <unresolved-qualifier-level> ::= <simple-id>
+Node *Db::parseUnresolvedName() {
+ Node *SoFar = nullptr;
+
+ // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+ // srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+ if (consumeIf("srN")) {
+ SoFar = parseUnresolvedType();
+ if (SoFar == nullptr)
+ return nullptr;
+
+ if (look() == 'I') {
+ Node *TA = parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ SoFar = make<NameWithTemplateArgs>(SoFar, TA);
}
- return first;
-}
-
-// dt <expression> <unresolved-name> # expr.name
-const char*
-parse_dot_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_unresolved_name(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<MemberExpr>(db.Names.back(), ".", name);
- first = t1;
- }
- }
+ while (!consumeIf('E')) {
+ Node *Qual = parseSimpleId();
+ if (Qual == nullptr)
+ return nullptr;
+ SoFar = make<QualifiedName>(SoFar, Qual);
}
- return first;
-}
-// cl <expression>+ E # call
+ Node *Base = parseBaseUnresolvedName();
+ if (Base == nullptr)
+ return nullptr;
+ return make<QualifiedName>(SoFar, Base);
+ }
-const char*
-parse_call_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t == last || t == first + 2 || db.Names.empty())
- return first;
- Node* callee = db.Names.back();
- db.Names.pop_back();
- size_t args_begin = db.Names.size();
- while (*t != 'E')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == last || t1 == t)
- return first;
- t = t1;
- }
- if (db.Names.size() < args_begin)
- return first;
- ++t;
- CallExpr* the_call = db.make<CallExpr>(
- callee, db.popTrailingNodeArray(args_begin));
- db.Names.push_back(the_call);
- first = t;
- }
- return first;
-}
+ bool Global = consumeIf("gs");
-// [gs] nw <expression>* _ <type> E # new (expr-list) type
-// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
-// [gs] na <expression>* _ <type> E # new[] (expr-list) type
-// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
-// <initializer> ::= pi <expression>* E # parenthesized initialization
+ // [gs] <base-unresolved-name> # x or (with "gs") ::x
+ if (!consumeIf("sr")) {
+ SoFar = parseBaseUnresolvedName();
+ if (SoFar == nullptr)
+ return nullptr;
+ if (Global)
+ SoFar = make<GlobalQualifiedName>(SoFar);
+ return SoFar;
+ }
-const char*
-parse_new_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 4)
- {
- const char* t = first;
- bool parsed_gs = false;
- if (t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a'))
- {
- bool is_array = t[1] == 'a';
- t += 2;
- if (t == last)
- return first;
- size_t first_expr_in_list = db.Names.size();
- NodeArray ExprList, init_list;
- while (*t != '_')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- }
- if (first_expr_in_list > db.Names.size())
- return first;
- ExprList = db.popTrailingNodeArray(first_expr_in_list);
- ++t;
- const char* t1 = parse_type(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- bool has_init = false;
- if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
- {
- t += 2;
- has_init = true;
- size_t init_list_begin = db.Names.size();
- while (*t != 'E')
- {
- t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- }
- if (init_list_begin > db.Names.size())
- return first;
- init_list = db.popTrailingNodeArray(init_list_begin);
- }
- if (*t != 'E' || db.Names.empty())
- return first;
- auto type = db.Names.back();
- db.Names.pop_back();
- db.Names.push_back(
- db.make<NewExpr>(ExprList, type, init_list,
- parsed_gs, is_array));
- first = t+1;
- }
+ // [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+ if (std::isdigit(look())) {
+ do {
+ Node *Qual = parseSimpleId();
+ if (Qual == nullptr)
+ return nullptr;
+ if (SoFar)
+ SoFar = make<QualifiedName>(SoFar, Qual);
+ else if (Global)
+ SoFar = make<GlobalQualifiedName>(Qual);
+ else
+ SoFar = Qual;
+ } while (!consumeIf('E'));
+ }
+ // sr <unresolved-type> <base-unresolved-name>
+ // sr <unresolved-type> <template-args> <base-unresolved-name>
+ else {
+ SoFar = parseUnresolvedType();
+ if (SoFar == nullptr)
+ return nullptr;
+
+ if (look() == 'I') {
+ Node *TA = parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ SoFar = make<NameWithTemplateArgs>(SoFar, TA);
}
- return first;
-}
+ }
-// cv <type> <expression> # conversion with one argument
-// cv <type> _ <expression>* E # conversion with a different number of arguments
+ assert(SoFar != nullptr);
-const char*
-parse_conversion_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
- {
- bool TryToParseTemplateArgs = db.TryToParseTemplateArgs;
- db.TryToParseTemplateArgs = false;
- size_t type_begin = db.Names.size();
- const char* t = parse_type(first+2, last, db);
- db.TryToParseTemplateArgs = TryToParseTemplateArgs;
- if (t != first+2 && t != last)
- {
- size_t expr_list_begin = db.Names.size();
- if (*t != '_')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t)
- return first;
- t = t1;
- }
- else
- {
- ++t;
- if (t == last)
- return first;
- if (*t != 'E')
- {
- while (*t != 'E')
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 == t || t1 == last)
- return first;
- t = t1;
- }
- }
- ++t;
- }
- if (db.Names.size() < expr_list_begin ||
- type_begin > expr_list_begin)
- return first;
- NodeArray expressions = db.makeNodeArray(
- db.Names.begin() + (long)expr_list_begin, db.Names.end());
- NodeArray types = db.makeNodeArray(
- db.Names.begin() + (long)type_begin,
- db.Names.begin() + (long)expr_list_begin);
- auto* conv_expr = db.make<ConversionExpr>(
- types, expressions);
- db.Names.dropBack(type_begin);
- db.Names.push_back(conv_expr);
- first = t;
- }
- }
- return first;
+ Node *Base = parseBaseUnresolvedName();
+ if (Base == nullptr)
+ return nullptr;
+ return make<QualifiedName>(SoFar, Base);
}
-// pt <expression> <expression> # expr->name
-
-const char*
-parse_arrow_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- const char* t1 = parse_expression(t, last, db);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto tmp = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<MemberExpr>(
- db.Names.back(), "->", tmp);
- first = t1;
- }
- }
- }
- return first;
+// <abi-tags> ::= <abi-tag> [<abi-tags>]
+// <abi-tag> ::= B <source-name>
+Node *Db::parseAbiTags(Node *N) {
+ while (consumeIf('B')) {
+ StringView SN = parseBareSourceName();
+ if (SN.empty())
+ return nullptr;
+ N = make<AbiTagAttr>(N, SN);
+ }
+ return N;
}
-// <ref-qualifier> ::= R # & ref-qualifier
-// <ref-qualifier> ::= O # && ref-qualifier
-
-// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
-
-const char*
-parse_function_type(const char* first, const char* last, Db& db)
-{
- if (first != last && *first == 'F')
- {
- const char* t = first+1;
- if (t != last)
- {
- if (*t == 'Y')
- {
- /* extern "C" */
- if (++t == last)
- return first;
- }
- const char* t1 = parse_type(t, last, db);
- if (t1 != t && !db.Names.empty())
- {
- Node* ret_type = db.Names.back();
- db.Names.pop_back();
- size_t params_begin = db.Names.size();
- t = t1;
- FunctionRefQual RefQuals = FrefQualNone;
- while (true)
- {
- if (t == last)
- {
- if (!db.Names.empty())
- db.Names.pop_back();
- return first;
- }
- if (*t == 'E')
- {
- ++t;
- break;
- }
- if (*t == 'v')
- {
- ++t;
- continue;
- }
- if (*t == 'R' && t+1 != last && t[1] == 'E')
- {
- RefQuals = FrefQualLValue;
- ++t;
- continue;
- }
- if (*t == 'O' && t+1 != last && t[1] == 'E')
- {
- RefQuals = FrefQualRValue;
- ++t;
- continue;
- }
- size_t k0 = db.Names.size();
- t1 = parse_type(t, last, db);
- size_t k1 = db.Names.size();
- if (t1 == t || t1 == last || k1 < k0)
- return first;
- t = t1;
- }
- if (db.Names.empty() || params_begin > db.Names.size())
- return first;
- Node* fty = db.make<FunctionType>(
- ret_type, db.popTrailingNodeArray(params_begin));
- if (RefQuals)
- fty = db.make<FunctionRefQualType>(fty, RefQuals);
- db.Names.push_back(fty);
- first = t;
- }
- }
- }
- return first;
+// <number> ::= [n] <non-negative decimal integer>
+StringView Db::parseNumber(bool AllowNegative) {
+ const char *Tmp = First;
+ if (AllowNegative)
+ consumeIf('n');
+ if (numLeft() == 0 || !std::isdigit(*First))
+ return StringView();
+ while (numLeft() != 0 && std::isdigit(*First))
+ ++First;
+ return StringView(Tmp, First);
}
-// <pointer-to-member-type> ::= M <class type> <member type>
-
-const char*
-parse_pointer_to_member_type(const char* first, const char* last, Db& db)
-{
- if (first != last && *first == 'M')
- {
- const char* t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- const char* t2 = parse_type(t, last, db);
- if (t2 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto func = std::move(db.Names.back());
- db.Names.pop_back();
- auto ClassType = std::move(db.Names.back());
- db.Names.back() =
- db.make<PointerToMemberType>(ClassType, func);
- first = t2;
- }
- }
- }
- return first;
+// <positive length number> ::= [0-9]*
+bool Db::parsePositiveInteger(size_t *Out) {
+ *Out = 0;
+ if (look() < '0' || look() > '9')
+ return true;
+ while (look() >= '0' && look() <= '9') {
+ *Out *= 10;
+ *Out += static_cast<size_t>(consume() - '0');
+ }
+ return false;
}
-// <array-type> ::= A <positive dimension number> _ <element type>
-// ::= A [<dimension expression>] _ <element type>
+StringView Db::parseBareSourceName() {
+ size_t Int = 0;
+ if (parsePositiveInteger(&Int) || numLeft() < Int)
+ return StringView();
+ StringView R(First, First + Int);
+ First += Int;
+ return R;
+}
-const char*
-parse_array_type(const char* first, const char* last, Db& db)
-{
- if (first != last && *first == 'A' && first+1 != last)
- {
- if (first[1] == '_')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<ArrayType>(db.Names.back());
- first = t;
- }
- }
- else if ('1' <= first[1] && first[1] <= '9')
- {
- const char* t = parse_number(first+1, last);
- if (t != last && *t == '_')
- {
- const char* t2 = parse_type(t+1, last, db);
- if (t2 != t+1)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<ArrayType>(db.Names.back(),
- StringView(first + 1, t));
- first = t2;
- }
- }
- }
- else
- {
- const char* t = parse_expression(first+1, last, db);
- if (t != first+1 && t != last && *t == '_')
- {
- const char* t2 = parse_type(++t, last, db);
- if (t2 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto base_type = std::move(db.Names.back());
- db.Names.pop_back();
- auto dimension_expr = std::move(db.Names.back());
- db.Names.back() =
- db.make<ArrayType>(base_type, dimension_expr);
- first = t2;
- }
- }
- }
+// <function-type> ::= [<CV-qualifiers>] [<exception-spec>] [Dx] F [Y] <bare-function-type> [<ref-qualifier>] E
+//
+// <exception-spec> ::= Do # non-throwing exception-specification (e.g., noexcept, throw())
+// ::= DO <expression> E # computed (instantiation-dependent) noexcept
+// ::= Dw <type>+ E # dynamic exception specification with instantiation-dependent types
+//
+// <ref-qualifier> ::= R # & ref-qualifier
+// <ref-qualifier> ::= O # && ref-qualifier
+Node *Db::parseFunctionType() {
+ Qualifiers CVQuals = parseCVQualifiers();
+
+ Node *ExceptionSpec = nullptr;
+ if (consumeIf("Do")) {
+ ExceptionSpec = make<NameType>("noexcept");
+ } else if (consumeIf("DO")) {
+ Node *E = parseExpr();
+ if (E == nullptr || !consumeIf('E'))
+ return nullptr;
+ ExceptionSpec = make<NoexceptSpec>(E);
+ } else if (consumeIf("Dw")) {
+ size_t SpecsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *T = parseType();
+ if (T == nullptr)
+ return nullptr;
+ Names.push_back(T);
}
- return first;
-}
+ ExceptionSpec =
+ make<DynamicExceptionSpec>(popTrailingNodeArray(SpecsBegin));
+ }
-// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
-// ::= DT <expression> E # decltype of an expression (C++0x)
+ consumeIf("Dx"); // transaction safe
-const char*
-parse_decltype(const char* first, const char* last, Db& db)
-{
- if (last - first >= 4 && first[0] == 'D')
- {
- switch (first[1])
- {
- case 't':
- case 'T':
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2 && t != last && *t == 'E')
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<EnclosingExpr>(
- "decltype(", db.Names.back(), ")");
- first = t+1;
- }
- }
- break;
- }
+ if (!consumeIf('F'))
+ return nullptr;
+ consumeIf('Y'); // extern "C"
+ Node *ReturnType = parseType();
+ if (ReturnType == nullptr)
+ return nullptr;
+
+ FunctionRefQual ReferenceQualifier = FrefQualNone;
+ size_t ParamsBegin = Names.size();
+ while (true) {
+ if (consumeIf('E'))
+ break;
+ if (consumeIf('v'))
+ continue;
+ if (consumeIf("RE")) {
+ ReferenceQualifier = FrefQualLValue;
+ break;
}
- return first;
+ if (consumeIf("OE")) {
+ ReferenceQualifier = FrefQualRValue;
+ break;
+ }
+ Node *T = parseType();
+ if (T == nullptr)
+ return nullptr;
+ Names.push_back(T);
+ }
+
+ NodeArray Params = popTrailingNodeArray(ParamsBegin);
+ return make<FunctionType>(ReturnType, Params, CVQuals,
+ ReferenceQualifier, ExceptionSpec);
}
// extension:
-// <vector-type> ::= Dv <positive dimension number> _
-// <extended element type>
+// <vector-type> ::= Dv <positive dimension number> _ <extended element type>
// ::= Dv [<dimension expression>] _ <element type>
// <extended element type> ::= <element type>
// ::= p # AltiVec vector pixel
+Node *Db::parseVectorType() {
+ if (!consumeIf("Dv"))
+ return nullptr;
+ if (look() >= '1' && look() <= '9') {
+ StringView DimensionNumber = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ if (consumeIf('p'))
+ return make<VectorType>(DimensionNumber);
+ Node *ElemType = parseType();
+ if (ElemType == nullptr)
+ return nullptr;
+ return make<VectorType>(ElemType, DimensionNumber);
+ }
-const char*
-parse_vector_type(const char* first, const char* last, Db& db)
-{
- if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
- {
- if ('1' <= first[2] && first[2] <= '9')
- {
- const char* t = parse_number(first+2, last);
- if (t == last || *t != '_')
- return first;
- const char* num = first + 2;
- size_t sz = static_cast<size_t>(t - num);
- if (++t != last)
- {
- if (*t != 'p')
- {
- const char* t1 = parse_type(t, last, db);
- if (t1 != t)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<VectorType>(db.Names.back(),
- StringView(num, num + sz));
- first = t1;
- }
- }
- else
- {
- ++t;
- db.Names.push_back(
- db.make<VectorType>(StringView(num, num + sz)));
- first = t;
- }
- }
- }
- else
- {
- Node* num = nullptr;
- const char* t1 = first+2;
- if (*t1 != '_')
- {
- const char* t = parse_expression(t1, last, db);
- if (t != t1)
- {
- if (db.Names.empty())
- return first;
- num = db.Names.back();
- db.Names.pop_back();
- t1 = t;
- }
- }
- if (t1 != last && *t1 == '_' && ++t1 != last)
- {
- const char* t = parse_type(t1, last, db);
- if (t != t1)
- {
- if (db.Names.empty())
- return first;
- if (num)
- db.Names.back() =
- db.make<VectorType>(db.Names.back(), num);
- else
- db.Names.back() =
- db.make<VectorType>(db.Names.back(), StringView());
- first = t;
- } else if (num)
- db.Names.push_back(num);
- }
- }
- }
- return first;
+ if (!consumeIf('_')) {
+ Node *DimExpr = parseExpr();
+ if (!DimExpr)
+ return nullptr;
+ if (!consumeIf('_'))
+ return nullptr;
+ Node *ElemType = parseType();
+ if (!ElemType)
+ return nullptr;
+ return make<VectorType>(ElemType, DimExpr);
+ }
+ Node *ElemType = parseType();
+ if (!ElemType)
+ return nullptr;
+ return make<VectorType>(ElemType, StringView());
}
-// <type> ::= <builtin-type>
-// ::= <function-type>
-// ::= <class-enum-type>
-// ::= <array-type>
-// ::= <pointer-to-member-type>
-// ::= <template-param>
-// ::= <template-template-param> <template-args>
-// ::= <decltype>
-// ::= <substitution>
-// ::= <CV-Qualifiers> <type>
-// ::= P <type> # pointer-to
-// ::= R <type> # reference-to
-// ::= O <type> # rvalue reference-to (C++0x)
-// ::= C <type> # complex pair (C 2000)
-// ::= G <type> # imaginary (C 2000)
-// ::= Dp <type> # pack expansion (C++0x)
-// ::= U <source-name> <type> # vendor extended type qualifier
-// extension := U <objc-name> <objc-type> # objc-type<identifier>
-// extension := <vector-type> # <vector-type> starts with Dv
-
-// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
-// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
-
-const char*
-parse_type(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'r':
- case 'V':
- case 'K':
- {
- Qualifiers cv = QualNone;
- const char* t = parse_cv_qualifiers(first, last, cv);
- if (t != first)
- {
- bool is_function = *t == 'F';
- size_t k0 = db.Names.size();
- const char* t1 = parse_type(t, last, db);
- size_t k1 = db.Names.size();
- if (t1 != t)
- {
- if (is_function)
- db.Subs.popPack();
- db.Subs.pushPack();
- for (size_t k = k0; k < k1; ++k)
- {
- if (cv) {
- if (is_function)
- db.Names[k] = db.make<FunctionQualType>(
- db.Names[k], cv);
- else
- db.Names[k] =
- db.make<QualType>(db.Names[k], cv);
- }
- db.Subs.pushSubstitutionIntoPack(db.Names[k]);
- }
- first = t1;
- }
- }
- }
- break;
- default:
- {
- const char* t = parse_builtin_type(first, last, db);
- if (t != first)
- {
- first = t;
- }
- else
- {
- switch (*first)
- {
- case 'A':
- t = parse_array_type(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- first = t;
- db.Subs.pushSubstitution(db.Names.back());
- }
- break;
- case 'C':
- t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<PostfixQualifiedType>(
- db.Names.back(), " complex");
- first = t;
- db.Subs.pushSubstitution(db.Names.back());
- }
- break;
- case 'F':
- t = parse_function_type(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- first = t;
- db.Subs.pushSubstitution(db.Names.back());
- }
- break;
- case 'G':
- t = parse_type(first+1, last, db);
- if (t != first+1)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<PostfixQualifiedType>(
- db.Names.back(), " imaginary");
- first = t;
- db.Subs.pushSubstitution(db.Names.back());
- }
- break;
- case 'M':
- t = parse_pointer_to_member_type(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- first = t;
- db.Subs.pushSubstitution(db.Names.back());
- }
- break;
- case 'O':
- {
- size_t k0 = db.Names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.Names.size();
- if (t != first+1)
- {
- db.Subs.pushPack();
- for (size_t k = k0; k < k1; ++k)
- {
- db.Names[k] =
- db.make<RValueReferenceType>(db.Names[k]);
- db.Subs.pushSubstitutionIntoPack(db.Names[k]);
- }
- first = t;
- }
- break;
- }
- case 'P':
- {
- size_t k0 = db.Names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.Names.size();
- if (t != first+1)
- {
- db.Subs.pushPack();
- for (size_t k = k0; k < k1; ++k)
- {
- db.Names[k] = db.make<PointerType>(db.Names[k]);
- db.Subs.pushSubstitutionIntoPack(db.Names[k]);
- }
- first = t;
- }
- break;
- }
- case 'R':
- {
- size_t k0 = db.Names.size();
- t = parse_type(first+1, last, db);
- size_t k1 = db.Names.size();
- if (t != first+1)
- {
- db.Subs.pushPack();
- for (size_t k = k0; k < k1; ++k)
- {
- db.Names[k] =
- db.make<LValueReferenceType>(db.Names[k]);
- db.Subs.pushSubstitutionIntoPack(db.Names[k]);
- }
- first = t;
- }
- break;
- }
- case 'T':
- {
- size_t k0 = db.Names.size();
- t = parse_template_param(first, last, db);
- size_t k1 = db.Names.size();
- if (t != first)
- {
- db.Subs.pushPack();
- for (size_t k = k0; k < k1; ++k)
- db.Subs.pushSubstitutionIntoPack(db.Names[k]);
- if (db.TryToParseTemplateArgs && k1 == k0+1)
- {
- const char* t1 = parse_template_args(t, last, db);
- if (t1 != t)
- {
- auto args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<
- NameWithTemplateArgs>(
- db.Names.back(), args);
- db.Subs.pushSubstitution(db.Names.back());
- t = t1;
- }
- }
- first = t;
- }
- break;
- }
- case 'U':
- if (first+1 != last)
- {
- t = parse_source_name(first+1, last, db);
- if (t != first+1)
- {
- const char* t2 = parse_type(t, last, db);
- if (t2 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto type = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KNameType ||
- !static_cast<NameType*>(db.Names.back())->getName().startsWith("objcproto"))
- {
- db.Names.back() = db.make<VendorExtQualType>(type, db.Names.back());
- }
- else
- {
- auto* proto = static_cast<NameType*>(db.Names.back());
- db.Names.pop_back();
- t = parse_source_name(proto->getName().begin() + 9, proto->getName().end(), db);
- if (t != proto->getName().begin() + 9)
- {
- db.Names.back() = db.make<ObjCProtoName>(type, db.Names.back());
- }
- else
- {
- db.Names.push_back(db.make<VendorExtQualType>(type, proto));
- }
- }
- db.Subs.pushSubstitution(db.Names.back());
- first = t2;
- }
- }
- }
- break;
- case 'S':
- if (first+1 != last && first[1] == 't')
- {
- t = parse_name(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- }
- }
- else
- {
- t = parse_substitution(first, last, db);
- if (t != first)
- {
- first = t;
- // Parsed a substitution. If the substitution is a
- // <template-param> it might be followed by <template-args>.
- if (db.TryToParseTemplateArgs)
- {
- t = parse_template_args(first, last, db);
- if (t != first)
- {
- if (db.Names.size() < 2)
- return first;
- auto template_args = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<
- NameWithTemplateArgs>(
- db.Names.back(), template_args);
- // Need to create substitution for <template-template-param> <template-args>
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- }
- }
- }
- }
- break;
- case 'D':
- if (first+1 != last)
- {
- switch (first[1])
- {
- case 'p':
- {
- size_t k0 = db.Names.size();
- t = parse_type(first+2, last, db);
- size_t k1 = db.Names.size();
- if (t != first+2)
- {
- db.Subs.pushPack();
- for (size_t k = k0; k < k1; ++k)
- db.Subs.pushSubstitutionIntoPack(db.Names[k]);
- first = t;
- return first;
- }
- break;
- }
- case 't':
- case 'T':
- t = parse_decltype(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- return first;
- }
- break;
- case 'v':
- t = parse_vector_type(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- return first;
- }
- break;
- }
- }
- _LIBCPP_FALLTHROUGH();
- default:
- // must check for builtin-types before class-enum-types to avoid
- // ambiguities with operator-names
- t = parse_builtin_type(first, last, db);
- if (t != first)
- {
- first = t;
- }
- else
- {
- t = parse_name(first, last, db);
- if (t != first)
- {
- if (db.Names.empty())
- return first;
- db.Subs.pushSubstitution(db.Names.back());
- first = t;
- }
- }
- break;
- }
- }
- break;
- }
- }
- }
- return first;
+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+// ::= DT <expression> E # decltype of an expression (C++0x)
+Node *Db::parseDecltype() {
+ if (!consumeIf('D'))
+ return nullptr;
+ if (!consumeIf('t') && !consumeIf('T'))
+ return nullptr;
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return nullptr;
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<EnclosingExpr>("decltype(", E, ")");
}
-// <operator-name>
-// ::= aa # &&
-// ::= ad # & (unary)
-// ::= an # &
-// ::= aN # &=
-// ::= aS # =
-// ::= cl # ()
-// ::= cm # ,
-// ::= co # ~
-// ::= cv <type> # (cast)
-// ::= da # delete[]
-// ::= de # * (unary)
-// ::= dl # delete
-// ::= dv # /
-// ::= dV # /=
-// ::= eo # ^
-// ::= eO # ^=
-// ::= eq # ==
-// ::= ge # >=
-// ::= gt # >
-// ::= ix # []
-// ::= le # <=
-// ::= li <source-name> # operator ""
-// ::= ls # <<
-// ::= lS # <<=
-// ::= lt # <
-// ::= mi # -
-// ::= mI # -=
-// ::= ml # *
-// ::= mL # *=
-// ::= mm # -- (postfix in <expression> context)
-// ::= na # new[]
-// ::= ne # !=
-// ::= ng # - (unary)
-// ::= nt # !
-// ::= nw # new
-// ::= oo # ||
-// ::= or # |
-// ::= oR # |=
-// ::= pm # ->*
-// ::= pl # +
-// ::= pL # +=
-// ::= pp # ++ (postfix in <expression> context)
-// ::= ps # + (unary)
-// ::= pt # ->
-// ::= qu # ?
-// ::= rm # %
-// ::= rM # %=
-// ::= rs # >>
-// ::= rS # >>=
-// ::= v <digit> <source-name> # vendor extended operator
-// extension ::= <operator-name> <abi-tag-seq>
-const char*
-parse_operator_name(const char* first, const char* last, Db& db)
-{
- const char* original_first = first;
- if (last - first >= 2)
- {
- switch (first[0])
- {
- case 'a':
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(db.make<NameType>("operator&&"));
- first += 2;
- break;
- case 'd':
- case 'n':
- db.Names.push_back(db.make<NameType>("operator&"));
- first += 2;
- break;
- case 'N':
- db.Names.push_back(db.make<NameType>("operator&="));
- first += 2;
- break;
- case 'S':
- db.Names.push_back(db.make<NameType>("operator="));
- first += 2;
- break;
- }
- break;
- case 'c':
- switch (first[1])
- {
- case 'l':
- db.Names.push_back(db.make<NameType>("operator()"));
- first += 2;
- break;
- case 'm':
- db.Names.push_back(db.make<NameType>("operator,"));
- first += 2;
- break;
- case 'o':
- db.Names.push_back(db.make<NameType>("operator~"));
- first += 2;
- break;
- case 'v':
- {
- bool TryToParseTemplateArgs = db.TryToParseTemplateArgs;
- db.TryToParseTemplateArgs = false;
- const char* t = parse_type(first+2, last, db);
- db.TryToParseTemplateArgs = TryToParseTemplateArgs;
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<ConversionOperatorType>(db.Names.back());
- db.ParsedCtorDtorCV = true;
- first = t;
- }
- }
- break;
- }
- break;
- case 'd':
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(db.make<NameType>("operator delete[]"));
- first += 2;
- break;
- case 'e':
- db.Names.push_back(db.make<NameType>("operator*"));
- first += 2;
- break;
- case 'l':
- db.Names.push_back(db.make<NameType>("operator delete"));
- first += 2;
- break;
- case 'v':
- db.Names.push_back(db.make<NameType>("operator/"));
- first += 2;
- break;
- case 'V':
- db.Names.push_back(db.make<NameType>("operator/="));
- first += 2;
- break;
- }
- break;
- case 'e':
- switch (first[1])
- {
- case 'o':
- db.Names.push_back(db.make<NameType>("operator^"));
- first += 2;
- break;
- case 'O':
- db.Names.push_back(db.make<NameType>("operator^="));
- first += 2;
- break;
- case 'q':
- db.Names.push_back(db.make<NameType>("operator=="));
- first += 2;
- break;
- }
- break;
- case 'g':
- switch (first[1])
- {
- case 'e':
- db.Names.push_back(db.make<NameType>("operator>="));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator>"));
- first += 2;
- break;
- }
- break;
- case 'i':
- if (first[1] == 'x')
- {
- db.Names.push_back(db.make<NameType>("operator[]"));
- first += 2;
- }
- break;
- case 'l':
- switch (first[1])
- {
- case 'e':
- db.Names.push_back(db.make<NameType>("operator<="));
- first += 2;
- break;
- case 'i':
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<LiteralOperator>(db.Names.back());
- first = t;
- }
- }
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("operator<<"));
- first += 2;
- break;
- case 'S':
- db.Names.push_back(db.make<NameType>("operator<<="));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator<"));
- first += 2;
- break;
- }
- break;
- case 'm':
- switch (first[1])
- {
- case 'i':
- db.Names.push_back(db.make<NameType>("operator-"));
- first += 2;
- break;
- case 'I':
- db.Names.push_back(db.make<NameType>("operator-="));
- first += 2;
- break;
- case 'l':
- db.Names.push_back(db.make<NameType>("operator*"));
- first += 2;
- break;
- case 'L':
- db.Names.push_back(db.make<NameType>("operator*="));
- first += 2;
- break;
- case 'm':
- db.Names.push_back(db.make<NameType>("operator--"));
- first += 2;
- break;
- }
- break;
- case 'n':
- switch (first[1])
- {
- case 'a':
- db.Names.push_back(db.make<NameType>("operator new[]"));
- first += 2;
- break;
- case 'e':
- db.Names.push_back(db.make<NameType>("operator!="));
- first += 2;
- break;
- case 'g':
- db.Names.push_back(db.make<NameType>("operator-"));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator!"));
- first += 2;
- break;
- case 'w':
- db.Names.push_back(db.make<NameType>("operator new"));
- first += 2;
- break;
- }
- break;
- case 'o':
- switch (first[1])
- {
- case 'o':
- db.Names.push_back(db.make<NameType>("operator||"));
- first += 2;
- break;
- case 'r':
- db.Names.push_back(db.make<NameType>("operator|"));
- first += 2;
- break;
- case 'R':
- db.Names.push_back(db.make<NameType>("operator|="));
- first += 2;
- break;
- }
- break;
- case 'p':
- switch (first[1])
- {
- case 'm':
- db.Names.push_back(db.make<NameType>("operator->*"));
- first += 2;
- break;
- case 'l':
- db.Names.push_back(db.make<NameType>("operator+"));
- first += 2;
- break;
- case 'L':
- db.Names.push_back(db.make<NameType>("operator+="));
- first += 2;
- break;
- case 'p':
- db.Names.push_back(db.make<NameType>("operator++"));
- first += 2;
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("operator+"));
- first += 2;
- break;
- case 't':
- db.Names.push_back(db.make<NameType>("operator->"));
- first += 2;
- break;
- }
- break;
- case 'q':
- if (first[1] == 'u')
- {
- db.Names.push_back(db.make<NameType>("operator?"));
- first += 2;
- }
- break;
- case 'r':
- switch (first[1])
- {
- case 'm':
- db.Names.push_back(db.make<NameType>("operator%"));
- first += 2;
- break;
- case 'M':
- db.Names.push_back(db.make<NameType>("operator%="));
- first += 2;
- break;
- case 's':
- db.Names.push_back(db.make<NameType>("operator>>"));
- first += 2;
- break;
- case 'S':
- db.Names.push_back(db.make<NameType>("operator>>="));
- first += 2;
- break;
- }
- break;
- case 'v':
- if (std::isdigit(first[1]))
- {
- const char* t = parse_source_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<ConversionOperatorType>(db.Names.back());
- first = t;
- }
- }
- break;
- }
- }
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+Node *Db::parseArrayType() {
+ if (!consumeIf('A'))
+ return nullptr;
+
+ if (std::isdigit(look())) {
+ StringView Dimension = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<ArrayType>(Ty, Dimension);
+ }
- if (original_first != first)
- first = parse_abi_tag_seq(first, last, db);
+ if (!consumeIf('_')) {
+ Node *DimExpr = parseExpr();
+ if (DimExpr == nullptr)
+ return nullptr;
+ if (!consumeIf('_'))
+ return nullptr;
+ Node *ElementType = parseType();
+ if (ElementType == nullptr)
+ return nullptr;
+ return make<ArrayType>(ElementType, DimExpr);
+ }
- return first;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<ArrayType>(Ty);
}
-const char*
-parse_integer_literal(const char* first, const char* last, StringView lit, Db& db)
-{
- const char* t = parse_number(first, last);
- if (t != first && t != last && *t == 'E')
- {
- db.Names.push_back(
- db.make<IntegerExpr>(lit, StringView(first, t)));
- first = t+1;
- }
- return first;
+// <pointer-to-member-type> ::= M <class type> <member type>
+Node *Db::parsePointerToMemberType() {
+ if (!consumeIf('M'))
+ return nullptr;
+ Node *ClassType = parseType();
+ if (ClassType == nullptr)
+ return nullptr;
+ Node *MemberType = parseType();
+ if (MemberType == nullptr)
+ return nullptr;
+ return make<PointerToMemberType>(ClassType, MemberType);
}
-// <expr-primary> ::= L <type> <value number> E # integer literal
-// ::= L <type> <value float> E # floating literal
-// ::= L <string type> E # string literal
-// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
-// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
-// ::= L <mangled-name> E # external name
+// <class-enum-type> ::= <name> # non-dependent type name, dependent type name, or dependent typename-specifier
+// ::= Ts <name> # dependent elaborated type specifier using 'struct' or 'class'
+// ::= Tu <name> # dependent elaborated type specifier using 'union'
+// ::= Te <name> # dependent elaborated type specifier using 'enum'
+Node *Db::parseClassEnumType() {
+ StringView ElabSpef;
+ if (consumeIf("Ts"))
+ ElabSpef = "struct";
+ else if (consumeIf("Tu"))
+ ElabSpef = "union";
+ else if (consumeIf("Te"))
+ ElabSpef = "enum";
+
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+
+ if (!ElabSpef.empty())
+ return make<ElaboratedTypeSpefType>(ElabSpef, Name);
+
+ return Name;
+}
-const char*
-parse_expr_primary(const char* first, const char* last, Db& db)
-{
- if (last - first >= 4 && *first == 'L')
- {
- switch (first[1])
- {
- case 'w':
- {
- const char* t = parse_integer_literal(first+2, last, "wchar_t", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'b':
- if (first[3] == 'E')
- {
- switch (first[2])
- {
- case '0':
- db.Names.push_back(db.make<BoolExpr>(0));
- first += 4;
- break;
- case '1':
- db.Names.push_back(db.make<BoolExpr>(1));
- first += 4;
- break;
- }
- }
- break;
- case 'c':
- {
- const char* t = parse_integer_literal(first+2, last, "char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'a':
- {
- const char* t = parse_integer_literal(first+2, last, "signed char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'h':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned char", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 's':
- {
- const char* t = parse_integer_literal(first+2, last, "short", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 't':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned short", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'i':
- {
- const char* t = parse_integer_literal(first+2, last, "", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'j':
- {
- const char* t = parse_integer_literal(first+2, last, "u", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'l':
- {
- const char* t = parse_integer_literal(first+2, last, "l", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'm':
- {
- const char* t = parse_integer_literal(first+2, last, "ul", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'x':
- {
- const char* t = parse_integer_literal(first+2, last, "ll", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'y':
- {
- const char* t = parse_integer_literal(first+2, last, "ull", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'n':
- {
- const char* t = parse_integer_literal(first+2, last, "__int128", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'o':
- {
- const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'f':
- {
- const char* t = parse_floating_number<float>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'd':
- {
- const char* t = parse_floating_number<double>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case 'e':
- {
- const char* t = parse_floating_number<long double>(first+2, last, db);
- if (t != first+2)
- first = t;
- }
- break;
- case '_':
- if (first[2] == 'Z')
- {
- const char* t = parse_encoding(first+3, last, db);
- if (t != first+3 && t != last && *t == 'E')
- first = t+1;
- }
- break;
- case 'T':
- // Invalid mangled name per
- // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
- break;
- default:
- {
- // might be named type
- const char* t = parse_type(first+1, last, db);
- if (t != first+1 && t != last)
- {
- if (*t != 'E')
- {
- const char* n = t;
- for (; n != last && isdigit(*n); ++n)
- ;
- if (n != t && n != last && *n == 'E')
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<IntegerCastExpr>(
- db.Names.back(), StringView(t, n));
- first = n+1;
- break;
- }
- }
- else
- {
- first = t+1;
- break;
- }
- }
- }
- }
+// <qualified-type> ::= <qualifiers> <type>
+// <qualifiers> ::= <extended-qualifier>* <CV-qualifiers>
+// <extended-qualifier> ::= U <source-name> [<template-args>] # vendor extended type qualifier
+Node *Db::parseQualifiedType() {
+ if (consumeIf('U')) {
+ StringView Qual = parseBareSourceName();
+ if (Qual.empty())
+ return nullptr;
+
+ // FIXME parse the optional <template-args> here!
+
+ // extension ::= U <objc-name> <objc-type> # objc-type<identifier>
+ if (Qual.startsWith("objcproto")) {
+ StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto"));
+ StringView Proto;
+ {
+ SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()),
+ SaveLast(Last, ProtoSourceName.end());
+ Proto = parseBareSourceName();
+ }
+ if (Proto.empty())
+ return nullptr;
+ Node *Child = parseQualifiedType();
+ if (Child == nullptr)
+ return nullptr;
+ return make<ObjCProtoName>(Child, Proto);
}
- return first;
+
+ Node *Child = parseQualifiedType();
+ if (Child == nullptr)
+ return nullptr;
+ return make<VendorExtQualType>(Child, Qual);
+ }
+
+ Qualifiers Quals = parseCVQualifiers();
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ if (Quals != QualNone)
+ Ty = make<QualType>(Ty, Quals);
+ return Ty;
}
-Node* maybe_change_special_sub_name(Node* inp, Db& db)
-{
- if (inp->K != Node::KSpecialSubstitution)
- return inp;
- auto Kind = static_cast<SpecialSubstitution*>(inp)->SSK;
- switch (Kind)
- {
- case SpecialSubKind::string:
- case SpecialSubKind::istream:
- case SpecialSubKind::ostream:
- case SpecialSubKind::iostream:
- return db.make<ExpandedSpecialSubstitution>(Kind);
- default:
- break;
+// <type> ::= <builtin-type>
+// ::= <qualified-type>
+// ::= <function-type>
+// ::= <class-enum-type>
+// ::= <array-type>
+// ::= <pointer-to-member-type>
+// ::= <template-param>
+// ::= <template-template-param> <template-args>
+// ::= <decltype>
+// ::= P <type> # pointer
+// ::= R <type> # l-value reference
+// ::= O <type> # r-value reference (C++11)
+// ::= C <type> # complex pair (C99)
+// ::= G <type> # imaginary (C99)
+// ::= <substitution> # See Compression below
+// extension ::= U <objc-name> <objc-type> # objc-type<identifier>
+// extension ::= <vector-type> # <vector-type> starts with Dv
+//
+// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+// <objc-type> ::= <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+Node *Db::parseType() {
+ Node *Result = nullptr;
+
+ switch (look()) {
+ // ::= <qualified-type>
+ case 'r':
+ case 'V':
+ case 'K': {
+ unsigned AfterQuals = 0;
+ if (look(AfterQuals) == 'r') ++AfterQuals;
+ if (look(AfterQuals) == 'V') ++AfterQuals;
+ if (look(AfterQuals) == 'K') ++AfterQuals;
+
+ if (look(AfterQuals) == 'F' ||
+ (look(AfterQuals) == 'D' &&
+ (look(AfterQuals + 1) == 'o' || look(AfterQuals + 1) == 'O' ||
+ look(AfterQuals + 1) == 'w' || look(AfterQuals + 1) == 'x'))) {
+ Result = parseFunctionType();
+ break;
+ }
+ _LIBCPP_FALLTHROUGH();
+ }
+ case 'U': {
+ Result = parseQualifiedType();
+ break;
+ }
+ // <builtin-type> ::= v # void
+ case 'v':
+ ++First;
+ return make<NameType>("void");
+ // ::= w # wchar_t
+ case 'w':
+ ++First;
+ return make<NameType>("wchar_t");
+ // ::= b # bool
+ case 'b':
+ ++First;
+ return make<NameType>("bool");
+ // ::= c # char
+ case 'c':
+ ++First;
+ return make<NameType>("char");
+ // ::= a # signed char
+ case 'a':
+ ++First;
+ return make<NameType>("signed char");
+ // ::= h # unsigned char
+ case 'h':
+ ++First;
+ return make<NameType>("unsigned char");
+ // ::= s # short
+ case 's':
+ ++First;
+ return make<NameType>("short");
+ // ::= t # unsigned short
+ case 't':
+ ++First;
+ return make<NameType>("unsigned short");
+ // ::= i # int
+ case 'i':
+ ++First;
+ return make<NameType>("int");
+ // ::= j # unsigned int
+ case 'j':
+ ++First;
+ return make<NameType>("unsigned int");
+ // ::= l # long
+ case 'l':
+ ++First;
+ return make<NameType>("long");
+ // ::= m # unsigned long
+ case 'm':
+ ++First;
+ return make<NameType>("unsigned long");
+ // ::= x # long long, __int64
+ case 'x':
+ ++First;
+ return make<NameType>("long long");
+ // ::= y # unsigned long long, __int64
+ case 'y':
+ ++First;
+ return make<NameType>("unsigned long long");
+ // ::= n # __int128
+ case 'n':
+ ++First;
+ return make<NameType>("__int128");
+ // ::= o # unsigned __int128
+ case 'o':
+ ++First;
+ return make<NameType>("unsigned __int128");
+ // ::= f # float
+ case 'f':
+ ++First;
+ return make<NameType>("float");
+ // ::= d # double
+ case 'd':
+ ++First;
+ return make<NameType>("double");
+ // ::= e # long double, __float80
+ case 'e':
+ ++First;
+ return make<NameType>("long double");
+ // ::= g # __float128
+ case 'g':
+ ++First;
+ return make<NameType>("__float128");
+ // ::= z # ellipsis
+ case 'z':
+ ++First;
+ return make<NameType>("...");
+
+ // <builtin-type> ::= u <source-name> # vendor extended type
+ case 'u': {
+ ++First;
+ StringView Res = parseBareSourceName();
+ if (Res.empty())
+ return nullptr;
+ return make<NameType>(Res);
+ }
+ case 'D':
+ switch (look(1)) {
+ // ::= Dd # IEEE 754r decimal floating point (64 bits)
+ case 'd':
+ First += 2;
+ return make<NameType>("decimal64");
+ // ::= De # IEEE 754r decimal floating point (128 bits)
+ case 'e':
+ First += 2;
+ return make<NameType>("decimal128");
+ // ::= Df # IEEE 754r decimal floating point (32 bits)
+ case 'f':
+ First += 2;
+ return make<NameType>("decimal32");
+ // ::= Dh # IEEE 754r half-precision floating point (16 bits)
+ case 'h':
+ First += 2;
+ return make<NameType>("decimal16");
+ // ::= Di # char32_t
+ case 'i':
+ First += 2;
+ return make<NameType>("char32_t");
+ // ::= Ds # char16_t
+ case 's':
+ First += 2;
+ return make<NameType>("char16_t");
+ // ::= Da # auto (in dependent new-expressions)
+ case 'a':
+ First += 2;
+ return make<NameType>("auto");
+ // ::= Dc # decltype(auto)
+ case 'c':
+ First += 2;
+ return make<NameType>("decltype(auto)");
+ // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+ case 'n':
+ First += 2;
+ return make<NameType>("std::nullptr_t");
+
+ // ::= <decltype>
+ case 't':
+ case 'T': {
+ Result = parseDecltype();
+ break;
+ }
+ // extension ::= <vector-type> # <vector-type> starts with Dv
+ case 'v': {
+ Result = parseVectorType();
+ break;
+ }
+ // ::= Dp <type> # pack expansion (C++0x)
+ case 'p': {
+ First += 2;
+ Node *Child = parseType();
+ if (!Child)
+ return nullptr;
+ Result = make<ParameterPackExpansion>(Child);
+ break;
+ }
+ // Exception specifier on a function type.
+ case 'o':
+ case 'O':
+ case 'w':
+ // Transaction safe function type.
+ case 'x':
+ Result = parseFunctionType();
+ break;
+ }
+ break;
+ // ::= <function-type>
+ case 'F': {
+ Result = parseFunctionType();
+ break;
+ }
+ // ::= <array-type>
+ case 'A': {
+ Result = parseArrayType();
+ break;
+ }
+ // ::= <pointer-to-member-type>
+ case 'M': {
+ Result = parsePointerToMemberType();
+ break;
+ }
+ // ::= <template-param>
+ case 'T': {
+ // This could be an elaborate type specifier on a <class-enum-type>.
+ if (look(1) == 's' || look(1) == 'u' || look(1) == 'e') {
+ Result = parseClassEnumType();
+ break;
}
- return inp;
-}
-// <ctor-dtor-name> ::= C1 # complete object constructor
-// ::= C2 # base object constructor
-// ::= C3 # complete object allocating constructor
-// extension ::= C5 # ?
-// ::= D0 # deleting destructor
-// ::= D1 # complete object destructor
-// ::= D2 # base object destructor
-// extension ::= D5 # ?
-// extension ::= <ctor-dtor-name> <abi-tag-seq>
-const char*
-parse_ctor_dtor_name(const char* first, const char* last, Db& db)
-{
- if (last-first >= 2 && !db.Names.empty())
- {
- switch (first[0])
- {
- case 'C':
- switch (first[1])
- {
- case '1':
- case '2':
- case '3':
- case '5':
- if (db.Names.empty())
- return first;
- db.Names.back() =
- maybe_change_special_sub_name(db.Names.back(), db);
- db.Names.push_back(
- db.make<CtorDtorName>(db.Names.back(), false));
- first += 2;
- first = parse_abi_tag_seq(first, last, db);
- db.ParsedCtorDtorCV = true;
- break;
- }
- break;
- case 'D':
- switch (first[1])
- {
- case '0':
- case '1':
- case '2':
- case '5':
- if (db.Names.empty())
- return first;
- db.Names.push_back(
- db.make<CtorDtorName>(db.Names.back(), true));
- first += 2;
- first = parse_abi_tag_seq(first, last, db);
- db.ParsedCtorDtorCV = true;
- break;
- }
- break;
- }
+ Result = parseTemplateParam();
+ if (Result == nullptr)
+ return nullptr;
+
+ // Result could be either of:
+ // <type> ::= <template-param>
+ // <type> ::= <template-template-param> <template-args>
+ //
+ // <template-template-param> ::= <template-param>
+ // ::= <substitution>
+ //
+ // If this is followed by some <template-args>, and we're permitted to
+ // parse them, take the second production.
+
+ if (TryToParseTemplateArgs && look() == 'I') {
+ Node *TA = parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ Result = make<NameWithTemplateArgs>(Result, TA);
}
- return first;
-}
+ break;
+ }
+ // ::= P <type> # pointer
+ case 'P': {
+ ++First;
+ Node *Ptr = parseType();
+ if (Ptr == nullptr)
+ return nullptr;
+ Result = make<PointerType>(Ptr);
+ break;
+ }
+ // ::= R <type> # l-value reference
+ case 'R': {
+ ++First;
+ Node *Ref = parseType();
+ if (Ref == nullptr)
+ return nullptr;
+ Result = make<ReferenceType>(Ref, ReferenceKind::LValue);
+ break;
+ }
+ // ::= O <type> # r-value reference (C++11)
+ case 'O': {
+ ++First;
+ Node *Ref = parseType();
+ if (Ref == nullptr)
+ return nullptr;
+ Result = make<ReferenceType>(Ref, ReferenceKind::RValue);
+ break;
+ }
+ // ::= C <type> # complex pair (C99)
+ case 'C': {
+ ++First;
+ Node *P = parseType();
+ if (P == nullptr)
+ return nullptr;
+ Result = make<PostfixQualifiedType>(P, " complex");
+ break;
+ }
+ // ::= G <type> # imaginary (C99)
+ case 'G': {
+ ++First;
+ Node *P = parseType();
+ if (P == nullptr)
+ return P;
+ Result = make<PostfixQualifiedType>(P, " imaginary");
+ break;
+ }
+ // ::= <substitution> # See Compression below
+ case 'S': {
+ if (look(1) && look(1) != 't') {
+ Node *Sub = parseSubstitution();
+ if (Sub == nullptr)
+ return nullptr;
-// <unnamed-type-name> ::= Ut [<nonnegative number>] _ [<abi-tag-seq>]
-// ::= <closure-type-name>
-//
-// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
-//
-// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters
-const char*
-parse_unnamed_type_name(const char* first, const char* last, Db& db)
-{
- if (last - first > 2 && first[0] == 'U')
- {
- char type = first[1];
- switch (type)
- {
- case 't':
- {
- const char* t0 = first+2;
- if (t0 == last)
- return first;
- StringView count;
- if (std::isdigit(*t0))
- {
- const char* t1 = t0 + 1;
- while (t1 != last && std::isdigit(*t1))
- ++t1;
- count = StringView(t0, t1);
- t0 = t1;
- }
- if (t0 == last || *t0 != '_')
- return first;
- db.Names.push_back(db.make<UnnamedTypeName>(count));
- first = t0 + 1;
- first = parse_abi_tag_seq(first, last, db);
- }
- break;
- case 'l':
- {
- size_t begin_pos = db.Names.size();
- const char* t0 = first+2;
- NodeArray lambda_params;
- if (first[2] == 'v')
- {
- ++t0;
- }
- else
- {
- while (true)
- {
- const char* t1 = parse_type(t0, last, db);
- if (t1 == t0)
- break;
- t0 = t1;
- }
- if (db.Names.size() < begin_pos)
- return first;
- lambda_params = db.popTrailingNodeArray(begin_pos);
- }
- if (t0 == last || *t0 != 'E')
- return first;
- ++t0;
- if (t0 == last)
- return first;
- StringView count;
- if (std::isdigit(*t0))
- {
- const char* t1 = t0 + 1;
- while (t1 != last && std::isdigit(*t1))
- ++t1;
- count = StringView(t0, t1);
- t0 = t1;
- }
- if (t0 == last || *t0 != '_')
- return first;
- db.Names.push_back(db.make<LambdaTypeName>(lambda_params, count));
- first = t0 + 1;
- }
- break;
- }
+ // Sub could be either of:
+ // <type> ::= <substitution>
+ // <type> ::= <template-template-param> <template-args>
+ //
+ // <template-template-param> ::= <template-param>
+ // ::= <substitution>
+ //
+ // If this is followed by some <template-args>, and we're permitted to
+ // parse them, take the second production.
+
+ if (TryToParseTemplateArgs && look() == 'I') {
+ Node *TA = parseTemplateArgs();
+ if (TA == nullptr)
+ return nullptr;
+ Result = make<NameWithTemplateArgs>(Sub, TA);
+ break;
+ }
+
+ // If all we parsed was a substitution, don't re-insert into the
+ // substitution table.
+ return Sub;
}
- return first;
+ _LIBCPP_FALLTHROUGH();
+ }
+ // ::= <class-enum-type>
+ default: {
+ Result = parseClassEnumType();
+ break;
+ }
+ }
+
+ // If we parsed a type, insert it into the substitution table. Note that all
+ // <builtin-type>s and <substitution>s have already bailed out, because they
+ // don't get substitutions.
+ if (Result != nullptr)
+ Subs.push_back(Result);
+ return Result;
}
-// <unqualified-name> ::= <operator-name>
-// ::= <ctor-dtor-name>
-// ::= <source-name>
-// ::= <unnamed-type-name>
+Node *Db::parsePrefixExpr(StringView Kind) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return nullptr;
+ return make<PrefixExpr>(Kind, E);
+}
-const char*
-parse_unqualified_name(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t;
- switch (*first)
- {
- case 'C':
- case 'D':
- t = parse_ctor_dtor_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case 'U':
- t = parse_unnamed_type_name(first, last, db);
- if (t != first)
- first = t;
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- t = parse_source_name(first, last, db);
- if (t != first)
- first = t;
- break;
- default:
- t = parse_operator_name(first, last, db);
- if (t != first)
- first = t;
- break;
- };
- }
- return first;
+Node *Db::parseBinaryExpr(StringView Kind) {
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<BinaryExpr>(LHS, Kind, RHS);
}
-// <unscoped-name> ::= <unqualified-name>
-// ::= St <unqualified-name> # ::std::
-// extension ::= StL<unqualified-name>
+Node *Db::parseIntegerLiteral(StringView Lit) {
+ StringView Tmp = parseNumber(true);
+ if (!Tmp.empty() && consumeIf('E'))
+ return make<IntegerExpr>(Lit, Tmp);
+ return nullptr;
+}
-const char*
-parse_unscoped_name(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- const char* t0 = first;
- bool St = false;
- if (first[0] == 'S' && first[1] == 't')
- {
- t0 += 2;
- St = true;
- if (t0 != last && *t0 == 'L')
- ++t0;
- }
- const char* t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0)
- {
- if (St)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<StdQualifiedName>(db.Names.back());
- }
- first = t1;
- }
- }
- return first;
+// <CV-Qualifiers> ::= [r] [V] [K]
+Qualifiers Db::parseCVQualifiers() {
+ Qualifiers CVR = QualNone;
+ if (consumeIf('r'))
+ addQualifiers(CVR, QualRestrict);
+ if (consumeIf('V'))
+ addQualifiers(CVR, QualVolatile);
+ if (consumeIf('K'))
+ addQualifiers(CVR, QualConst);
+ return CVR;
}
-// at <type> # alignof (a type)
+// <function-param> ::= fp <top-level CV-Qualifiers> _ # L == 0, first parameter
+// ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter
+// ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+Node *Db::parseFunctionParam() {
+ if (consumeIf("fp")) {
+ parseCVQualifiers();
+ StringView Num = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<FunctionParam>(Num);
+ }
+ if (consumeIf("fL")) {
+ if (parseNumber().empty())
+ return nullptr;
+ if (!consumeIf('p'))
+ return nullptr;
+ parseCVQualifiers();
+ StringView Num = parseNumber();
+ if (!consumeIf('_'))
+ return nullptr;
+ return make<FunctionParam>(Num);
+ }
+ return nullptr;
+}
-const char*
-parse_alignof_type(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
- {
- const char* t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<EnclosingExpr>("alignof (", db.Names.back(), ")");
- first = t;
- }
+// [gs] nw <expression>* _ <type> E # new (expr-list) type
+// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+// [gs] na <expression>* _ <type> E # new[] (expr-list) type
+// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+// <initializer> ::= pi <expression>* E # parenthesized initialization
+Node *Db::parseNewExpr() {
+ bool Global = consumeIf("gs");
+ bool IsArray = look(1) == 'a';
+ if (!consumeIf("nw") && !consumeIf("na"))
+ return nullptr;
+ size_t Exprs = Names.size();
+ while (!consumeIf('_')) {
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ Names.push_back(Ex);
+ }
+ NodeArray ExprList = popTrailingNodeArray(Exprs);
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return Ty;
+ if (consumeIf("pi")) {
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *Init = parseExpr();
+ if (Init == nullptr)
+ return Init;
+ Names.push_back(Init);
}
- return first;
+ NodeArray Inits = popTrailingNodeArray(InitsBegin);
+ return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray);
+ } else if (!consumeIf('E'))
+ return nullptr;
+ return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray);
}
-// az <expression> # alignof (a expression)
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+Node *Db::parseConversionExpr() {
+ if (!consumeIf("cv"))
+ return nullptr;
+ Node *Ty;
+ {
+ SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false);
+ Ty = parseType();
+ }
-const char*
-parse_alignof_expr(const char* first, const char* last, Db& db)
-{
- if (last - first >= 3 && first[0] == 'a' && first[1] == 'z')
- {
- const char* t = parse_expression(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<EnclosingExpr>("alignof (", db.Names.back(), ")");
- first = t;
- }
+ if (Ty == nullptr)
+ return nullptr;
+
+ if (consumeIf('_')) {
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
}
- return first;
+ NodeArray Exprs = popTrailingNodeArray(ExprsBegin);
+ return make<ConversionExpr>(Ty, Exprs);
+ }
+
+ Node *E[1] = {parseExpr()};
+ if (E[0] == nullptr)
+ return nullptr;
+ return make<ConversionExpr>(Ty, makeNodeArray(E, E + 1));
}
-const char*
-parse_noexcept_expression(const char* first, const char* last, Db& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<EnclosingExpr>("noexcept (", db.Names.back(), ")");
- first = t1;
+// <expr-primary> ::= L <type> <value number> E # integer literal
+// ::= L <type> <value float> E # floating literal
+// ::= L <string type> E # string literal
+// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+// FIXME: ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000)
+// ::= L <mangled-name> E # external name
+Node *Db::parseExprPrimary() {
+ if (!consumeIf('L'))
+ return nullptr;
+ switch (look()) {
+ case 'w':
+ ++First;
+ return parseIntegerLiteral("wchar_t");
+ case 'b':
+ if (consumeIf("b0E"))
+ return make<BoolExpr>(0);
+ if (consumeIf("b1E"))
+ return make<BoolExpr>(1);
+ return nullptr;
+ case 'c':
+ ++First;
+ return parseIntegerLiteral("char");
+ case 'a':
+ ++First;
+ return parseIntegerLiteral("signed char");
+ case 'h':
+ ++First;
+ return parseIntegerLiteral("unsigned char");
+ case 's':
+ ++First;
+ return parseIntegerLiteral("short");
+ case 't':
+ ++First;
+ return parseIntegerLiteral("unsigned short");
+ case 'i':
+ ++First;
+ return parseIntegerLiteral("");
+ case 'j':
+ ++First;
+ return parseIntegerLiteral("u");
+ case 'l':
+ ++First;
+ return parseIntegerLiteral("l");
+ case 'm':
+ ++First;
+ return parseIntegerLiteral("ul");
+ case 'x':
+ ++First;
+ return parseIntegerLiteral("ll");
+ case 'y':
+ ++First;
+ return parseIntegerLiteral("ull");
+ case 'n':
+ ++First;
+ return parseIntegerLiteral("__int128");
+ case 'o':
+ ++First;
+ return parseIntegerLiteral("unsigned __int128");
+ case 'f':
+ ++First;
+ return parseFloatingLiteral<float>();
+ case 'd':
+ ++First;
+ return parseFloatingLiteral<double>();
+ case 'e':
+ ++First;
+ return parseFloatingLiteral<long double>();
+ case '_':
+ if (consumeIf("_Z")) {
+ Node *R = parseEncoding();
+ if (R != nullptr && consumeIf('E'))
+ return R;
}
- return first;
+ return nullptr;
+ case 'T':
+ // Invalid mangled name per
+ // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ return nullptr;
+ default: {
+ // might be named type
+ Node *T = parseType();
+ if (T == nullptr)
+ return nullptr;
+ StringView N = parseNumber();
+ if (!N.empty()) {
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<IntegerCastExpr>(T, N);
+ }
+ if (consumeIf('E'))
+ return T;
+ return nullptr;
+ }
+ }
}
-const char*
-parse_prefix_expression(const char* first, const char* last, StringView op, Db& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<PrefixExpr>(op, db.Names.back());
- first = t1;
+// <braced-expression> ::= <expression>
+// ::= di <field source-name> <braced-expression> # .name = expr
+// ::= dx <index expression> <braced-expression> # [expr] = expr
+// ::= dX <range begin expression> <range end expression> <braced-expression>
+Node *Db::parseBracedExpr() {
+ if (look() == 'd') {
+ switch (look(1)) {
+ case 'i': {
+ First += 2;
+ Node *Field = parseSourceName(/*NameState=*/nullptr);
+ if (Field == nullptr)
+ return nullptr;
+ Node *Init = parseBracedExpr();
+ if (Init == nullptr)
+ return nullptr;
+ return make<BracedExpr>(Field, Init, /*isArray=*/false);
}
- return first;
+ case 'x': {
+ First += 2;
+ Node *Index = parseExpr();
+ if (Index == nullptr)
+ return nullptr;
+ Node *Init = parseBracedExpr();
+ if (Init == nullptr)
+ return nullptr;
+ return make<BracedExpr>(Index, Init, /*isArray=*/true);
+ }
+ case 'X': {
+ First += 2;
+ Node *RangeBegin = parseExpr();
+ if (RangeBegin == nullptr)
+ return nullptr;
+ Node *RangeEnd = parseExpr();
+ if (RangeEnd == nullptr)
+ return nullptr;
+ Node *Init = parseBracedExpr();
+ if (Init == nullptr)
+ return nullptr;
+ return make<BracedRangeExpr>(RangeBegin, RangeEnd, Init);
+ }
+ }
+ }
+ return parseExpr();
}
-const char*
-parse_binary_expression(const char* first, const char* last, StringView op, Db& db)
-{
- const char* t1 = parse_expression(first, last, db);
- if (t1 != first)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- if (db.Names.size() < 2)
- return first;
- auto op2 = db.Names.back();
- db.Names.pop_back();
- auto op1 = db.Names.back();
- db.Names.back() = db.make<BinaryExpr>(op1, op, op2);
- first = t2;
- }
- }
- return first;
+// (not yet in the spec)
+// <fold-expr> ::= fL <binary-operator-name> <expression> <expression>
+// ::= fR <binary-operator-name> <expression> <expression>
+// ::= fl <binary-operator-name> <expression>
+// ::= fr <binary-operator-name> <expression>
+Node *Db::parseFoldExpr() {
+ if (!consumeIf('f'))
+ return nullptr;
+
+ char FoldKind = look();
+ bool IsLeftFold, HasInitializer;
+ HasInitializer = FoldKind == 'L' || FoldKind == 'R';
+ if (FoldKind == 'l' || FoldKind == 'L')
+ IsLeftFold = true;
+ else if (FoldKind == 'r' || FoldKind == 'R')
+ IsLeftFold = false;
+ else
+ return nullptr;
+ ++First;
+
+ // FIXME: This map is duplicated in parseOperatorName and parseExpr.
+ StringView OperatorName;
+ if (consumeIf("aa")) OperatorName = "&&";
+ else if (consumeIf("an")) OperatorName = "&";
+ else if (consumeIf("aN")) OperatorName = "&=";
+ else if (consumeIf("aS")) OperatorName = "=";
+ else if (consumeIf("cm")) OperatorName = ",";
+ else if (consumeIf("ds")) OperatorName = ".*";
+ else if (consumeIf("dv")) OperatorName = "/";
+ else if (consumeIf("dV")) OperatorName = "/=";
+ else if (consumeIf("eo")) OperatorName = "^";
+ else if (consumeIf("eO")) OperatorName = "^=";
+ else if (consumeIf("eq")) OperatorName = "==";
+ else if (consumeIf("ge")) OperatorName = ">=";
+ else if (consumeIf("gt")) OperatorName = ">";
+ else if (consumeIf("le")) OperatorName = "<=";
+ else if (consumeIf("ls")) OperatorName = "<<";
+ else if (consumeIf("lS")) OperatorName = "<<=";
+ else if (consumeIf("lt")) OperatorName = "<";
+ else if (consumeIf("mi")) OperatorName = "-";
+ else if (consumeIf("mI")) OperatorName = "-=";
+ else if (consumeIf("ml")) OperatorName = "*";
+ else if (consumeIf("mL")) OperatorName = "*=";
+ else if (consumeIf("ne")) OperatorName = "!=";
+ else if (consumeIf("oo")) OperatorName = "||";
+ else if (consumeIf("or")) OperatorName = "|";
+ else if (consumeIf("oR")) OperatorName = "|=";
+ else if (consumeIf("pl")) OperatorName = "+";
+ else if (consumeIf("pL")) OperatorName = "+=";
+ else if (consumeIf("rm")) OperatorName = "%";
+ else if (consumeIf("rM")) OperatorName = "%=";
+ else if (consumeIf("rs")) OperatorName = ">>";
+ else if (consumeIf("rS")) OperatorName = ">>=";
+ else return nullptr;
+
+ Node *Pack = parseExpr(), *Init = nullptr;
+ if (Pack == nullptr)
+ return nullptr;
+ if (HasInitializer) {
+ Init = parseExpr();
+ if (Init == nullptr)
+ return nullptr;
+ }
+
+ if (IsLeftFold && Init)
+ std::swap(Pack, Init);
+
+ return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init);
}
// <expression> ::= <unary operator-name> <expression>
@@ -4691,1031 +3912,502 @@ parse_binary_expression(const char* first, const char* last, StringView op, Db&
// ::= ds <expression> <expression> # expr.*expr
// ::= sZ <template-param> # size of a parameter pack
// ::= sZ <function-param> # size of a function parameter pack
+// ::= sP <template-arg>* E # sizeof...(T), size of a captured template parameter pack from an alias template
// ::= sp <expression> # pack expansion
// ::= tw <expression> # throw expression
// ::= tr # throw with no operand (rethrow)
// ::= <unresolved-name> # f(p), N::f(p), ::f(p),
// # freestanding dependent name (e.g., T::x),
// # objectless nonstatic member reference
+// ::= fL <binary-operator-name> <expression> <expression>
+// ::= fR <binary-operator-name> <expression> <expression>
+// ::= fl <binary-operator-name> <expression>
+// ::= fr <binary-operator-name> <expression>
// ::= <expr-primary>
-
-const char*
-parse_expression(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2)
- {
- const char* t = first;
- bool parsed_gs = false;
- if (last - first >= 4 && t[0] == 'g' && t[1] == 's')
- {
- t += 2;
- parsed_gs = true;
- }
- switch (*t)
- {
- case 'L':
- first = parse_expr_primary(first, last, db);
- break;
- case 'T':
- first = parse_template_param(first, last, db);
- break;
- case 'f':
- first = parse_function_param(first, last, db);
- break;
- case 'a':
- switch (t[1])
- {
- case 'a':
- t = parse_binary_expression(first+2, last, "&&", db);
- if (t != first+2)
- first = t;
- break;
- case 'd':
- t = parse_prefix_expression(first+2, last, "&", db);
- if (t != first+2)
- first = t;
- break;
- case 'n':
- t = parse_binary_expression(first+2, last, "&", db);
- if (t != first+2)
- first = t;
- break;
- case 'N':
- t = parse_binary_expression(first+2, last, "&=", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, "=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- first = parse_alignof_type(first, last, db);
- break;
- case 'z':
- first = parse_alignof_expr(first, last, db);
- break;
- }
- break;
- case 'c':
- switch (t[1])
- {
- case 'c':
- first = parse_const_cast_expr(first, last, db);
- break;
- case 'l':
- first = parse_call_expr(first, last, db);
- break;
- case 'm':
- t = parse_binary_expression(first+2, last, ",", db);
- if (t != first+2)
- first = t;
- break;
- case 'o':
- t = parse_prefix_expression(first+2, last, "~", db);
- if (t != first+2)
- first = t;
- break;
- case 'v':
- first = parse_conversion_expr(first, last, db);
- break;
- }
- break;
- case 'd':
- switch (t[1])
- {
- case 'a':
- {
- const char* t1 = parse_expression(t+2, last, db);
- if (t1 != t+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<DeleteExpr>(
- db.Names.back(), parsed_gs, /*is_array=*/true);
- first = t1;
- }
- }
- break;
- case 'c':
- first = parse_dynamic_cast_expr(first, last, db);
- break;
- case 'e':
- t = parse_prefix_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- {
- const char* t1 = parse_expression(t+2, last, db);
- if (t1 != t+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<DeleteExpr>(
- db.Names.back(), parsed_gs, /*is_array=*/false);
- first = t1;
- }
- }
- break;
- case 'n':
- return parse_unresolved_name(first, last, db);
- case 's':
- first = parse_dot_star_expr(first, last, db);
- break;
- case 't':
- first = parse_dot_expr(first, last, db);
- break;
- case 'v':
- t = parse_binary_expression(first+2, last, "/", db);
- if (t != first+2)
- first = t;
- break;
- case 'V':
- t = parse_binary_expression(first+2, last, "/=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'e':
- switch (t[1])
- {
- case 'o':
- t = parse_binary_expression(first+2, last, "^", db);
- if (t != first+2)
- first = t;
- break;
- case 'O':
- t = parse_binary_expression(first+2, last, "^=", db);
- if (t != first+2)
- first = t;
- break;
- case 'q':
- t = parse_binary_expression(first+2, last, "==", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'g':
- switch (t[1])
- {
- case 'e':
- t = parse_binary_expression(first+2, last, ">=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_binary_expression(first+2, last, ">", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'i':
- if (t[1] == 'x')
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- if (db.Names.size() < 2)
- return first;
- auto op2 = db.Names.back();
- db.Names.pop_back();
- auto op1 = db.Names.back();
- db.Names.back() =
- db.make<ArraySubscriptExpr>(op1, op2);
- first = t2;
- }
- else if (!db.Names.empty())
- db.Names.pop_back();
- }
- }
- break;
- case 'l':
- switch (t[1])
- {
- case 'e':
- t = parse_binary_expression(first+2, last, "<=", db);
- if (t != first+2)
- first = t;
- break;
- case 's':
- t = parse_binary_expression(first+2, last, "<<", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, "<<=", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_binary_expression(first+2, last, "<", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'm':
- switch (t[1])
- {
- case 'i':
- t = parse_binary_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
- break;
- case 'I':
- t = parse_binary_expression(first+2, last, "-=", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- t = parse_binary_expression(first+2, last, "*", db);
- if (t != first+2)
- first = t;
- break;
- case 'L':
- t = parse_binary_expression(first+2, last, "*=", db);
- if (t != first+2)
- first = t;
- break;
- case 'm':
- if (first+2 != last && first[2] == '_')
- {
- t = parse_prefix_expression(first+3, last, "--", db);
- if (t != first+3)
- first = t;
- }
- else
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<PostfixExpr>(db.Names.back(), "--");
- first = t1;
- }
- }
- break;
- }
- break;
- case 'n':
- switch (t[1])
- {
- case 'a':
- case 'w':
- first = parse_new_expr(first, last, db);
- break;
- case 'e':
- t = parse_binary_expression(first+2, last, "!=", db);
- if (t != first+2)
- first = t;
- break;
- case 'g':
- t = parse_prefix_expression(first+2, last, "-", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- t = parse_prefix_expression(first+2, last, "!", db);
- if (t != first+2)
- first = t;
- break;
- case 'x':
- t = parse_noexcept_expression(first+2, last, db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'o':
- switch (t[1])
- {
- case 'n':
- return parse_unresolved_name(first, last, db);
- case 'o':
- t = parse_binary_expression(first+2, last, "||", db);
- if (t != first+2)
- first = t;
- break;
- case 'r':
- t = parse_binary_expression(first+2, last, "|", db);
- if (t != first+2)
- first = t;
- break;
- case 'R':
- t = parse_binary_expression(first+2, last, "|=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 'p':
- switch (t[1])
- {
- case 'm':
- t = parse_binary_expression(first+2, last, "->*", db);
- if (t != first+2)
- first = t;
- break;
- case 'l':
- t = parse_binary_expression(first+2, last, "+", db);
- if (t != first+2)
- first = t;
- break;
- case 'L':
- t = parse_binary_expression(first+2, last, "+=", db);
- if (t != first+2)
- first = t;
- break;
- case 'p':
- if (first+2 != last && first[2] == '_')
- {
- t = parse_prefix_expression(first+3, last, "++", db);
- if (t != first+3)
- first = t;
- }
- else
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<PostfixExpr>(db.Names.back(), "++");
- first = t1;
- }
- }
- break;
- case 's':
- t = parse_prefix_expression(first+2, last, "+", db);
- if (t != first+2)
- first = t;
- break;
- case 't':
- first = parse_arrow_expr(first, last, db);
- break;
- }
- break;
- case 'q':
- if (t[1] == 'u')
- {
- const char* t1 = parse_expression(first+2, last, db);
- if (t1 != first+2)
- {
- const char* t2 = parse_expression(t1, last, db);
- if (t2 != t1)
- {
- const char* t3 = parse_expression(t2, last, db);
- if (t3 != t2)
- {
- if (db.Names.size() < 3)
- return first;
- auto op3 = db.Names.back();
- db.Names.pop_back();
- auto op2 = db.Names.back();
- db.Names.pop_back();
- auto op1 = db.Names.back();
- db.Names.back() =
- db.make<ConditionalExpr>(op1, op2, op3);
- first = t3;
- }
- else
- {
- if (db.Names.size() < 2)
- return first;
- db.Names.pop_back();
- db.Names.pop_back();
- }
- }
- else if (!db.Names.empty())
- db.Names.pop_back();
- }
- }
- break;
- case 'r':
- switch (t[1])
- {
- case 'c':
- first = parse_reinterpret_cast_expr(first, last, db);
- break;
- case 'm':
- t = parse_binary_expression(first+2, last, "%", db);
- if (t != first+2)
- first = t;
- break;
- case 'M':
- t = parse_binary_expression(first+2, last, "%=", db);
- if (t != first+2)
- first = t;
- break;
- case 's':
- t = parse_binary_expression(first+2, last, ">>", db);
- if (t != first+2)
- first = t;
- break;
- case 'S':
- t = parse_binary_expression(first+2, last, ">>=", db);
- if (t != first+2)
- first = t;
- break;
- }
- break;
- case 's':
- switch (t[1])
- {
- case 'c':
- first = parse_static_cast_expr(first, last, db);
- break;
- case 'p':
- first = parse_pack_expansion(first, last, db);
- break;
- case 'r':
- return parse_unresolved_name(first, last, db);
- case 't':
- first = parse_sizeof_type_expr(first, last, db);
- break;
- case 'z':
- first = parse_sizeof_expr_expr(first, last, db);
- break;
- case 'Z':
- if (last - t >= 3)
- {
- switch (t[2])
- {
- case 'T':
- first = parse_sizeof_param_pack_expr(first, last, db);
- break;
- case 'f':
- first = parse_sizeof_function_param_pack_expr(first, last, db);
- break;
- }
- }
- break;
- }
- break;
- case 't':
- switch (t[1])
- {
- case 'e':
- case 'i':
- first = parse_typeid_expr(first, last, db);
- break;
- case 'r':
- db.Names.push_back(db.make<NameType>("throw"));
- first += 2;
- break;
- case 'w':
- first = parse_throw_expr(first, last, db);
- break;
- }
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return parse_unresolved_name(first, last, db);
- }
+Node *Db::parseExpr() {
+ bool Global = consumeIf("gs");
+ if (numLeft() < 2)
+ return nullptr;
+
+ switch (*First) {
+ case 'L':
+ return parseExprPrimary();
+ case 'T':
+ return parseTemplateParam();
+ case 'f': {
+ // Disambiguate a fold expression from a <function-param>.
+ if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2))))
+ return parseFunctionParam();
+ return parseFoldExpr();
+ }
+ case 'a':
+ switch (First[1]) {
+ case 'a':
+ First += 2;
+ return parseBinaryExpr("&&");
+ case 'd':
+ First += 2;
+ return parsePrefixExpr("&");
+ case 'n':
+ First += 2;
+ return parseBinaryExpr("&");
+ case 'N':
+ First += 2;
+ return parseBinaryExpr("&=");
+ case 'S':
+ First += 2;
+ return parseBinaryExpr("=");
+ case 't': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("alignof (", Ty, ")");
}
- return first;
-}
-
-// <template-arg> ::= <type> # type or template
-// ::= X <expression> E # expression
-// ::= <expr-primary> # simple expressions
-// ::= J <template-arg>* E # argument pack
-// ::= LZ <encoding> E # extension
-
-const char*
-parse_template_arg(const char* first, const char* last, Db& db)
-{
- if (first != last)
- {
- const char* t;
- switch (*first)
- {
- case 'X':
- t = parse_expression(first+1, last, db);
- if (t != first+1)
- {
- if (t != last && *t == 'E')
- first = t+1;
- }
- break;
- case 'J':
- t = first+1;
- if (t == last)
- return first;
- while (*t != 'E')
- {
- const char* t1 = parse_template_arg(t, last, db);
- if (t1 == t)
- return first;
- t = t1;
- }
- first = t+1;
- break;
- case 'L':
- // <expr-primary> or LZ <encoding> E
- if (first+1 != last && first[1] == 'Z')
- {
- t = parse_encoding(first+2, last, db);
- if (t != first+2 && t != last && *t == 'E')
- first = t+1;
- }
- else
- first = parse_expr_primary(first, last, db);
- break;
- default:
- // <type>
- first = parse_type(first, last, db);
- break;
- }
+ case 'z': {
+ First += 2;
+ Node *Ty = parseExpr();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("alignof (", Ty, ")");
}
- return first;
-}
-
-// <template-args> ::= I <template-arg>* E
-// extension, the abi says <template-arg>+
-
-const char*
-parse_template_args(const char* first, const char* last, Db& db)
-{
- if (last - first >= 2 && *first == 'I')
- {
- if (db.TagTemplates)
- db.TemplateParams.clear();
- const char* t = first+1;
- size_t begin_idx = db.Names.size();
- while (*t != 'E')
- {
- if (db.TagTemplates)
- {
- auto TmpParams = std::move(db.TemplateParams);
- size_t k0 = db.Names.size();
- const char* t1 = parse_template_arg(t, last, db);
- size_t k1 = db.Names.size();
- db.TemplateParams = std::move(TmpParams);
-
- if (t1 == t || t1 == last || k0 > k1)
- return first;
- db.TemplateParams.pushPack();
- for (size_t k = k0; k < k1; ++k)
- db.TemplateParams.pushSubstitutionIntoPack(db.Names[k]);
- t = t1;
- continue;
- }
- size_t k0 = db.Names.size();
- const char* t1 = parse_template_arg(t, last, db);
- size_t k1 = db.Names.size();
- if (t1 == t || t1 == last || k0 > k1)
- return first;
- t = t1;
- }
- if (begin_idx > db.Names.size())
- return first;
- first = t + 1;
- TemplateParams* tp = db.make<TemplateParams>(
- db.popTrailingNodeArray(begin_idx));
- db.Names.push_back(tp);
}
- return first;
-}
-
-// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
-// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
-//
-// <prefix> ::= <prefix> <unqualified-name>
-// ::= <template-prefix> <template-args>
-// ::= <template-param>
-// ::= <decltype>
-// ::= # empty
-// ::= <substitution>
-// ::= <prefix> <data-member-prefix>
-// extension ::= L
-//
-// <template-prefix> ::= <prefix> <template unqualified-name>
-// ::= <template-param>
-// ::= <substitution>
-
-const char*
-parse_nested_name(const char* first, const char* last, Db& db,
- bool* ends_with_template_args)
-{
- if (first != last && *first == 'N')
- {
- Qualifiers cv;
- const char* t0 = parse_cv_qualifiers(first+1, last, cv);
- if (t0 == last)
- return first;
- db.RefQuals = FrefQualNone;
- if (*t0 == 'R')
- {
- db.RefQuals = FrefQualLValue;
- ++t0;
- }
- else if (*t0 == 'O')
- {
- db.RefQuals = FrefQualRValue;
- ++t0;
- }
- db.Names.push_back(db.make<EmptyName>());
- if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
- {
- t0 += 2;
- db.Names.back() = db.make<NameType>("std");
- }
- if (t0 == last)
- return first;
- bool pop_subs = false;
- bool component_ends_with_template_args = false;
- while (*t0 != 'E')
- {
- component_ends_with_template_args = false;
- const char* t1;
- switch (*t0)
- {
- case 'S':
- if (t0 + 1 != last && t0[1] == 't')
- goto do_parse_unqualified_name;
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- {
- db.Names.back() = db.make<QualifiedName>(
- db.Names.back(), name);
- db.Subs.pushSubstitution(db.Names.back());
- }
- else
- db.Names.back() = name;
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'T':
- t1 = parse_template_param(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- else
- db.Names.back() = name;
- db.Subs.pushSubstitution(db.Names.back());
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'D':
- if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T')
- goto do_parse_unqualified_name;
- t1 = parse_decltype(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- else
- db.Names.back() = name;
- db.Subs.pushSubstitution(db.Names.back());
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- break;
- case 'I':
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- db.Names.back() = db.make<NameWithTemplateArgs>(
- db.Names.back(), name);
- db.Subs.pushSubstitution(db.Names.back());
- t0 = t1;
- component_ends_with_template_args = true;
- }
- else
- return first;
- break;
- case 'L':
- if (++t0 == last)
- return first;
- break;
- default:
- do_parse_unqualified_name:
- t1 = parse_unqualified_name(t0, last, db);
- if (t1 != t0 && t1 != last)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.back()->K != Node::KEmptyName)
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- else
- db.Names.back() = name;
- db.Subs.pushSubstitution(db.Names.back());
- pop_subs = true;
- t0 = t1;
- }
- else
- return first;
- }
- }
- first = t0 + 1;
- db.CV = cv;
- if (pop_subs && !db.Subs.empty())
- db.Subs.popPack();
- if (ends_with_template_args)
- *ends_with_template_args = component_ends_with_template_args;
+ return nullptr;
+ case 'c':
+ switch (First[1]) {
+ // cc <type> <expression> # const_cast<type>(expression)
+ case 'c': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return Ty;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("const_cast", Ty, Ex);
}
- return first;
-}
-
-// <discriminator> := _ <non-negative number> # when number < 10
-// := __ <non-negative number> _ # when number >= 10
-// extension := decimal-digit+ # at the end of string
-
-const char*
-parse_discriminator(const char* first, const char* last)
-{
- // parse but ignore discriminator
- if (first != last)
- {
- if (*first == '_')
- {
- const char* t1 = first+1;
- if (t1 != last)
- {
- if (std::isdigit(*t1))
- first = t1+1;
- else if (*t1 == '_')
- {
- for (++t1; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 != last && *t1 == '_')
- first = t1 + 1;
- }
- }
- }
- else if (std::isdigit(*first))
- {
- const char* t1 = first+1;
- for (; t1 != last && std::isdigit(*t1); ++t1)
- ;
- if (t1 == last)
- first = last;
- }
+ // cl <expression>+ E # call
+ case 'l': {
+ First += 2;
+ Node *Callee = parseExpr();
+ if (Callee == nullptr)
+ return Callee;
+ size_t ExprsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ Names.push_back(E);
+ }
+ return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin));
}
- return first;
-}
-
-// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
-// := Z <function encoding> E s [<discriminator>]
-// := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
-
-const char*
-parse_local_name(const char* first, const char* last, Db& db,
- bool* ends_with_template_args)
-{
- if (first != last && *first == 'Z')
- {
- const char* t = parse_encoding(first+1, last, db);
- if (t != first+1 && t != last && *t == 'E' && ++t != last)
- {
- switch (*t)
- {
- case 's':
- first = parse_discriminator(t+1, last);
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<QualifiedName>(
- db.Names.back(), db.make<NameType>("string literal"));
- break;
- case 'd':
- if (++t != last)
- {
- const char* t1 = parse_number(t, last);
- if (t1 != last && *t1 == '_')
- {
- t = t1 + 1;
- t1 = parse_name(t, last, db,
- ends_with_template_args);
- if (t1 != t)
- {
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- first = t1;
- }
- else if (!db.Names.empty())
- db.Names.pop_back();
- }
- }
- break;
- default:
- {
- const char* t1 = parse_name(t, last, db,
- ends_with_template_args);
- if (t1 != t)
- {
- // parse but ignore discriminator
- first = parse_discriminator(t1, last);
- if (db.Names.size() < 2)
- return first;
- auto name = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<QualifiedName>(db.Names.back(), name);
- }
- else if (!db.Names.empty())
- db.Names.pop_back();
- }
- break;
- }
- }
+ case 'm':
+ First += 2;
+ return parseBinaryExpr(",");
+ case 'o':
+ First += 2;
+ return parsePrefixExpr("~");
+ case 'v':
+ return parseConversionExpr();
}
- return first;
-}
-
-// <name> ::= <nested-name> // N
-// ::= <local-name> # See Scope Encoding below // Z
-// ::= <unscoped-template-name> <template-args>
-// ::= <unscoped-name>
-
-// <unscoped-template-name> ::= <unscoped-name>
-// ::= <substitution>
-
-const char*
-parse_name(const char* first, const char* last, Db& db,
- bool* ends_with_template_args)
-{
- if (last - first >= 2)
- {
- const char* t0 = first;
- // extension: ignore L here
- if (*t0 == 'L')
- ++t0;
- switch (*t0)
- {
- case 'N':
- {
- const char* t1 = parse_nested_name(t0, last, db,
- ends_with_template_args);
- if (t1 != t0)
- first = t1;
- break;
- }
- case 'Z':
- {
- const char* t1 = parse_local_name(t0, last, db,
- ends_with_template_args);
- if (t1 != t0)
- first = t1;
- break;
- }
- default:
- {
- const char* t1 = parse_unscoped_name(t0, last, db);
- if (t1 != t0)
- {
- if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args>
- {
- if (db.Names.empty())
- return first;
- db.Subs.pushSubstitution(db.Names.back());
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
- {
- if (db.Names.size() < 2)
- return first;
- auto tmp = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), tmp);
- first = t1;
- if (ends_with_template_args)
- *ends_with_template_args = true;
- }
- }
- else // <unscoped-name>
- first = t1;
- }
- else
- { // try <substitution> <template-args>
- t1 = parse_substitution(t0, last, db);
- if (t1 != t0 && t1 != last && *t1 == 'I')
- {
- t0 = t1;
- t1 = parse_template_args(t0, last, db);
- if (t1 != t0)
- {
- if (db.Names.size() < 2)
- return first;
- auto tmp = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<NameWithTemplateArgs>(
- db.Names.back(), tmp);
- first = t1;
- if (ends_with_template_args)
- *ends_with_template_args = true;
- }
- }
- }
- break;
- }
- }
+ return nullptr;
+ case 'd':
+ switch (First[1]) {
+ case 'a': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<DeleteExpr>(Ex, Global, /*is_array=*/true);
}
- return first;
+ case 'c': {
+ First += 2;
+ Node *T = parseType();
+ if (T == nullptr)
+ return T;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("dynamic_cast", T, Ex);
+ }
+ case 'e':
+ First += 2;
+ return parsePrefixExpr("*");
+ case 'l': {
+ First += 2;
+ Node *E = parseExpr();
+ if (E == nullptr)
+ return E;
+ return make<DeleteExpr>(E, Global, /*is_array=*/false);
+ }
+ case 'n':
+ return parseUnresolvedName();
+ case 's': {
+ First += 2;
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<MemberExpr>(LHS, ".*", RHS);
+ }
+ case 't': {
+ First += 2;
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
+ return LHS;
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<MemberExpr>(LHS, ".", RHS);
+ }
+ case 'v':
+ First += 2;
+ return parseBinaryExpr("/");
+ case 'V':
+ First += 2;
+ return parseBinaryExpr("/=");
+ }
+ return nullptr;
+ case 'e':
+ switch (First[1]) {
+ case 'o':
+ First += 2;
+ return parseBinaryExpr("^");
+ case 'O':
+ First += 2;
+ return parseBinaryExpr("^=");
+ case 'q':
+ First += 2;
+ return parseBinaryExpr("==");
+ }
+ return nullptr;
+ case 'g':
+ switch (First[1]) {
+ case 'e':
+ First += 2;
+ return parseBinaryExpr(">=");
+ case 't':
+ First += 2;
+ return parseBinaryExpr(">");
+ }
+ return nullptr;
+ case 'i':
+ switch (First[1]) {
+ case 'x': {
+ First += 2;
+ Node *Base = parseExpr();
+ if (Base == nullptr)
+ return nullptr;
+ Node *Index = parseExpr();
+ if (Index == nullptr)
+ return Index;
+ return make<ArraySubscriptExpr>(Base, Index);
+ }
+ case 'l': {
+ First += 2;
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseBracedExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
+ }
+ return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin));
+ }
+ }
+ return nullptr;
+ case 'l':
+ switch (First[1]) {
+ case 'e':
+ First += 2;
+ return parseBinaryExpr("<=");
+ case 's':
+ First += 2;
+ return parseBinaryExpr("<<");
+ case 'S':
+ First += 2;
+ return parseBinaryExpr("<<=");
+ case 't':
+ First += 2;
+ return parseBinaryExpr("<");
+ }
+ return nullptr;
+ case 'm':
+ switch (First[1]) {
+ case 'i':
+ First += 2;
+ return parseBinaryExpr("-");
+ case 'I':
+ First += 2;
+ return parseBinaryExpr("-=");
+ case 'l':
+ First += 2;
+ return parseBinaryExpr("*");
+ case 'L':
+ First += 2;
+ return parseBinaryExpr("*=");
+ case 'm':
+ First += 2;
+ if (consumeIf('_'))
+ return parsePrefixExpr("--");
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<PostfixExpr>(Ex, "--");
+ }
+ return nullptr;
+ case 'n':
+ switch (First[1]) {
+ case 'a':
+ case 'w':
+ return parseNewExpr();
+ case 'e':
+ First += 2;
+ return parseBinaryExpr("!=");
+ case 'g':
+ First += 2;
+ return parsePrefixExpr("-");
+ case 't':
+ First += 2;
+ return parsePrefixExpr("!");
+ case 'x':
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("noexcept (", Ex, ")");
+ }
+ return nullptr;
+ case 'o':
+ switch (First[1]) {
+ case 'n':
+ return parseUnresolvedName();
+ case 'o':
+ First += 2;
+ return parseBinaryExpr("||");
+ case 'r':
+ First += 2;
+ return parseBinaryExpr("|");
+ case 'R':
+ First += 2;
+ return parseBinaryExpr("|=");
+ }
+ return nullptr;
+ case 'p':
+ switch (First[1]) {
+ case 'm':
+ First += 2;
+ return parseBinaryExpr("->*");
+ case 'l':
+ First += 2;
+ return parseBinaryExpr("+");
+ case 'L':
+ First += 2;
+ return parseBinaryExpr("+=");
+ case 'p': {
+ First += 2;
+ if (consumeIf('_'))
+ return parsePrefixExpr("++");
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<PostfixExpr>(Ex, "++");
+ }
+ case 's':
+ First += 2;
+ return parsePrefixExpr("+");
+ case 't': {
+ First += 2;
+ Node *L = parseExpr();
+ if (L == nullptr)
+ return nullptr;
+ Node *R = parseExpr();
+ if (R == nullptr)
+ return nullptr;
+ return make<MemberExpr>(L, "->", R);
+ }
+ }
+ return nullptr;
+ case 'q':
+ if (First[1] == 'u') {
+ First += 2;
+ Node *Cond = parseExpr();
+ if (Cond == nullptr)
+ return nullptr;
+ Node *LHS = parseExpr();
+ if (LHS == nullptr)
+ return nullptr;
+ Node *RHS = parseExpr();
+ if (RHS == nullptr)
+ return nullptr;
+ return make<ConditionalExpr>(Cond, LHS, RHS);
+ }
+ return nullptr;
+ case 'r':
+ switch (First[1]) {
+ case 'c': {
+ First += 2;
+ Node *T = parseType();
+ if (T == nullptr)
+ return T;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("reinterpret_cast", T, Ex);
+ }
+ case 'm':
+ First += 2;
+ return parseBinaryExpr("%");
+ case 'M':
+ First += 2;
+ return parseBinaryExpr("%=");
+ case 's':
+ First += 2;
+ return parseBinaryExpr(">>");
+ case 'S':
+ First += 2;
+ return parseBinaryExpr(">>=");
+ }
+ return nullptr;
+ case 's':
+ switch (First[1]) {
+ case 'c': {
+ First += 2;
+ Node *T = parseType();
+ if (T == nullptr)
+ return T;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<CastExpr>("static_cast", T, Ex);
+ }
+ case 'p': {
+ First += 2;
+ Node *Child = parseExpr();
+ if (Child == nullptr)
+ return nullptr;
+ return make<ParameterPackExpansion>(Child);
+ }
+ case 'r':
+ return parseUnresolvedName();
+ case 't': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return Ty;
+ return make<EnclosingExpr>("sizeof (", Ty, ")");
+ }
+ case 'z': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("sizeof (", Ex, ")");
+ }
+ case 'Z':
+ First += 2;
+ if (look() == 'T') {
+ Node *R = parseTemplateParam();
+ if (R == nullptr)
+ return nullptr;
+ return make<SizeofParamPackExpr>(R);
+ } else if (look() == 'f') {
+ Node *FP = parseFunctionParam();
+ if (FP == nullptr)
+ return nullptr;
+ return make<EnclosingExpr>("sizeof... (", FP, ")");
+ }
+ return nullptr;
+ case 'P': {
+ First += 2;
+ size_t ArgsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *Arg = parseTemplateArg();
+ if (Arg == nullptr)
+ return nullptr;
+ Names.push_back(Arg);
+ }
+ return make<EnclosingExpr>(
+ "sizeof... (", make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)),
+ ")");
+ }
+ }
+ return nullptr;
+ case 't':
+ switch (First[1]) {
+ case 'e': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return Ex;
+ return make<EnclosingExpr>("typeid (", Ex, ")");
+ }
+ case 'i': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return Ty;
+ return make<EnclosingExpr>("typeid (", Ty, ")");
+ }
+ case 'l': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ size_t InitsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *E = parseBracedExpr();
+ if (E == nullptr)
+ return nullptr;
+ Names.push_back(E);
+ }
+ return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin));
+ }
+ case 'r':
+ First += 2;
+ return make<NameType>("throw");
+ case 'w': {
+ First += 2;
+ Node *Ex = parseExpr();
+ if (Ex == nullptr)
+ return nullptr;
+ return make<ThrowExpr>(Ex);
+ }
+ }
+ return nullptr;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return parseUnresolvedName();
+ }
+ return nullptr;
}
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
-//
+//
// <nv-offset> ::= <offset number>
// # non-virtual base override
-//
+//
// <v-offset> ::= <offset number> _ <virtual offset number>
// # virtual base override, with vcall offset
-
-const char*
-parse_call_offset(const char* first, const char* last)
-{
- if (first != last)
- {
- switch (*first)
- {
- case 'h':
- {
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- first = t + 1;
- }
- break;
- case 'v':
- {
- const char* t = parse_number(first + 1, last);
- if (t != first + 1 && t != last && *t == '_')
- {
- const char* t2 = parse_number(++t, last);
- if (t2 != t && t2 != last && *t2 == '_')
- first = t2 + 1;
- }
- }
- break;
- }
- }
- return first;
+bool Db::parseCallOffset() {
+ // Just scan through the call offset, we never add this information into the
+ // output.
+ if (consumeIf('h'))
+ return parseNumber(true).empty() || !consumeIf('_');
+ if (consumeIf('v'))
+ return parseNumber(true).empty() || !consumeIf('_') ||
+ parseNumber(true).empty() || !consumeIf('_');
+ return true;
}
// <special-name> ::= TV <type> # virtual table
@@ -5732,493 +4424,575 @@ parse_call_offset(const char* first, const char* last)
// # No <type>
// ::= TW <object name> # Thread-local wrapper
// ::= TH <object name> # Thread-local initialization
+// ::= GR <object name> _ # First temporary
+// ::= GR <object name> <seq-id> _ # Subsequent temporaries
// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
// extension ::= GR <object name> # reference temporary for object
+Node *Db::parseSpecialName() {
+ switch (look()) {
+ case 'T':
+ switch (look(1)) {
+ // TV <type> # virtual table
+ case 'V': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("vtable for ", Ty);
+ }
+ // TT <type> # VTT structure (construction vtable index)
+ case 'T': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("VTT for ", Ty);
+ }
+ // TI <type> # typeinfo structure
+ case 'I': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("typeinfo for ", Ty);
+ }
+ // TS <type> # typeinfo name (null-terminated byte string)
+ case 'S': {
+ First += 2;
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ return make<SpecialName>("typeinfo name for ", Ty);
+ }
+ // Tc <call-offset> <call-offset> <base encoding>
+ case 'c': {
+ First += 2;
+ if (parseCallOffset() || parseCallOffset())
+ return nullptr;
+ Node *Encoding = parseEncoding();
+ if (Encoding == nullptr)
+ return nullptr;
+ return make<SpecialName>("covariant return thunk to ", Encoding);
+ }
+ // extension ::= TC <first type> <number> _ <second type>
+ // # construction vtable for second-in-first
+ case 'C': {
+ First += 2;
+ Node *FirstType = parseType();
+ if (FirstType == nullptr)
+ return nullptr;
+ if (parseNumber(true).empty() || !consumeIf('_'))
+ return nullptr;
+ Node *SecondType = parseType();
+ if (SecondType == nullptr)
+ return nullptr;
+ return make<CtorVtableSpecialName>(SecondType, FirstType);
+ }
+ // TW <object name> # Thread-local wrapper
+ case 'W': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ return make<SpecialName>("thread-local wrapper routine for ", Name);
+ }
+ // TH <object name> # Thread-local initialization
+ case 'H': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ return make<SpecialName>("thread-local initialization routine for ", Name);
+ }
+ // T <call-offset> <base encoding>
+ default: {
+ ++First;
+ bool IsVirt = look() == 'v';
+ if (parseCallOffset())
+ return nullptr;
+ Node *BaseEncoding = parseEncoding();
+ if (BaseEncoding == nullptr)
+ return nullptr;
+ if (IsVirt)
+ return make<SpecialName>("virtual thunk to ", BaseEncoding);
+ else
+ return make<SpecialName>("non-virtual thunk to ", BaseEncoding);
+ }
+ }
+ case 'G':
+ switch (look(1)) {
+ // GV <object name> # Guard variable for one-time initialization
+ case 'V': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ return make<SpecialName>("guard variable for ", Name);
+ }
+ // GR <object name> # reference temporary for object
+ // GR <object name> _ # First temporary
+ // GR <object name> <seq-id> _ # Subsequent temporaries
+ case 'R': {
+ First += 2;
+ Node *Name = parseName();
+ if (Name == nullptr)
+ return nullptr;
+ size_t Count;
+ bool ParsedSeqId = !parseSeqId(&Count);
+ if (!consumeIf('_') && ParsedSeqId)
+ return nullptr;
+ return make<SpecialName>("reference temporary for ", Name);
+ }
+ }
+ }
+ return nullptr;
+}
-const char*
-parse_special_name(const char* first, const char* last, Db& db)
-{
- if (last - first > 2)
- {
- const char* t;
- switch (*first)
- {
- case 'T':
- switch (first[1])
- {
- case 'V':
- // TV <type> # virtual table
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("vtable for ", db.Names.back());
- first = t;
- }
- break;
- case 'T':
- // TT <type> # VTT structure (construction vtable index)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("VTT for ", db.Names.back());
- first = t;
- }
- break;
- case 'I':
- // TI <type> # typeinfo structure
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("typeinfo for ", db.Names.back());
- first = t;
- }
- break;
- case 'S':
- // TS <type> # typeinfo name (null-terminated byte string)
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("typeinfo name for ", db.Names.back());
- first = t;
- }
- break;
- case 'c':
- // Tc <call-offset> <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+2, last);
- if (t0 == first+2)
- break;
- const char* t1 = parse_call_offset(t0, last);
- if (t1 == t0)
- break;
- t = parse_encoding(t1, last, db);
- if (t != t1)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("covariant return thunk to ",
- db.Names.back());
- first = t;
- }
- }
- break;
- case 'C':
- // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
- t = parse_type(first+2, last, db);
- if (t != first+2)
- {
- const char* t0 = parse_number(t, last);
- if (t0 != t && t0 != last && *t0 == '_')
- {
- const char* t1 = parse_type(++t0, last, db);
- if (t1 != t0)
- {
- if (db.Names.size() < 2)
- return first;
- auto left = db.Names.back();
- db.Names.pop_back();
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<CtorVtableSpecialName>(
- left, db.Names.back());
- first = t1;
- }
- }
- }
- break;
- case 'W':
- // TW <object name> # Thread-local wrapper
- t = parse_name(first + 2, last, db);
- if (t != first + 2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("thread-local wrapper routine for ",
- db.Names.back());
- first = t;
- }
- break;
- case 'H':
- //TH <object name> # Thread-local initialization
- t = parse_name(first + 2, last, db);
- if (t != first + 2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() = db.make<SpecialName>(
- "thread-local initialization routine for ", db.Names.back());
- first = t;
- }
- break;
- default:
- // T <call-offset> <base encoding>
- {
- const char* t0 = parse_call_offset(first+1, last);
- if (t0 == first+1)
- break;
- t = parse_encoding(t0, last, db);
- if (t != t0)
- {
- if (db.Names.empty())
- return first;
- if (first[1] == 'v')
- {
- db.Names.back() =
- db.make<SpecialName>("virtual thunk to ",
- db.Names.back());
- first = t;
- }
- else
- {
- db.Names.back() =
- db.make<SpecialName>("non-virtual thunk to ",
- db.Names.back());
- first = t;
- }
- }
- }
- break;
- }
- break;
- case 'G':
- switch (first[1])
- {
- case 'V':
- // GV <object name> # Guard variable for one-time initialization
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("guard variable for ", db.Names.back());
- first = t;
- }
- break;
- case 'R':
- // extension ::= GR <object name> # reference temporary for object
- t = parse_name(first+2, last, db);
- if (t != first+2)
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("reference temporary for ",
- db.Names.back());
- first = t;
- }
- break;
- }
- break;
- }
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+Node *Db::parseEncoding() {
+ if (look() == 'G' || look() == 'T')
+ return parseSpecialName();
+
+ auto IsEndOfEncoding = [&] {
+ // The set of chars that can potentially follow an <encoding> (none of which
+ // can start a <type>). Enumerating these allows us to avoid speculative
+ // parsing.
+ return numLeft() == 0 || look() == 'E' || look() == '.' || look() == '_';
+ };
+
+ NameState NameInfo(this);
+ Node *Name = parseName(&NameInfo);
+ if (Name == nullptr)
+ return nullptr;
+
+ if (resolveForwardTemplateRefs(NameInfo))
+ return nullptr;
+
+ if (IsEndOfEncoding())
+ return Name;
+
+ Node *Attrs = nullptr;
+ if (consumeIf("Ua9enable_ifI")) {
+ size_t BeforeArgs = Names.size();
+ while (!consumeIf('E')) {
+ Node *Arg = parseTemplateArg();
+ if (Arg == nullptr)
+ return nullptr;
+ Names.push_back(Arg);
}
- return first;
+ Attrs = make<EnableIfAttr>(popTrailingNodeArray(BeforeArgs));
+ }
+
+ Node *ReturnType = nullptr;
+ if (!NameInfo.CtorDtorConversion && NameInfo.EndsWithTemplateArgs) {
+ ReturnType = parseType();
+ if (ReturnType == nullptr)
+ return nullptr;
+ }
+
+ if (consumeIf('v'))
+ return make<FunctionEncoding>(ReturnType, Name, NodeArray(),
+ Attrs, NameInfo.CVQualifiers,
+ NameInfo.ReferenceQualifier);
+
+ size_t ParamsBegin = Names.size();
+ do {
+ Node *Ty = parseType();
+ if (Ty == nullptr)
+ return nullptr;
+ Names.push_back(Ty);
+ } while (!IsEndOfEncoding());
+
+ return make<FunctionEncoding>(ReturnType, Name,
+ popTrailingNodeArray(ParamsBegin),
+ Attrs, NameInfo.CVQualifiers,
+ NameInfo.ReferenceQualifier);
}
-template <class T>
-class save_value
+template <class Float>
+struct FloatData;
+
+template <>
+struct FloatData<float>
{
- T& restore_;
- T original_value_;
-public:
- save_value(T& restore)
- : restore_(restore),
- original_value_(restore)
- {}
+ static const size_t mangled_size = 8;
+ static const size_t max_demangled_size = 24;
+ static constexpr const char* spec = "%af";
+};
- ~save_value()
- {
- restore_ = std::move(original_value_);
- }
+constexpr const char* FloatData<float>::spec;
- save_value(const save_value&) = delete;
- save_value& operator=(const save_value&) = delete;
+template <>
+struct FloatData<double>
+{
+ static const size_t mangled_size = 16;
+ static const size_t max_demangled_size = 32;
+ static constexpr const char* spec = "%a";
};
-// <encoding> ::= <function name> <bare-function-type>
-// ::= <data name>
-// ::= <special-name>
+constexpr const char* FloatData<double>::spec;
-const char*
-parse_encoding(const char* first, const char* last, Db& db)
+template <>
+struct FloatData<long double>
{
- if (first != last)
- {
- save_value<decltype(db.EncodingDepth)> su(db.EncodingDepth);
- ++db.EncodingDepth;
- save_value<decltype(db.TagTemplates)> sb(db.TagTemplates);
- if (db.EncodingDepth > 1)
- db.TagTemplates = true;
- save_value<decltype(db.ParsedCtorDtorCV)> sp(db.ParsedCtorDtorCV);
- db.ParsedCtorDtorCV = false;
- switch (*first)
- {
- case 'G':
- case 'T':
- first = parse_special_name(first, last, db);
- break;
- default:
- {
- bool ends_with_template_args = false;
- const char* t = parse_name(first, last, db,
- &ends_with_template_args);
- if (db.Names.empty())
- return first;
- Qualifiers cv = db.CV;
- FunctionRefQual ref = db.RefQuals;
- if (t != first)
- {
- if (t != last && *t != 'E' && *t != '.')
- {
- save_value<bool> sb2(db.TagTemplates);
- db.TagTemplates = false;
- const char* t2;
- if (db.Names.empty())
- return first;
- if (!db.Names.back())
- return first;
- Node* return_type = nullptr;
- if (!db.ParsedCtorDtorCV && ends_with_template_args)
- {
- t2 = parse_type(t, last, db);
- if (t2 == t)
- return first;
- if (db.Names.size() < 1)
- return first;
- return_type = db.Names.back();
- db.Names.pop_back();
- t = t2;
- }
-
- Node* result = nullptr;
-
- if (t != last && *t == 'v')
- {
- ++t;
- if (db.Names.empty())
- return first;
- Node* name = db.Names.back();
- db.Names.pop_back();
- result = db.make<TopLevelFunctionDecl>(
- return_type, name, NodeArray());
- }
- else
- {
- size_t params_begin = db.Names.size();
- while (true)
- {
- t2 = parse_type(t, last, db);
- if (t2 == t)
- break;
- t = t2;
- }
- if (db.Names.size() < params_begin)
- return first;
- NodeArray params =
- db.popTrailingNodeArray(params_begin);
- if (db.Names.empty())
- return first;
- Node* name = db.Names.back();
- db.Names.pop_back();
- result = db.make<TopLevelFunctionDecl>(
- return_type, name, params);
- }
- if (ref != FrefQualNone)
- result = db.make<FunctionRefQualType>(result, ref);
- if (cv != QualNone)
- result = db.make<FunctionQualType>(result, cv);
- db.Names.push_back(result);
- first = t;
- }
- else
- first = t;
- }
- break;
- }
- }
- }
- return first;
+#if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \
+ defined(__wasm__)
+ static const size_t mangled_size = 32;
+#elif defined(__arm__) || defined(__mips__) || defined(__hexagon__)
+ static const size_t mangled_size = 16;
+#else
+ static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms
+#endif
+ static const size_t max_demangled_size = 40;
+ static constexpr const char *spec = "%LaL";
+};
+
+constexpr const char *FloatData<long double>::spec;
+
+template <class Float> Node *Db::parseFloatingLiteral() {
+ const size_t N = FloatData<Float>::mangled_size;
+ if (numLeft() <= N)
+ return nullptr;
+ StringView Data(First, First + N);
+ for (char C : Data)
+ if (!std::isxdigit(C))
+ return nullptr;
+ First += N;
+ if (!consumeIf('E'))
+ return nullptr;
+ return make<FloatExpr<Float>>(Data);
}
-// _block_invoke
-// _block_invoke<decimal-digit>+
-// _block_invoke_<decimal-digit>+
+// <seq-id> ::= <0-9A-Z>+
+bool Db::parseSeqId(size_t *Out) {
+ if (!(look() >= '0' && look() <= '9') &&
+ !(look() >= 'A' && look() <= 'Z'))
+ return true;
+
+ size_t Id = 0;
+ while (true) {
+ if (look() >= '0' && look() <= '9') {
+ Id *= 36;
+ Id += static_cast<size_t>(look() - '0');
+ } else if (look() >= 'A' && look() <= 'Z') {
+ Id *= 36;
+ Id += static_cast<size_t>(look() - 'A') + 10;
+ } else {
+ *Out = Id;
+ return false;
+ }
+ ++First;
+ }
+}
-const char*
-parse_block_invoke(const char* first, const char* last, Db& db)
-{
- if (last - first >= 13)
- {
- // FIXME: strcmp?
- const char test[] = "_block_invoke";
- const char* t = first;
- for (int i = 0; i < 13; ++i, ++t)
- {
- if (*t != test[i])
- return first;
- }
- if (t != last)
- {
- if (*t == '_')
- {
- // must have at least 1 decimal digit
- if (++t == last || !std::isdigit(*t))
- return first;
- ++t;
- }
- // parse zero or more digits
- while (t != last && isdigit(*t))
- ++t;
- }
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<SpecialName>("invocation function for block in ",
- db.Names.back());
- first = t;
+// <substitution> ::= S <seq-id> _
+// ::= S_
+// <substitution> ::= Sa # ::std::allocator
+// <substitution> ::= Sb # ::std::basic_string
+// <substitution> ::= Ss # ::std::basic_string < char,
+// ::std::char_traits<char>,
+// ::std::allocator<char> >
+// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> >
+// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> >
+// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> >
+Node *Db::parseSubstitution() {
+ if (!consumeIf('S'))
+ return nullptr;
+
+ if (std::islower(look())) {
+ Node *SpecialSub;
+ switch (look()) {
+ case 'a':
+ ++First;
+ SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator);
+ break;
+ case 'b':
+ ++First;
+ SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string);
+ break;
+ case 's':
+ ++First;
+ SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string);
+ break;
+ case 'i':
+ ++First;
+ SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream);
+ break;
+ case 'o':
+ ++First;
+ SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream);
+ break;
+ case 'd':
+ ++First;
+ SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream);
+ break;
+ default:
+ return nullptr;
}
- return first;
+ // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution>
+ // has ABI tags, the tags are appended to the substitution; the result is a
+ // substitutable component.
+ Node *WithTags = parseAbiTags(SpecialSub);
+ if (WithTags != SpecialSub) {
+ Subs.push_back(WithTags);
+ SpecialSub = WithTags;
+ }
+ return SpecialSub;
+ }
+
+ // ::= S_
+ if (consumeIf('_')) {
+ if (Subs.empty())
+ return nullptr;
+ return Subs[0];
+ }
+
+ // ::= S <seq-id> _
+ size_t Index = 0;
+ if (parseSeqId(&Index))
+ return nullptr;
+ ++Index;
+ if (!consumeIf('_') || Index >= Subs.size())
+ return nullptr;
+ return Subs[Index];
}
-// extension
-// <dot-suffix> := .<anything and everything>
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+Node *Db::parseTemplateParam() {
+ if (!consumeIf('T'))
+ return nullptr;
+
+ size_t Index = 0;
+ if (!consumeIf('_')) {
+ if (parsePositiveInteger(&Index))
+ return nullptr;
+ ++Index;
+ if (!consumeIf('_'))
+ return nullptr;
+ }
-const char*
-parse_dot_suffix(const char* first, const char* last, Db& db)
-{
- if (first != last && *first == '.')
- {
- if (db.Names.empty())
- return first;
- db.Names.back() =
- db.make<DotSuffix>(db.Names.back(), StringView(first, last));
- first = last;
+ // Itanium ABI 5.1.8: In a generic lambda, uses of auto in the parameter list
+ // are mangled as the corresponding artificial template type parameter.
+ if (ParsingLambdaParams)
+ return make<NameType>("auto");
+
+ // If we're in a context where this <template-param> refers to a
+ // <template-arg> further ahead in the mangled name (currently just conversion
+ // operator types), then we should only look it up in the right context.
+ if (PermitForwardTemplateReferences) {
+ ForwardTemplateRefs.push_back(make<ForwardTemplateReference>(Index));
+ return ForwardTemplateRefs.back();
+ }
+
+ if (Index >= TemplateParams.size())
+ return nullptr;
+ return TemplateParams[Index];
+}
+
+// <template-arg> ::= <type> # type or template
+// ::= X <expression> E # expression
+// ::= <expr-primary> # simple expressions
+// ::= J <template-arg>* E # argument pack
+// ::= LZ <encoding> E # extension
+Node *Db::parseTemplateArg() {
+ switch (look()) {
+ case 'X': {
+ ++First;
+ Node *Arg = parseExpr();
+ if (Arg == nullptr || !consumeIf('E'))
+ return nullptr;
+ return Arg;
+ }
+ case 'J': {
+ ++First;
+ size_t ArgsBegin = Names.size();
+ while (!consumeIf('E')) {
+ Node *Arg = parseTemplateArg();
+ if (Arg == nullptr)
+ return nullptr;
+ Names.push_back(Arg);
}
- return first;
+ NodeArray Args = popTrailingNodeArray(ArgsBegin);
+ return make<TemplateArgumentPack>(Args);
+ }
+ case 'L': {
+ // ::= LZ <encoding> E # extension
+ if (look(1) == 'Z') {
+ First += 2;
+ Node *Arg = parseEncoding();
+ if (Arg == nullptr || !consumeIf('E'))
+ return nullptr;
+ return Arg;
+ }
+ // ::= <expr-primary> # simple expressions
+ return parseExprPrimary();
+ }
+ default:
+ return parseType();
+ }
}
-// <block-involcaton-function> ___Z<encoding>_block_invoke
-// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+
-// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+
-// <mangled-name> ::= _Z<encoding>
-// ::= <type>
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
+Node *Db::parseTemplateArgs(bool TagTemplates) {
+ if (!consumeIf('I'))
+ return nullptr;
+
+ // <template-params> refer to the innermost <template-args>. Clear out any
+ // outer args that we may have inserted into TemplateParams.
+ if (TagTemplates)
+ TemplateParams.clear();
+
+ size_t ArgsBegin = Names.size();
+ while (!consumeIf('E')) {
+ if (TagTemplates) {
+ auto OldParams = std::move(TemplateParams);
+ Node *Arg = parseTemplateArg();
+ TemplateParams = std::move(OldParams);
+ if (Arg == nullptr)
+ return nullptr;
+ Names.push_back(Arg);
+ Node *TableEntry = Arg;
+ if (Arg->getKind() == Node::KTemplateArgumentPack) {
+ TableEntry = make<ParameterPack>(
+ static_cast<TemplateArgumentPack*>(TableEntry)->getElements());
+ }
+ TemplateParams.push_back(TableEntry);
+ } else {
+ Node *Arg = parseTemplateArg();
+ if (Arg == nullptr)
+ return nullptr;
+ Names.push_back(Arg);
+ }
+ }
+ return make<TemplateArgs>(popTrailingNodeArray(ArgsBegin));
+}
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+ # at the end of string
-void
-demangle(const char* first, const char* last, Db& db, int& status)
+const char*
+parse_discriminator(const char* first, const char* last)
{
- if (first >= last)
- {
- status = invalid_mangled_name;
- return;
- }
- if (*first == '_')
+ // parse but ignore discriminator
+ if (first != last)
{
- if (last - first >= 4)
+ if (*first == '_')
{
- if (first[1] == 'Z')
- {
- const char* t = parse_encoding(first+2, last, db);
- if (t != first+2 && t != last && *t == '.')
- t = parse_dot_suffix(t, last, db);
- if (t != last)
- status = invalid_mangled_name;
- }
- else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z')
+ const char* t1 = first+1;
+ if (t1 != last)
{
- const char* t = parse_encoding(first+4, last, db);
- if (t != first+4 && t != last)
+ if (std::isdigit(*t1))
+ first = t1+1;
+ else if (*t1 == '_')
{
- const char* t1 = parse_block_invoke(t, last, db);
- if (t1 != last)
- status = invalid_mangled_name;
+ for (++t1; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
}
- else
- status = invalid_mangled_name;
}
- else
- status = invalid_mangled_name;
}
- else
- status = invalid_mangled_name;
+ else if (std::isdigit(*first))
+ {
+ const char* t1 = first+1;
+ for (; t1 != last && std::isdigit(*t1); ++t1)
+ ;
+ if (t1 == last)
+ first = last;
+ }
}
- else
- {
- const char* t = parse_type(first, last, db);
- if (t != last)
- status = invalid_mangled_name;
+ return first;
+}
+
+// <mangled-name> ::= _Z <encoding>
+// ::= <type>
+// extension ::= ___Z <encoding> _block_invoke
+// extension ::= ___Z <encoding> _block_invoke<decimal-digit>+
+// extension ::= ___Z <encoding> _block_invoke_<decimal-digit>+
+Node *Db::parse() {
+ if (consumeIf("_Z")) {
+ Node *Encoding = parseEncoding();
+ if (Encoding == nullptr)
+ return nullptr;
+ if (look() == '.') {
+ Encoding = make<DotSuffix>(Encoding, StringView(First, Last));
+ First = Last;
}
- if (status == success && db.Names.empty())
- status = invalid_mangled_name;
+ if (numLeft() != 0)
+ return nullptr;
+ return Encoding;
+ }
+
+ if (consumeIf("___Z")) {
+ Node *Encoding = parseEncoding();
+ if (Encoding == nullptr || !consumeIf("_block_invoke"))
+ return nullptr;
+ bool RequireNumber = consumeIf('_');
+ if (parseNumber().empty() && RequireNumber)
+ return nullptr;
+ if (numLeft() != 0)
+ return nullptr;
+ return make<SpecialName>("invocation function for block in ", Encoding);
+ }
+
+ Node *Ty = parseType();
+ if (numLeft() != 0)
+ return nullptr;
+ return Ty;
+}
+
+bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
+ size_t InitSize) {
+ size_t BufferSize;
+ if (Buf == nullptr) {
+ Buf = static_cast<char *>(std::malloc(InitSize));
+ if (Buf == nullptr)
+ return true;
+ BufferSize = InitSize;
+ } else
+ BufferSize = *N;
+
+ S.reset(Buf, BufferSize);
+ return false;
}
} // unnamed namespace
+namespace __cxxabiv1 {
extern "C" _LIBCXXABI_FUNC_VIS char *
-__cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status) {
- if (mangled_name == nullptr || (buf != nullptr && n == nullptr))
- {
- if (status)
- *status = invalid_args;
- return nullptr;
- }
-
- size_t internal_size = buf != nullptr ? *n : 0;
- Db db;
- int internal_status = success;
- size_t len = std::strlen(mangled_name);
- demangle(mangled_name, mangled_name + len, db,
- internal_status);
-
- if (internal_status == success && db.FixForwardReferences &&
- !db.TemplateParams.empty())
- {
- db.FixForwardReferences = false;
- db.TagTemplates = false;
- db.Names.clear();
- db.Subs.clear();
- demangle(mangled_name, mangled_name + len, db, internal_status);
- if (db.FixForwardReferences)
- internal_status = invalid_mangled_name;
- }
+__cxa_demangle(const char *MangledName, char *Buf, size_t *N, int *Status) {
+ if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
+ if (Status)
+ *Status = demangle_invalid_args;
+ return nullptr;
+ }
- if (internal_status == success)
- {
- if (!buf)
- {
- internal_size = 1024;
- buf = static_cast<char*>(std::malloc(internal_size));
- }
+ int InternalStatus = demangle_success;
+ Db Parser(MangledName, MangledName + std::strlen(MangledName));
+ OutputStream S;
+
+ Node *AST = Parser.parse();
+
+ if (AST == nullptr)
+ InternalStatus = demangle_invalid_mangled_name;
+ else if (initializeOutputStream(Buf, N, S, 1024))
+ InternalStatus = demangle_memory_alloc_failure;
+ else {
+ assert(Parser.ForwardTemplateRefs.empty());
+ AST->print(S);
+ S += '\0';
+ if (N != nullptr)
+ *N = S.getCurrentPosition();
+ Buf = S.getBuffer();
+ }
- if (buf)
- {
- OutputStream s(buf, internal_size);
- db.Names.back()->print(s);
- s += '\0';
- if (n) *n = s.getCurrentPosition();
- buf = s.getBuffer();
- }
- else
- internal_status = memory_alloc_failure;
- }
- else
- buf = nullptr;
- if (status)
- *status = internal_status;
- return buf;
+ if (Status)
+ *Status = InternalStatus;
+ return InternalStatus == demangle_success ? Buf : nullptr;
}
-
} // __cxxabiv1
diff --git a/lib/libcxxabi/src/cxa_exception.cpp b/lib/libcxxabi/src/cxa_exception.cpp
index d5230cdc7d9..397427a0299 100644
--- a/lib/libcxxabi/src/cxa_exception.cpp
+++ b/lib/libcxxabi/src/cxa_exception.cpp
@@ -18,6 +18,7 @@
#include "cxa_exception.hpp"
#include "cxa_handlers.hpp"
#include "fallback_malloc.h"
+#include "include/atomic_support.h"
#if __has_feature(address_sanitizer)
extern "C" void __asan_handle_no_return(void);
@@ -616,7 +617,7 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() {
if (thrown_object != NULL )
{
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
- __sync_add_and_fetch(&exception_header->referenceCount, 1);
+ std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
}
}
@@ -628,12 +629,12 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() {
Requires: If thrown_object is not NULL, it is a native exception.
*/
-void
-__cxa_decrement_exception_refcount(void *thrown_object) throw() {
+_LIBCXXABI_NO_CFI
+void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
if (thrown_object != NULL )
{
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
- if (__sync_sub_and_fetch(&exception_header->referenceCount, size_t(1)) == 0)
+ if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0)
{
if (NULL != exception_header->exceptionDestructor)
exception_header->exceptionDestructor(thrown_object);
diff --git a/lib/libcxxabi/src/cxa_handlers.cpp b/lib/libcxxabi/src/cxa_handlers.cpp
index 2881a2a65fe..622e93c354e 100644
--- a/lib/libcxxabi/src/cxa_handlers.cpp
+++ b/lib/libcxxabi/src/cxa_handlers.cpp
@@ -18,6 +18,7 @@
#include "cxa_handlers.hpp"
#include "cxa_exception.hpp"
#include "private_typeinfo.h"
+#include "include/atomic_support.h"
namespace std
{
@@ -25,10 +26,7 @@ namespace std
unexpected_handler
get_unexpected() _NOEXCEPT
{
- return __sync_fetch_and_add(&__cxa_unexpected_handler, (unexpected_handler)0);
-// The above is safe but overkill on x86
-// Using of C++11 atomics this should be rewritten
-// return __cxa_unexpected_handler.load(memory_order_acq);
+ return __libcpp_atomic_load(&__cxa_unexpected_handler, _AO_Acquire);
}
void
@@ -49,10 +47,7 @@ unexpected()
terminate_handler
get_terminate() _NOEXCEPT
{
- return __sync_fetch_and_add(&__cxa_terminate_handler, (terminate_handler)0);
-// The above is safe but overkill on x86
-// Using of C++11 atomics this should be rewritten
-// return __cxa_terminate_handler.load(memory_order_acq);
+ return __libcpp_atomic_load(&__cxa_terminate_handler, _AO_Acquire);
}
void
@@ -99,8 +94,6 @@ terminate() _NOEXCEPT
__terminate(get_terminate());
}
-// In the future this will become:
-// std::atomic<std::new_handler> __cxa_new_handler(0);
extern "C" {
new_handler __cxa_new_handler = 0;
}
@@ -108,18 +101,13 @@ new_handler __cxa_new_handler = 0;
new_handler
set_new_handler(new_handler handler) _NOEXCEPT
{
- return __atomic_exchange_n(&__cxa_new_handler, handler, __ATOMIC_ACQ_REL);
-// Using of C++11 atomics this should be rewritten
-// return __cxa_new_handler.exchange(handler, memory_order_acq_rel);
+ return __libcpp_atomic_exchange(&__cxa_new_handler, handler, _AO_Acq_Rel);
}
new_handler
get_new_handler() _NOEXCEPT
{
- return __sync_fetch_and_add(&__cxa_new_handler, (new_handler)0);
-// The above is safe but overkill on x86
-// Using of C++11 atomics this should be rewritten
-// return __cxa_new_handler.load(memory_order_acq);
+ return __libcpp_atomic_load(&__cxa_new_handler, _AO_Acquire);
}
} // std
diff --git a/lib/libcxxabi/src/cxa_personality.cpp b/lib/libcxxabi/src/cxa_personality.cpp
index 7f857faf78f..6759d8a71f9 100644
--- a/lib/libcxxabi/src/cxa_personality.cpp
+++ b/lib/libcxxabi/src/cxa_personality.cpp
@@ -23,6 +23,16 @@
#include "private_typeinfo.h"
#include "unwind.h"
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#include <windows.h>
+#include <winnt.h>
+
+extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD,
+ void *, PCONTEXT,
+ PDISPATCHER_CONTEXT,
+ _Unwind_Personality_Fn);
+#endif
+
/*
Exception Header Layout:
@@ -934,12 +944,16 @@ _UA_CLEANUP_PHASE
*/
#if !defined(_LIBCXXABI_ARM_EHABI)
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+static _Unwind_Reason_Code __gxx_personality_imp
+#else
_LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
#ifdef __USING_SJLJ_EXCEPTIONS__
__gxx_personality_sj0
#else
__gxx_personality_v0
#endif
+#endif
(int version, _Unwind_Action actions, uint64_t exceptionClass,
_Unwind_Exception* unwind_exception, _Unwind_Context* context)
{
@@ -1022,6 +1036,17 @@ __gxx_personality_v0
// We were called improperly: neither a phase 1 or phase 2 search
return _URC_FATAL_PHASE1_ERROR;
}
+
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+extern "C" EXCEPTION_DISPOSITION
+__gxx_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
+ PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp)
+{
+ return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
+ __gxx_personality_imp);
+}
+#endif
+
#else
extern "C" _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Exception*,
diff --git a/lib/libcxxabi/src/demangle/Compiler.h b/lib/libcxxabi/src/demangle/Compiler.h
new file mode 100644
index 00000000000..e5f3c72a451
--- /dev/null
+++ b/lib/libcxxabi/src/demangle/Compiler.h
@@ -0,0 +1,34 @@
+//===--- Compiler.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// This file is contains a subset of macros copied from
+// llvm/lib/Demangle/Compiler.h.
+//===----------------------------------------------------------------------===//
+
+#ifndef LIBCXX_DEMANGLE_COMPILER_H
+#define LIBCXX_DEMANGLE_COMPILER_H
+
+#ifdef _MSC_VER
+// snprintf is implemented in VS 2015
+#if _MSC_VER < 1900
+#define snprintf _snprintf_s
+#endif
+#endif
+
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
+#ifndef NDEBUG
+#if __has_attribute(noinline) && __has_attribute(used)
+#define DUMP_METHOD __attribute__((noinline, used))
+#else
+#define DUMP_METHOD
+#endif
+#endif
+
+#endif
diff --git a/lib/libcxxabi/src/demangle/StringView.h b/lib/libcxxabi/src/demangle/StringView.h
new file mode 100644
index 00000000000..986f2defc08
--- /dev/null
+++ b/lib/libcxxabi/src/demangle/StringView.h
@@ -0,0 +1,98 @@
+//===--- StringView.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//
+// This file is copied from llvm/lib/Demangle/StringView.h.
+//===----------------------------------------------------------------------===//
+
+#ifndef LIBCXX_DEMANGLE_STRINGVIEW_H
+#define LIBCXX_DEMANGLE_STRINGVIEW_H
+
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+
+namespace {
+class StringView {
+ const char *First;
+ const char *Last;
+
+public:
+ template <size_t N>
+ StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
+ StringView(const char *First_, const char *Last_)
+ : First(First_), Last(Last_) {}
+ StringView(const char *First_, size_t Len)
+ : First(First_), Last(First_ + Len) {}
+ StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
+ StringView() : First(nullptr), Last(nullptr) {}
+
+ StringView substr(size_t From) const {
+ return StringView(begin() + From, size() - From);
+ }
+
+ StringView substr(size_t From, size_t To) const {
+ if (To >= size())
+ To = size() - 1;
+ if (From >= size())
+ From = size() - 1;
+ return StringView(First + From, First + To);
+ }
+
+ StringView dropFront(size_t N = 1) const {
+ if (N >= size())
+ N = size() - 1;
+ return StringView(First + N, Last);
+ }
+
+ char front() const {
+ assert(!empty());
+ return *begin();
+ }
+
+ char popFront() {
+ assert(!empty());
+ return *First++;
+ }
+
+ bool consumeFront(char C) {
+ if (!startsWith(C))
+ return false;
+ *this = dropFront(1);
+ return true;
+ }
+
+ bool consumeFront(StringView S) {
+ if (!startsWith(S))
+ return false;
+ *this = dropFront(S.size());
+ return true;
+ }
+
+ bool startsWith(char C) const { return !empty() && *begin() == C; }
+
+ bool startsWith(StringView Str) const {
+ if (Str.size() > size())
+ return false;
+ return std::equal(Str.begin(), Str.end(), begin());
+ }
+
+ const char &operator[](size_t Idx) const { return *(begin() + Idx); }
+
+ const char *begin() const { return First; }
+ const char *end() const { return Last; }
+ size_t size() const { return static_cast<size_t>(Last - First); }
+ bool empty() const { return First == Last; }
+};
+
+inline bool operator==(const StringView &LHS, const StringView &RHS) {
+ return LHS.size() == RHS.size() &&
+ std::equal(LHS.begin(), LHS.end(), RHS.begin());
+}
+} // namespace
+
+#endif
diff --git a/lib/libcxxabi/src/demangle/Utility.h b/lib/libcxxabi/src/demangle/Utility.h
new file mode 100644
index 00000000000..39092436283
--- /dev/null
+++ b/lib/libcxxabi/src/demangle/Utility.h
@@ -0,0 +1,191 @@
+//===--- Utility.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//
+// This file is copied from llvm/lib/Demangle/Utility.h.
+//===----------------------------------------------------------------------===//
+
+#ifndef LIBCXX_DEMANGLE_UTILITY_H
+#define LIBCXX_DEMANGLE_UTILITY_H
+
+#include "StringView.h"
+
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iterator>
+#include <limits>
+
+namespace {
+// Stream that AST nodes write their string representation into after the AST
+// has been parsed.
+class OutputStream {
+ char *Buffer;
+ size_t CurrentPosition;
+ size_t BufferCapacity;
+
+ // Ensure there is at least n more positions in buffer.
+ void grow(size_t N) {
+ if (N + CurrentPosition >= BufferCapacity) {
+ BufferCapacity *= 2;
+ if (BufferCapacity < N + CurrentPosition)
+ BufferCapacity = N + CurrentPosition;
+ Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
+ if (Buffer == nullptr)
+ std::terminate();
+ }
+ }
+
+ void writeUnsigned(uint64_t N, bool isNeg = false) {
+ // Handle special case...
+ if (N == 0) {
+ *this << '0';
+ return;
+ }
+
+ char Temp[21];
+ char *TempPtr = std::end(Temp);
+
+ while (N) {
+ *--TempPtr = '0' + char(N % 10);
+ N /= 10;
+ }
+
+ // Add negative sign...
+ if (isNeg)
+ *--TempPtr = '-';
+ this->operator<<(StringView(TempPtr, std::end(Temp)));
+ }
+
+public:
+ OutputStream(char *StartBuf, size_t Size)
+ : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
+ OutputStream() = default;
+ void reset(char *Buffer_, size_t BufferCapacity_) {
+ CurrentPosition = 0;
+ Buffer = Buffer_;
+ BufferCapacity = BufferCapacity_;
+ }
+
+ /// Create an OutputStream from a buffer and a size. If either of these are
+ /// null a buffer is allocated.
+ static OutputStream create(char *StartBuf, size_t *Size, size_t AllocSize) {
+ OutputStream Result;
+
+ if (!StartBuf || !Size) {
+ StartBuf = static_cast<char *>(std::malloc(AllocSize));
+ if (StartBuf == nullptr)
+ std::terminate();
+ Size = &AllocSize;
+ }
+
+ Result.reset(StartBuf, *Size);
+ return Result;
+ }
+
+ /// If a ParameterPackExpansion (or similar type) is encountered, the offset
+ /// into the pack that we're currently printing.
+ unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
+ unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
+
+ OutputStream &operator+=(StringView R) {
+ size_t Size = R.size();
+ if (Size == 0)
+ return *this;
+ grow(Size);
+ std::memmove(Buffer + CurrentPosition, R.begin(), Size);
+ CurrentPosition += Size;
+ return *this;
+ }
+
+ OutputStream &operator+=(char C) {
+ grow(1);
+ Buffer[CurrentPosition++] = C;
+ return *this;
+ }
+
+ OutputStream &operator<<(StringView R) { return (*this += R); }
+
+ OutputStream &operator<<(char C) { return (*this += C); }
+
+ OutputStream &operator<<(long long N) {
+ if (N < 0)
+ writeUnsigned(static_cast<unsigned long long>(-N), true);
+ else
+ writeUnsigned(static_cast<unsigned long long>(N));
+ return *this;
+ }
+
+ OutputStream &operator<<(unsigned long long N) {
+ writeUnsigned(N, false);
+ return *this;
+ }
+
+ OutputStream &operator<<(long N) {
+ return this->operator<<(static_cast<long long>(N));
+ }
+
+ OutputStream &operator<<(unsigned long N) {
+ return this->operator<<(static_cast<unsigned long long>(N));
+ }
+
+ OutputStream &operator<<(int N) {
+ return this->operator<<(static_cast<long long>(N));
+ }
+
+ OutputStream &operator<<(unsigned int N) {
+ return this->operator<<(static_cast<unsigned long long>(N));
+ }
+
+ size_t getCurrentPosition() const { return CurrentPosition; }
+ void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
+
+ char back() const {
+ return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
+ }
+
+ bool empty() const { return CurrentPosition == 0; }
+
+ char *getBuffer() { return Buffer; }
+ char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
+ size_t getBufferCapacity() { return BufferCapacity; }
+};
+
+template <class T> class SwapAndRestore {
+ T &Restore;
+ T OriginalValue;
+ bool ShouldRestore = true;
+
+public:
+ SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
+
+ SwapAndRestore(T &Restore_, T NewVal)
+ : Restore(Restore_), OriginalValue(Restore) {
+ Restore = std::move(NewVal);
+ }
+ ~SwapAndRestore() {
+ if (ShouldRestore)
+ Restore = std::move(OriginalValue);
+ }
+
+ void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
+
+ void restoreNow(bool Force) {
+ if (!Force && !ShouldRestore)
+ return;
+
+ Restore = std::move(OriginalValue);
+ ShouldRestore = false;
+ }
+
+ SwapAndRestore(const SwapAndRestore &) = delete;
+ SwapAndRestore &operator=(const SwapAndRestore &) = delete;
+};
+
+} // namespace
+
+#endif
diff --git a/lib/libcxxabi/src/fallback_malloc.cpp b/lib/libcxxabi/src/fallback_malloc.cpp
index 336ad31b017..bec9952596b 100644
--- a/lib/libcxxabi/src/fallback_malloc.cpp
+++ b/lib/libcxxabi/src/fallback_malloc.cpp
@@ -7,6 +7,9 @@
//
//===----------------------------------------------------------------------===//
+// Define _LIBCPP_BUILDING_LIBRARY to ensure _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
+// is only defined when libc aligned allocation is not available.
+#define _LIBCPP_BUILDING_LIBRARY
#include "fallback_malloc.h"
#include <__threading_support>
diff --git a/lib/libcxxabi/src/include/atomic_support.h b/lib/libcxxabi/src/include/atomic_support.h
new file mode 100644
index 00000000000..96dbd2ccd16
--- /dev/null
+++ b/lib/libcxxabi/src/include/atomic_support.h
@@ -0,0 +1,181 @@
+//===----------------------------------------------------------------------===////
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===////
+
+// FIXME: This file is copied from libcxx/src/include/atomic_support.h. Instead
+// of duplicating the file in libc++abi we should require that the libc++
+// sources are available when building libc++abi.
+
+#ifndef ATOMIC_SUPPORT_H
+#define ATOMIC_SUPPORT_H
+
+#include "__config"
+#include "memory" // for __libcpp_relaxed_load
+
+#if defined(__clang__) && __has_builtin(__atomic_load_n) \
+ && __has_builtin(__atomic_store_n) \
+ && __has_builtin(__atomic_add_fetch) \
+ && __has_builtin(__atomic_exchange_n) \
+ && __has_builtin(__atomic_compare_exchange_n) \
+ && defined(__ATOMIC_RELAXED) \
+ && defined(__ATOMIC_CONSUME) \
+ && defined(__ATOMIC_ACQUIRE) \
+ && defined(__ATOMIC_RELEASE) \
+ && defined(__ATOMIC_ACQ_REL) \
+ && defined(__ATOMIC_SEQ_CST)
+# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
+#elif !defined(__clang__) && defined(_GNUC_VER) && _GNUC_VER >= 407
+# define _LIBCXXABI_HAS_ATOMIC_BUILTINS
+#endif
+
+#if !defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
+# if defined(_LIBCPP_WARNING)
+ _LIBCPP_WARNING("Building libc++ without __atomic builtins is unsupported")
+# else
+# warning Building libc++ without __atomic builtins is unsupported
+# endif
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace {
+
+#if defined(_LIBCXXABI_HAS_ATOMIC_BUILTINS) && !defined(_LIBCXXABI_HAS_NO_THREADS)
+
+enum __libcpp_atomic_order {
+ _AO_Relaxed = __ATOMIC_RELAXED,
+ _AO_Consume = __ATOMIC_CONSUME,
+ _AO_Acquire = __ATOMIC_ACQUIRE,
+ _AO_Release = __ATOMIC_RELEASE,
+ _AO_Acq_Rel = __ATOMIC_ACQ_REL,
+ _AO_Seq = __ATOMIC_SEQ_CST
+};
+
+template <class _ValueType, class _FromType>
+inline _LIBCPP_INLINE_VISIBILITY
+void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
+ int __order = _AO_Seq)
+{
+ __atomic_store_n(__dest, __val, __order);
+}
+
+template <class _ValueType, class _FromType>
+inline _LIBCPP_INLINE_VISIBILITY
+void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
+{
+ __atomic_store_n(__dest, __val, _AO_Relaxed);
+}
+
+template <class _ValueType>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_load(_ValueType const* __val,
+ int __order = _AO_Seq)
+{
+ return __atomic_load_n(__val, __order);
+}
+
+template <class _ValueType, class _AddType>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
+ int __order = _AO_Seq)
+{
+ return __atomic_add_fetch(__val, __a, __order);
+}
+
+template <class _ValueType>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_exchange(_ValueType* __target,
+ _ValueType __value, int __order = _AO_Seq)
+{
+ return __atomic_exchange_n(__target, __value, __order);
+}
+
+template <class _ValueType>
+inline _LIBCPP_INLINE_VISIBILITY
+bool __libcpp_atomic_compare_exchange(_ValueType* __val,
+ _ValueType* __expected, _ValueType __after,
+ int __success_order = _AO_Seq,
+ int __fail_order = _AO_Seq)
+{
+ return __atomic_compare_exchange_n(__val, __expected, __after, true,
+ __success_order, __fail_order);
+}
+
+#else // _LIBCPP_HAS_NO_THREADS
+
+enum __libcpp_atomic_order {
+ _AO_Relaxed,
+ _AO_Consume,
+ _AO_Acquire,
+ _AO_Release,
+ _AO_Acq_Rel,
+ _AO_Seq
+};
+
+template <class _ValueType, class _FromType>
+inline _LIBCPP_INLINE_VISIBILITY
+void __libcpp_atomic_store(_ValueType* __dest, _FromType __val,
+ int = 0)
+{
+ *__dest = __val;
+}
+
+template <class _ValueType, class _FromType>
+inline _LIBCPP_INLINE_VISIBILITY
+void __libcpp_relaxed_store(_ValueType* __dest, _FromType __val)
+{
+ *__dest = __val;
+}
+
+template <class _ValueType>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_load(_ValueType const* __val,
+ int = 0)
+{
+ return *__val;
+}
+
+template <class _ValueType, class _AddType>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_add(_ValueType* __val, _AddType __a,
+ int = 0)
+{
+ return *__val += __a;
+}
+
+template <class _ValueType>
+inline _LIBCPP_INLINE_VISIBILITY
+_ValueType __libcpp_atomic_exchange(_ValueType* __target,
+ _ValueType __value, int __order = _AO_Seq)
+{
+ _ValueType old = *__target;
+ *__target = __value;
+ return old;
+}
+
+template <class _ValueType>
+inline _LIBCPP_INLINE_VISIBILITY
+bool __libcpp_atomic_compare_exchange(_ValueType* __val,
+ _ValueType* __expected, _ValueType __after,
+ int = 0, int = 0)
+{
+ if (*__val == *__expected) {
+ *__val = __after;
+ return true;
+ }
+ *__expected = *__val;
+ return false;
+}
+
+#endif // _LIBCPP_HAS_NO_THREADS
+
+} // end namespace
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // ATOMIC_SUPPORT_H
diff --git a/lib/libcxxabi/src/include/refstring.h b/lib/libcxxabi/src/include/refstring.h
index bc131aeb5ae..69f6747e125 100644
--- a/lib/libcxxabi/src/include/refstring.h
+++ b/lib/libcxxabi/src/include/refstring.h
@@ -22,6 +22,7 @@
#include <dlfcn.h>
#include <mach-o/dyld.h>
#endif
+#include "atomic_support.h"
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -87,7 +88,7 @@ __libcpp_refstring::__libcpp_refstring(const __libcpp_refstring &s) _NOEXCEPT
: __imp_(s.__imp_)
{
if (__uses_refcount())
- __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1);
+ __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
}
inline
@@ -96,10 +97,10 @@ __libcpp_refstring& __libcpp_refstring::operator=(__libcpp_refstring const& s) _
struct _Rep_base *old_rep = rep_from_data(__imp_);
__imp_ = s.__imp_;
if (__uses_refcount())
- __sync_add_and_fetch(&rep_from_data(__imp_)->count, 1);
+ __libcpp_atomic_add(&rep_from_data(__imp_)->count, 1);
if (adjust_old_count)
{
- if (__sync_add_and_fetch(&old_rep->count, count_t(-1)) < 0)
+ if (__libcpp_atomic_add(&old_rep->count, count_t(-1)) < 0)
{
::operator delete(old_rep);
}
@@ -111,7 +112,7 @@ inline
__libcpp_refstring::~__libcpp_refstring() {
if (__uses_refcount()) {
_Rep_base* rep = rep_from_data(__imp_);
- if (__sync_add_and_fetch(&rep->count, count_t(-1)) < 0) {
+ if (__libcpp_atomic_add(&rep->count, count_t(-1)) < 0) {
::operator delete(rep);
}
}
diff --git a/lib/libcxxabi/src/private_typeinfo.cpp b/lib/libcxxabi/src/private_typeinfo.cpp
index ef9466ef610..a0326a188c4 100644
--- a/lib/libcxxabi/src/private_typeinfo.cpp
+++ b/lib/libcxxabi/src/private_typeinfo.cpp
@@ -859,13 +859,14 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
// Record the access path that got us here
// If there is more than one dst_type this path doesn't matter.
info->path_dynamic_ptr_to_dst_ptr = path_below;
+ bool does_dst_type_point_to_our_static_type = false;
// Only search above here if dst_type derives from static_type, or
// if it is unknown if dst_type derives from static_type.
if (info->is_dst_type_derived_from_static_type != no)
{
// Set up flags to record results from all base classes
bool is_dst_type_derived_from_static_type = false;
- bool does_dst_type_point_to_our_static_type = false;
+
// We've found a dst_type with a potentially public path to here.
// We have to assume the path is public because it may become
// public later (if we get back to here with a public path).
@@ -909,21 +910,6 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
}
}
}
- if (!does_dst_type_point_to_our_static_type)
- {
- // We found a dst_type that doesn't point to (static_ptr, static_type)
- // So record the address of this dst_ptr and increment the
- // count of the number of such dst_types found in the tree.
- info->dst_ptr_not_leading_to_static_ptr = current_ptr;
- info->number_to_dst_ptr += 1;
- // If there exists another dst with a private path to
- // (static_ptr, static_type), then the cast from
- // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,
- // so stop search.
- if (info->number_to_static_ptr == 1 &&
- info->path_dst_ptr_to_static_ptr == not_public_path)
- info->search_done = true;
- }
// If we found no static_type,s then dst_type doesn't derive
// from static_type, else it does. Record this result so that
// next time we hit a dst_type we will know not to search above
@@ -932,7 +918,22 @@ __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
info->is_dst_type_derived_from_static_type = yes;
else
info->is_dst_type_derived_from_static_type = no;
- }
+ }
+ if (!does_dst_type_point_to_our_static_type)
+ {
+ // We found a dst_type that doesn't point to (static_ptr, static_type)
+ // So record the address of this dst_ptr and increment the
+ // count of the number of such dst_types found in the tree.
+ info->dst_ptr_not_leading_to_static_ptr = current_ptr;
+ info->number_to_dst_ptr += 1;
+ // If there exists another dst with a private path to
+ // (static_ptr, static_type), then the cast from
+ // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous,
+ // so stop search.
+ if (info->number_to_static_ptr == 1 &&
+ info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->search_done = true;
+ }
}
}
else
@@ -1030,13 +1031,13 @@ __si_class_type_info::search_below_dst(__dynamic_cast_info* info,
// Record the access path that got us here
// If there is more than one dst_type this path doesn't matter.
info->path_dynamic_ptr_to_dst_ptr = path_below;
+ bool does_dst_type_point_to_our_static_type = false;
// Only search above here if dst_type derives from static_type, or
// if it is unknown if dst_type derives from static_type.
if (info->is_dst_type_derived_from_static_type != no)
{
// Set up flags to record results from all base classes
bool is_dst_type_derived_from_static_type = false;
- bool does_dst_type_point_to_our_static_type = false;
// Zero out found flags
info->found_our_static_ptr = false;
info->found_any_static_type = false;
@@ -1047,20 +1048,6 @@ __si_class_type_info::search_below_dst(__dynamic_cast_info* info,
if (info->found_our_static_ptr)
does_dst_type_point_to_our_static_type = true;
}
- if (!does_dst_type_point_to_our_static_type)
- {
- // We found a dst_type that doesn't point to (static_ptr, static_type)
- // So record the address of this dst_ptr and increment the
- // count of the number of such dst_types found in the tree.
- info->dst_ptr_not_leading_to_static_ptr = current_ptr;
- info->number_to_dst_ptr += 1;
- // If there exists another dst with a private path to
- // (static_ptr, static_type), then the cast from
- // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
- if (info->number_to_static_ptr == 1 &&
- info->path_dst_ptr_to_static_ptr == not_public_path)
- info->search_done = true;
- }
// If we found no static_type,s then dst_type doesn't derive
// from static_type, else it does. Record this result so that
// next time we hit a dst_type we will know not to search above
@@ -1070,6 +1057,20 @@ __si_class_type_info::search_below_dst(__dynamic_cast_info* info,
else
info->is_dst_type_derived_from_static_type = no;
}
+ if (!does_dst_type_point_to_our_static_type)
+ {
+ // We found a dst_type that doesn't point to (static_ptr, static_type)
+ // So record the address of this dst_ptr and increment the
+ // count of the number of such dst_types found in the tree.
+ info->dst_ptr_not_leading_to_static_ptr = current_ptr;
+ info->number_to_dst_ptr += 1;
+ // If there exists another dst with a private path to
+ // (static_ptr, static_type), then the cast from
+ // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous.
+ if (info->number_to_static_ptr == 1 &&
+ info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->search_done = true;
+ }
}
}
else
@@ -1181,6 +1182,8 @@ __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
info->found_our_static_ptr = false;
info->found_any_static_type = false;
p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
+ found_our_static_ptr |= info->found_our_static_ptr;
+ found_any_static_type |= info->found_any_static_type;
if (++p < e)
{
do
@@ -1210,6 +1213,8 @@ __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
info->found_our_static_ptr = false;
info->found_any_static_type = false;
p->search_above_dst(info, dst_ptr, current_ptr, path_below, use_strcmp);
+ found_our_static_ptr |= info->found_our_static_ptr;
+ found_any_static_type |= info->found_any_static_type;
} while (++p < e);
}
// Restore flags
diff --git a/lib/libcxxabi/src/stdlib_exception.cpp b/lib/libcxxabi/src/stdlib_exception.cpp
index a8f71ab0ecc..6c0910267d4 100644
--- a/lib/libcxxabi/src/stdlib_exception.cpp
+++ b/lib/libcxxabi/src/stdlib_exception.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#define _LIBCPP_BUILDING_LIBRARY
-#define _LIBCPP_BUILDING_NEW
#include <new>
#include <exception>
diff --git a/lib/libcxxabi/src/stdlib_new_delete.cpp b/lib/libcxxabi/src/stdlib_new_delete.cpp
index 0e85f6ad299..686ad07ccd5 100644
--- a/lib/libcxxabi/src/stdlib_new_delete.cpp
+++ b/lib/libcxxabi/src/stdlib_new_delete.cpp
@@ -9,7 +9,6 @@
// This file implements the new and delete operators.
//===----------------------------------------------------------------------===//
-#define _LIBCPP_BUILDING_NEW
#define _LIBCPP_BUILDING_LIBRARY
#include "__cxxabi_config.h"
#include <new>