aboutsummaryrefslogtreecommitdiff
path: root/system/lib
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2012-02-22 11:23:32 -0800
committerAlon Zakai <alonzakai@gmail.com>2012-02-22 11:23:32 -0800
commitdd979ed995ce4a82b505fba2f29a8f32dc900bdd (patch)
treea6f11f4ad5d17bfcfbcc53b0f477b60e7dff2dd7 /system/lib
parentf53e69d92372020949c5ac0ca8f5ffdc67fb42fb (diff)
bundle libcxxabi
Diffstat (limited to 'system/lib')
-rw-r--r--system/lib/libcxxabi/CREDITS.TXT22
-rw-r--r--system/lib/libcxxabi/LICENSE.TXT76
-rw-r--r--system/lib/libcxxabi/Makefile27
-rw-r--r--system/lib/libcxxabi/include/cxa_demangle.h167
-rw-r--r--system/lib/libcxxabi/include/cxxabi.h175
-rwxr-xr-xsystem/lib/libcxxabi/lib/buildit90
-rw-r--r--system/lib/libcxxabi/readme.txt1
-rw-r--r--system/lib/libcxxabi/src/abort_message.cpp60
-rw-r--r--system/lib/libcxxabi/src/abort_message.h33
-rw-r--r--system/lib/libcxxabi/src/cxa_aux_runtime.cpp34
-rw-r--r--system/lib/libcxxabi/src/cxa_demangle.cpp10798
-rw-r--r--system/lib/libcxxabi/src/cxa_exception.cpp622
-rw-r--r--system/lib/libcxxabi/src/cxa_exception.hpp118
-rw-r--r--system/lib/libcxxabi/src/cxa_exception_storage.cpp91
-rw-r--r--system/lib/libcxxabi/src/cxa_guard.cpp231
-rw-r--r--system/lib/libcxxabi/src/cxa_handlers.cpp196
-rw-r--r--system/lib/libcxxabi/src/cxa_handlers.hpp26
-rw-r--r--system/lib/libcxxabi/src/cxa_new_delete.cpp231
-rw-r--r--system/lib/libcxxabi/src/cxa_personality.cpp987
-rw-r--r--system/lib/libcxxabi/src/cxa_unexpected.cpp27
-rw-r--r--system/lib/libcxxabi/src/cxa_vector.cpp367
-rw-r--r--system/lib/libcxxabi/src/cxa_virtual.cpp31
-rw-r--r--system/lib/libcxxabi/src/exception.cpp41
-rw-r--r--system/lib/libcxxabi/src/fallback_malloc.ipp174
-rw-r--r--system/lib/libcxxabi/src/private_typeinfo.cpp1036
-rw-r--r--system/lib/libcxxabi/src/private_typeinfo.h246
-rw-r--r--system/lib/libcxxabi/src/stdexcept.cpp122
-rw-r--r--system/lib/libcxxabi/src/temporary.cpp41
-rw-r--r--system/lib/libcxxabi/src/typeinfo.cpp53
29 files changed, 16123 insertions, 0 deletions
diff --git a/system/lib/libcxxabi/CREDITS.TXT b/system/lib/libcxxabi/CREDITS.TXT
new file mode 100644
index 00000000..a99245f7
--- /dev/null
+++ b/system/lib/libcxxabi/CREDITS.TXT
@@ -0,0 +1,22 @@
+This file is a partial list of people who have contributed to the LLVM/libc++abi
+project. If you have contributed a patch or made some other contribution to
+LLVM/libc++abi, please submit a patch to this file to add yourself, and it will be
+done!
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Howard Hinnant
+E: hhinnant@apple.com
+D: Architect and primary coauthor of libc++abi
+
+N: Marshall Clow
+E: marshall@idio.com
+E: mclow.lists@gmail.com
+E: mclow@qualcomm.com
+D: Architect and primary coauthor of libc++abi
+
+N: Nick Kledzik
+E: kledzik@apple.com
diff --git a/system/lib/libcxxabi/LICENSE.TXT b/system/lib/libcxxabi/LICENSE.TXT
new file mode 100644
index 00000000..40ce7c7d
--- /dev/null
+++ b/system/lib/libcxxabi/LICENSE.TXT
@@ -0,0 +1,76 @@
+==============================================================================
+libc++abi License
+==============================================================================
+
+The libc++abi library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license. As a user of this code you may choose
+to use it under either license. As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2010 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2010 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/system/lib/libcxxabi/Makefile b/system/lib/libcxxabi/Makefile
new file mode 100644
index 00000000..86d88976
--- /dev/null
+++ b/system/lib/libcxxabi/Makefile
@@ -0,0 +1,27 @@
+OBJECTS = \
+ cxa_vector.bc \
+ private_typeinfo.bc \
+ cxa_virtual.bc \
+ temporary.bc \
+ cxa_guard.bc \
+ cxa_unexpected.bc \
+ cxa_exception.bc \
+ cxa_aux_runtime.bc \
+ exception.bc \
+ stdexcept.bc \
+ abort_message.bc \
+ cxa_personality.bc \
+ cxa_new_delete.bc \
+ cxa_handlers.bc \
+ cxa_exception_storage.bc \
+ typeinfo.bc \
+ cxa_demangle.bc
+
+all: libcxx.bc
+
+%.bc: %.cpp
+ $(CXX) $< -o $@
+
+libcxx.bc: $(OBJECTS)
+ $(CXX) $(OBJECTS) -o libcxxabi.bc
+
diff --git a/system/lib/libcxxabi/include/cxa_demangle.h b/system/lib/libcxxabi/include/cxa_demangle.h
new file mode 100644
index 00000000..46dc9821
--- /dev/null
+++ b/system/lib/libcxxabi/include/cxa_demangle.h
@@ -0,0 +1,167 @@
+//===-------------------------- cxa_demangle.h ----------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _CXA_DEMANGLE_H
+#define _CXA_DEMANGLE_H
+
+#include <cxxabi.h>
+
+#pragma GCC visibility push(hidden)
+
+namespace __cxxabiv1
+{
+
+namespace __libcxxabi
+{
+
+class __demangle_tree;
+class __node;
+
+char*
+__demangle(__demangle_tree, char*, size_t*, int*);
+
+struct __demangle_tree_rv
+{
+ __demangle_tree* ptr_;
+
+ explicit __demangle_tree_rv(__demangle_tree* ptr)
+ : ptr_(ptr) {}
+};
+
+class __demangle_tree
+{
+ const char* __mangled_name_begin_;
+ const char* __mangled_name_end_;
+ int __status_;
+ __node* __root_;
+ __node* __node_begin_;
+ __node* __node_end_;
+ __node* __node_cap_;
+ __node** __sub_begin_;
+ __node** __sub_end_;
+ __node** __sub_cap_;
+ __node** __t_begin_;
+ __node** __t_end_;
+ __node** __t_cap_;
+ bool __tag_templates_;
+ bool __fix_forward_references_;
+ bool __owns_buf_;
+
+ __demangle_tree& operator=(const __demangle_tree&);
+public:
+ __demangle_tree(const char*, char*, size_t);
+ ~__demangle_tree();
+
+ __demangle_tree(__demangle_tree&);
+ __demangle_tree(__demangle_tree_rv);
+ operator __demangle_tree_rv() {return __demangle_tree_rv(this);}
+
+ int __status() const;
+ size_t size() const;
+ char* __get_demangled_name(char*) const;
+
+ void __parse();
+
+private:
+ const char* __parse_encoding(const char*, const char*);
+ const char* __parse_type(const char*, const char*,
+ bool = true, bool = false);
+ const char* __parse_special_name(const char*, const char*);
+ const char* __parse_name(const char*, const char*);
+ const char* __parse_bare_function_type(const char*, const char*);
+ const char* __parse_call_offset(const char*, const char*);
+ const char* __parse_number(const char*, const char*);
+ const char* __parse_cv_qualifiers(const char* first, const char* last,
+ unsigned& cv, bool = false);
+ const char* __parse_nested_name(const char*, const char*);
+ const char* __parse_discriminator(const char*, const char*);
+ const char* __parse_local_name(const char*, const char*);
+ const char* __parse_unscoped_template_name(const char*, const char*);
+ const char* __parse_unscoped_name(const char*, const char*);
+ const char* __parse_operator_name(const char*, const char*, int* = 0);
+ const char* __parse_unqualified_name(const char*, const char*);
+ const char* __parse_source_name(const char*, const char*);
+ const char* __parse_ctor_dtor_name(const char*, const char*);
+ const char* __parse_unnamed_type_name(const char*, const char*);
+ const char* __parse_template_args(const char*, const char*);
+ const char* __parse_template_arg(const char*, const char*);
+ const char* __parse_expression(const char*, const char*);
+ const char* __parse_expr_primary(const char*, const char*);
+ const char* __parse_substitution(const char*, const char*);
+ const char* __parse_builtin_type(const char*, const char*);
+ const char* __parse_function_type(const char*, const char*);
+ const char* __parse_class_enum_type(const char*, const char*);
+ const char* __parse_array_type(const char*, const char*);
+ const char* __parse_pointer_to_member_type(const char*, const char*);
+ const char* __parse_decltype(const char*, const char*);
+ const char* __parse_template_param(const char*, const char*);
+ const char* __parse_unresolved_name(const char*, const char*);
+ const char* __parse_unresolved_type(const char*, const char*);
+ const char* __parse_base_unresolved_name(const char*, const char*);
+ const char* __parse_simple_id(const char*, const char*);
+ const char* __parse_destructor_name(const char*, const char*);
+ const char* __parse_function_param(const char*, const char*);
+ const char* __parse_const_cast_expr(const char*, const char*);
+ const char* __parse_alignof_expr(const char*, const char*);
+ const char* __parse_call_expr(const char*, const char*);
+ const char* __parse_conversion_expr(const char*, const char*);
+ const char* __parse_delete_array_expr(const char*, const char*);
+ const char* __parse_delete_expr(const char*, const char*);
+ const char* __parse_dynamic_cast_expr(const char*, const char*);
+ const char* __parse_dot_star_expr(const char*, const char*);
+ const char* __parse_dot_expr(const char*, const char*);
+ const char* __parse_decrement_expr(const char*, const char*);
+ const char* __parse_new_expr(const char*, const char*);
+ const char* __parse_increment_expr(const char*, const char*);
+ const char* __parse_arrow_expr(const char*, const char*);
+ const char* __parse_reinterpret_cast_expr(const char*, const char*);
+ const char* __parse_static_cast_expr(const char*, const char*);
+ const char* __parse_sizeof_type_expr(const char*, const char*);
+ const char* __parse_sizeof_param_pack_expr(const char*, const char*);
+ const char* __parse_typeid_expr(const char*, const char*);
+ const char* __parse_throw_expr(const char*, const char*);
+ const char* __parse_pack_expansion(const char*, const char*);
+ const char* __parse_sizeof_function_param_pack_expr(const char*, const char*);
+ const char* __parse_dot_suffix(const char*, const char*);
+ const char* __parse_unresolved_qualifier_level(const char*, const char*);
+ const char* __parse_vector_type(const char*, const char*);
+ const char* __parse_hex_number(const char*, const char*, unsigned long long&);
+
+ template <class _Tp> bool __make();
+ template <class _Tp, class _A0> bool __make(_A0 __a0);
+ template <class _Tp, class _A0, class _A1> bool __make(_A0 __a0, _A1 __a1);
+ template <class _Tp, class _A0, class _A1, class _A2>
+ bool __make(_A0 __a0, _A1 __a1, _A2 __a2);
+ template <class _Tp, class _A0, class _A1, class _A2, class _A3>
+ bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3);
+ template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4>
+ bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4);
+ template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4,
+ class _A5>
+ bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4, _A5 __a5);
+
+ friend
+ char*
+ __demangle(__demangle_tree, char*, size_t*, int*);
+
+};
+
+__demangle_tree
+__demangle(const char*);
+
+__demangle_tree
+__demangle(const char*, char*, size_t);
+
+} // __libcxxabi
+} // __cxxabiv1
+
+#pragma GCC visibility pop
+
+
+#endif // _CXA_DEMANGLE_H
diff --git a/system/lib/libcxxabi/include/cxxabi.h b/system/lib/libcxxabi/include/cxxabi.h
new file mode 100644
index 00000000..b08fba0e
--- /dev/null
+++ b/system/lib/libcxxabi/include/cxxabi.h
@@ -0,0 +1,175 @@
+//===--------------------------- cxxabi.h ---------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CXXABI_H
+#define __CXXABI_H
+
+/*
+ * This header provides the interface to the C++ ABI as defined at:
+ * http://www.codesourcery.com/cxx-abi/
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define _LIBCPPABI_VERSION 1001
+#define LIBCXXABI_NORETURN __attribute__((noreturn))
+
+#ifdef __cplusplus
+
+namespace std {
+ class type_info; // forward declaration
+}
+
+
+// runtime routines use C calling conventions, but are in __cxxabiv1 namespace
+namespace __cxxabiv1 {
+ extern "C" {
+
+// 2.4.2 Allocating the Exception Object
+extern void * __cxa_allocate_exception(size_t thrown_size) throw();
+extern void __cxa_free_exception(void * thrown_exception) throw();
+
+// 2.4.3 Throwing the Exception Object
+extern LIBCXXABI_NORETURN void __cxa_throw(void * thrown_exception,
+ std::type_info * tinfo, void (*dest)(void *));
+
+// 2.5.3 Exception Handlers
+extern void * __cxa_get_exception_ptr(void * exceptionObject) throw();
+extern void * __cxa_begin_catch(void * exceptionObject) throw();
+extern void __cxa_end_catch();
+extern std::type_info * __cxa_current_exception_type();
+
+// 2.5.4 Rethrowing Exceptions
+extern LIBCXXABI_NORETURN void __cxa_rethrow();
+
+
+
+// 2.6 Auxiliary Runtime APIs
+extern LIBCXXABI_NORETURN void __cxa_bad_cast(void);
+extern LIBCXXABI_NORETURN void __cxa_bad_typeid(void);
+
+
+
+// 3.2.6 Pure Virtual Function API
+extern LIBCXXABI_NORETURN void __cxa_pure_virtual(void);
+
+// 3.2.7 Deleted Virtual Function API
+extern LIBCXXABI_NORETURN void __cxa_deleted_virtual(void);
+
+// 3.3.2 One-time Construction API
+#ifdef LIBCXXABI_ARMEABI
+extern int __cxa_guard_acquire(uint32_t*);
+extern void __cxa_guard_release(uint32_t*);
+extern void __cxa_guard_abort(uint32_t*);
+#else
+extern int __cxa_guard_acquire(uint64_t*);
+extern void __cxa_guard_release(uint64_t*);
+extern void __cxa_guard_abort(uint64_t*);
+#endif
+
+// 3.3.3 Array Construction and Destruction API
+extern void* __cxa_vec_new(size_t element_count,
+ size_t element_size,
+ size_t padding_size,
+ void (*constructor)(void*),
+ void (*destructor)(void*) );
+
+extern void* __cxa_vec_new2(size_t element_count,
+ size_t element_size,
+ size_t padding_size,
+ void (*constructor)(void*),
+ void (*destructor)(void*),
+ void* (*alloc)(size_t),
+ void (*dealloc)(void*) );
+
+extern void* __cxa_vec_new3(size_t element_count,
+ size_t element_size,
+ size_t padding_size,
+ void (*constructor)(void*),
+ void (*destructor)(void*),
+ void* (*alloc)(size_t),
+ void (*dealloc)(void*, size_t) );
+
+extern void __cxa_vec_ctor(void* array_address,
+ size_t element_count,
+ size_t element_size,
+ void (*constructor)(void*),
+ void (*destructor)(void*) );
+
+
+extern void __cxa_vec_dtor(void* array_address,
+ size_t element_count,
+ size_t element_size,
+ void (*destructor)(void*) );
+
+
+extern void __cxa_vec_cleanup(void* array_address,
+ size_t element_count,
+ size_t element_size,
+ void (*destructor)(void*) );
+
+
+extern void __cxa_vec_delete(void* array_address,
+ size_t element_size,
+ size_t padding_size,
+ void (*destructor)(void*) );
+
+
+extern void __cxa_vec_delete2(void* array_address,
+ size_t element_size,
+ size_t padding_size,
+ void (*destructor)(void*),
+ void (*dealloc)(void*) );
+
+
+extern void __cxa_vec_delete3(void* __array_address,
+ size_t element_size,
+ size_t padding_size,
+ void (*destructor)(void*),
+ void (*dealloc) (void*, size_t));
+
+
+extern void __cxa_vec_cctor(void* dest_array,
+ void* src_array,
+ size_t element_count,
+ size_t element_size,
+ void (*constructor) (void*, void*),
+ void (*destructor)(void*) );
+
+
+// 3.3.5.3 Runtime API
+extern int __cxa_atexit(void (*f)(void*), void* p, void* d);
+extern int __cxa_finalize(void*);
+
+
+// 3.4 Demangler API
+extern char* __cxa_demangle(const char* mangled_name,
+ char* output_buffer,
+ size_t* length,
+ int* status);
+
+// Apple additions to support C++ 0x exception_ptr class
+// These are primitives to wrap a smart pointer around an exception object
+extern void * __cxa_current_primary_exception() throw();
+extern void __cxa_rethrow_primary_exception(void* primary_exception);
+extern void __cxa_increment_exception_refcount(void* primary_exception) throw();
+extern void __cxa_decrement_exception_refcount(void* primary_exception) throw();
+
+// Apple addition to support std::uncaught_exception()
+extern bool __cxa_uncaught_exception() throw();
+
+ } // extern "C"
+} // namespace __cxxabiv1
+
+#endif // __cplusplus
+
+namespace abi = __cxxabiv1;
+
+#endif // __CXXABI_H
diff --git a/system/lib/libcxxabi/lib/buildit b/system/lib/libcxxabi/lib/buildit
new file mode 100755
index 00000000..d1d2acda
--- /dev/null
+++ b/system/lib/libcxxabi/lib/buildit
@@ -0,0 +1,90 @@
+#! /bin/sh
+#
+# Set the $TRIPLE environment variable to your system's triple before
+# running this script. If you set $CXX, that will be used to compile
+# the library. Otherwise we'll use clang++.
+
+set -e
+
+if [ `basename $(pwd)` != "lib" ]
+then
+ echo "current directory must be lib"
+ exit 1
+fi
+
+if [ -z "$CXX" ]
+then
+ CXX=clang++
+fi
+
+if [ -z "$CC" ]
+then
+ CC=clang
+fi
+
+if [ -z $RC_ProjectSourceVersion ]
+then
+ RC_ProjectSourceVersion=1
+fi
+
+EXTRA_FLAGS="-std=c++0x -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 -Wnewline-eof"
+
+case $TRIPLE in
+ *-apple-*)
+ if [ -z $RC_XBS ]
+ then
+ RC_CFLAGS="-arch i386 -arch x86_64"
+ fi
+ SOEXT=dylib
+ if [ -n "$SDKROOT" ]
+ then
+ EXTRA_FLAGS+="-isysroot ${SDKROOT}"
+ CXX=`xcrun -sdk "${SDKROOT}" -find clang++`
+ CC=`xcrun -sdk "${SDKROOT}" -find clang`
+ fi
+ LDSHARED_FLAGS="-o libc++abi.dylib \
+ -dynamiclib -nodefaultlibs \
+ -current_version ${RC_ProjectSourceVersion} \
+ -compatibility_version 1 \
+ -install_name /usr/lib/libc++abi.dylib \
+ -lSystem"
+ ;;
+ *-*-mingw*)
+ # FIXME: removing libgcc and libsupc++ dependencies means porting libcxxrt and LLVM/compiler-rt
+ SOEXT=dll
+ LDSHARED_FLAGS="-o libc++abi.dll \
+ -shared -nodefaultlibs -Wl,--export-all-symbols -Wl,--allow-multiple-definition -Wl,--out-implib,libc++abi.dll.a \
+ -lsupc++ -lpthread -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcr100 -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt"
+ ;;
+ *)
+ RC_CFLAGS="-fPIC"
+ SOEXT=so
+ LDSHARED_FLAGS="-o libc++abi.so.1.0 \
+ -shared -nodefaultlibs -Wl,-soname,libc++abi.so.1 \
+ -lpthread -lrt -lc -lstdc++"
+ ;;
+esac
+
+if [ -z $RC_XBS ]
+then
+ rm -f libc++abi.1.$SOEXT*
+fi
+
+set -x
+
+for FILE in ../src/*.cpp; do
+ $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE
+done
+case $TRIPLE in
+ *-*-mingw*)
+ for FILE in ../src/support/win32/*.cpp; do
+ $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE
+ done
+ ;;
+esac
+$CC *.o $RC_CFLAGS $LDSHARED_FLAGS $EXTRA_FLAGS
+
+if [ -z $RC_XBS ]
+then
+ rm *.o
+fi
diff --git a/system/lib/libcxxabi/readme.txt b/system/lib/libcxxabi/readme.txt
new file mode 100644
index 00000000..0be9a318
--- /dev/null
+++ b/system/lib/libcxxabi/readme.txt
@@ -0,0 +1 @@
+These files are from libcxxabi, svn revision 151132, Feb 22 2012
diff --git a/system/lib/libcxxabi/src/abort_message.cpp b/system/lib/libcxxabi/src/abort_message.cpp
new file mode 100644
index 00000000..7beb86b5
--- /dev/null
+++ b/system/lib/libcxxabi/src/abort_message.cpp
@@ -0,0 +1,60 @@
+//===------------------------- abort_message.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "abort_message.h"
+
+#pragma GCC visibility push(hidden)
+
+#if __APPLE__
+# if defined(__has_include) && __has_include(<CrashReporterClient.h>)
+# define HAVE_CRASHREPORTERCLIENT_H 1
+# include <CrashReporterClient.h>
+
+ // If any clients of llvm try to link to libCrashReporterClient.a themselves,
+ // only one crash info struct will be used.
+ extern "C" {
+ CRASH_REPORTER_CLIENT_HIDDEN
+ struct crashreporter_annotations_t gCRAnnotations
+ __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION)))
+ = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 };
+ }
+
+# endif
+#endif
+
+__attribute__((visibility("hidden"), noreturn))
+void abort_message(const char* format, ...)
+{
+ // write message to stderr
+#if __APPLE__
+ fprintf(stderr, "libc++abi.dylib: ");
+#endif
+ va_list list;
+ va_start(list, format);
+ vfprintf(stderr, format, list);
+ va_end(list);
+ fprintf(stderr, "\n");
+
+#if __APPLE__ && HAVE_CRASHREPORTERCLIENT_H
+ // record message in crash report
+ char* buffer;
+ va_list list2;
+ va_start(list2, format);
+ vasprintf(&buffer, format, list2);
+ va_end(list2);
+ CRSetCrashLogMessage(buffer);
+#endif
+
+ abort();
+}
+
+#pragma GCC visibility pop
diff --git a/system/lib/libcxxabi/src/abort_message.h b/system/lib/libcxxabi/src/abort_message.h
new file mode 100644
index 00000000..2c5cb204
--- /dev/null
+++ b/system/lib/libcxxabi/src/abort_message.h
@@ -0,0 +1,33 @@
+//===-------------------------- abort_message.h-----------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ABORT_MESSAGE_H_
+#define __ABORT_MESSAGE_H_
+
+#include <stdio.h>
+
+#pragma GCC visibility push(hidden)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+__attribute__((visibility("hidden"), noreturn))
+ void abort_message(const char* format, ...)
+ __attribute__((format(printf, 1, 2)));
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma GCC visibility pop
+
+#endif
+
diff --git a/system/lib/libcxxabi/src/cxa_aux_runtime.cpp b/system/lib/libcxxabi/src/cxa_aux_runtime.cpp
new file mode 100644
index 00000000..abd8091c
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_aux_runtime.cpp
@@ -0,0 +1,34 @@
+//===------------------------ cxa_aux_runtime.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the "Auxiliary Runtime APIs"
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html#cxx-aux
+//===----------------------------------------------------------------------===//
+
+#include "cxxabi.h"
+#include <typeinfo>
+
+namespace __cxxabiv1
+{
+
+extern "C"
+{
+
+LIBCXXABI_NORETURN
+void __cxa_bad_cast (void) {
+ throw std::bad_cast();
+}
+
+LIBCXXABI_NORETURN
+void __cxa_bad_typeid(void) {
+ throw std::bad_typeid();
+}
+
+} // extern "C"
+
+} // abi
diff --git a/system/lib/libcxxabi/src/cxa_demangle.cpp b/system/lib/libcxxabi/src/cxa_demangle.cpp
new file mode 100644
index 00000000..1135c99b
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_demangle.cpp
@@ -0,0 +1,10798 @@
+//===-------------------------- cxa_demangle.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxa_demangle.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <new>
+#include <algorithm>
+#include <assert.h>
+
+
+#ifdef DEBUGGING
+
+#include <string>
+#include <typeinfo>
+
+#endif
+
+namespace __cxxabiv1
+{
+
+namespace __libcxxabi
+{
+
+#pragma GCC visibility push(hidden)
+
+class __node
+{
+ __node(const __node&);
+ __node& operator=(const __node&);
+public:
+ const char* __name_;
+ size_t __size_;
+ __node* __left_;
+ __node* __right_;
+ long double __value_;
+ long __cached_size_;
+public:
+ __node()
+ : __name_(0), __size_(0), __left_(0), __right_(0), __cached_size_(-1)
+ {}
+ virtual ~__node() {};
+
+ void reset_cached_size()
+ {
+ __cached_size_ = -1;
+ if (__left_)
+ __left_->reset_cached_size();
+ if (__right_)
+ __right_->reset_cached_size();
+ }
+
+ virtual size_t first_size() const {return 0;}
+ virtual size_t second_size() const {return 0;}
+ virtual size_t size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = first_size() + second_size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const {return buf;}
+ virtual char* second_demangled_name(char* buf) const {return buf;}
+ virtual char* get_demangled_name(char* buf) const
+ {
+ return second_demangled_name(first_demangled_name(buf));
+ }
+ virtual size_t base_size() const {return size();}
+ virtual char* get_base_name(char* buf) const
+ {
+ return get_demangled_name(buf);
+ }
+
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return false;
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return false;
+ }
+ virtual __node* base_name() const
+ {
+ return const_cast<__node*>(this);
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return false;
+ }
+ virtual bool is_function() const
+ {
+ return false;
+ }
+ virtual bool is_cv_qualifer() const
+ {
+ return false;
+ }
+ virtual bool is_array() const
+ {
+ return false;
+ }
+
+ virtual bool fix_forward_references(__node**, __node**)
+ {
+ return true;
+ }
+ virtual __node* extract_cv(__node*&) const
+ {
+ return 0;
+ }
+ virtual size_t list_len() const
+ {
+ return 0;
+ }
+ virtual bool is_sub() const
+ {
+ return false;
+ }
+};
+
+#ifdef DEBUGGING
+
+void display(__node* x, int indent = 0)
+{
+ if (x)
+ {
+ for (int i = 0; i < 2*indent; ++i)
+ printf(" ");
+ std::string buf(x->size(), '\0');
+ x->get_demangled_name(&buf.front());
+ printf("%s %s, %p\n", typeid(*x).name(), buf.c_str(), x);
+ display(x->__left_, indent+1);
+ display(x->__right_, indent+1);
+ }
+}
+
+#endif
+
+class __vtable
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("vtable for ") - 1;
+public:
+ __vtable(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "vtable for ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __VTT
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("VTT for ") - 1;
+public:
+ __VTT(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "VTT for ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __construction_vtable
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("construction vtable for ") - 1 + 4;
+public:
+ __construction_vtable(__node* left, __node* right)
+ {
+ __left_ = left;
+ __right_ = right;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __left_->size()
+ + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "construction vtable for ", n-4);
+ buf = __left_->get_demangled_name(buf+n-4);
+ *buf++ = '-';
+ *buf++ = 'i';
+ *buf++ = 'n';
+ *buf++ = '-';
+ return __right_->get_demangled_name(buf);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = __left_->fix_forward_references(t_begin, t_end);
+ return r && __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __typeinfo
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("typeinfo for ") - 1;
+public:
+ __typeinfo(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "typeinfo for ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __typeinfo_name
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("typeinfo name for ") - 1;
+public:
+ __typeinfo_name(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "typeinfo name for ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __covariant_return_thunk
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("covariant return thunk to ") - 1;
+public:
+ __covariant_return_thunk(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "covariant return thunk to ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __virtual_thunk
+ : public __node
+{
+ static const size_t n = sizeof("virtual thunk to ") - 1;
+public:
+ __virtual_thunk(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "virtual thunk to ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __non_virtual_thunk
+ : public __node
+{
+ static const size_t n = sizeof("non-virtual thunk to ") - 1;
+public:
+ __non_virtual_thunk(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "non-virtual thunk to ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __guard_variable
+ : public __node
+{
+ static const size_t n = sizeof("guard variable for ") - 1;
+public:
+ __guard_variable(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "guard variable for ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __reference_temporary
+ : public __node
+{
+ static const size_t n = sizeof("reference temporary for ") - 1;
+public:
+ __reference_temporary(__node* type)
+ {
+ __right_ = type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "reference temporary for ", n);
+ return __right_->get_demangled_name(buf+n);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __source_name
+ : public __node
+{
+public:
+ __source_name(const char* __name, unsigned __size)
+ {
+ __name_ = __name;
+ __size_ = __size;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0)
+ const_cast<long&>(__cached_size_) = 21;
+ else
+ const_cast<long&>(__cached_size_) = __size_;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0)
+ return strncpy(buf, "(anonymous namespace)", 21) + 21;
+ return strncpy(buf, __name_, __size_) + __size_;
+ }
+};
+
+class __operator_new
+ : public __node
+{
+public:
+
+ virtual size_t first_size() const {return sizeof("operator new") - 1;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ return strncpy(buf, "operator new", sizeof("operator new") - 1) +
+ sizeof("operator new") - 1;
+ }
+};
+
+class __operator_new_array
+ : public __node
+{
+public:
+
+ virtual size_t first_size() const {return sizeof("operator new[]") - 1;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ return strncpy(buf, "operator new[]", sizeof("operator new[]") - 1) +
+ sizeof("operator new[]") - 1;
+ }
+};
+
+class __operator_delete
+ : public __node
+{
+public:
+
+ virtual size_t first_size() const {return sizeof("operator delete") - 1;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ return strncpy(buf, "operator delete", sizeof("operator delete") - 1) +
+ sizeof("operator delete") - 1;
+ }
+};
+
+class __operator_delete_array
+ : public __node
+{
+public:
+
+ virtual size_t first_size() const {return sizeof("operator delete[]") - 1;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ return strncpy(buf, "operator delete[]", sizeof("operator delete[]") - 1) +
+ sizeof("operator delete[]") - 1;
+ }
+};
+
+class __operator_logical_and
+ : public __node
+{
+public:
+
+ __operator_logical_and() {}
+ __operator_logical_and(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator&&") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") && (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator&&", sizeof("operator&&") - 1);
+ buf += sizeof("operator&&") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_addressof
+ : public __node
+{
+public:
+
+ __operator_addressof() {}
+ explicit __operator_addressof(__node* op)
+ {
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 3+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator&") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '&';
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator&", sizeof("operator&") - 1);
+ buf += sizeof("operator&") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_bit_and
+ : public __node
+{
+public:
+
+ __operator_bit_and() {}
+ __operator_bit_and(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator&") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") & (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator&", sizeof("operator&") - 1);
+ buf += sizeof("operator&") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_and_equal
+ : public __node
+{
+public:
+
+ __operator_and_equal() {}
+ __operator_and_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator&=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") &= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator&=", sizeof("operator&=") - 1);
+ buf += sizeof("operator&=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_equal
+ : public __node
+{
+public:
+
+ __operator_equal() {}
+ __operator_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") = (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator=", sizeof("operator=") - 1);
+ buf += sizeof("operator=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_alignof_type
+ : public __node
+{
+public:
+
+ __operator_alignof_type() {}
+ __operator_alignof_type(__node* op)
+ {
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__right_)
+ const_cast<long&>(__cached_size_) = __right_->size() + 10;
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__right_)
+ {
+ strncpy(buf, "alignof (", 9);
+ buf += 9;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator alignof", sizeof("operator alignof") - 1);
+ buf += sizeof("operator alignof") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__right_)
+ return __right_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_alignof_expression
+ : public __node
+{
+public:
+
+ __operator_alignof_expression() {}
+ __operator_alignof_expression(__node* op)
+ {
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__right_)
+ const_cast<long&>(__cached_size_) = __right_->size() + 10;
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__right_)
+ {
+ strncpy(buf, "alignof (", 9);
+ buf += 9;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator alignof", sizeof("operator alignof") - 1);
+ buf += sizeof("operator alignof") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__right_)
+ return __right_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_paren
+ : public __node
+{
+public:
+
+ virtual size_t first_size() const {return sizeof("operator()") - 1;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "operator()", sizeof("operator()") - 1);
+ return buf + sizeof("operator()") - 1;
+ }
+};
+
+class __operator_comma
+ : public __node
+{
+public:
+
+ __operator_comma() {}
+ __operator_comma(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator,") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") , (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator,", sizeof("operator,") - 1);
+ buf += sizeof("operator,") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_tilda
+ : public __node
+{
+public:
+
+ __operator_tilda() {}
+ explicit __operator_tilda(__node* op)
+ {
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 3+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator~") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '~';
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator~", sizeof("operator~") - 1);
+ buf += sizeof("operator~") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_cast
+ : public __node
+{
+ static const size_t n = sizeof("operator ") - 1;
+public:
+
+ explicit __operator_cast(__node* type)
+ {
+ __right_ = type;
+ }
+ __operator_cast(__node* type, __node* arg)
+ {
+ __size_ = 1;
+ __right_ = type;
+ __left_ = arg;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t off;
+ if (__size_)
+ {
+ off = 4;
+ off += __right_->size();
+ if (__left_)
+ off += __left_->size();
+ }
+ else
+ off = n + __right_->size();;
+ const_cast<long&>(__cached_size_) = off;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_)
+ {
+ *buf++ = '(';
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ *buf++ = '(';
+ if (__left_)
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator ", n);
+ buf = __right_->get_demangled_name(buf+n);
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return true;
+ }
+};
+
+class __cast_literal
+ : public __node
+{
+public:
+
+ __cast_literal(__node* type, const char* f, const char* l)
+ {
+ __left_ = type;
+ __name_ = f;
+ __size_ = l - f;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = 2 + __left_->size() + __size_;
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ strncpy(buf, __name_, __size_);
+ return buf + __size_;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __operator_dereference
+ : public __node
+{
+public:
+
+ __operator_dereference() {}
+ explicit __operator_dereference(__node* op)
+ {
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 3+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator*") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '*';
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator*", sizeof("operator*") - 1);
+ buf += sizeof("operator*") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_divide
+ : public __node
+{
+public:
+
+ __operator_divide() {}
+ __operator_divide(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator/") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") / (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator/", sizeof("operator/") - 1);
+ buf += sizeof("operator/") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_divide_equal
+ : public __node
+{
+public:
+
+ __operator_divide_equal() {}
+ __operator_divide_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator/=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") /= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator/=", sizeof("operator/=") - 1);
+ buf += sizeof("operator/=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_xor
+ : public __node
+{
+public:
+
+ __operator_xor() {}
+ __operator_xor(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator^") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") ^ (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator^", sizeof("operator^") - 1);
+ buf += sizeof("operator^") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_xor_equal
+ : public __node
+{
+public:
+
+ __operator_xor_equal() {}
+ __operator_xor_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator^=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '('; // strncpy(buf, "(", 1);
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") ^= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator^=", sizeof("operator^=") - 1);
+ buf += sizeof("operator^=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_equality
+ : public __node
+{
+public:
+
+ __operator_equality() {}
+ __operator_equality(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator==") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") == (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator==", sizeof("operator==") - 1);
+ buf += sizeof("operator==") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_greater_equal
+ : public __node
+{
+public:
+
+ __operator_greater_equal() {}
+ __operator_greater_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator>=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") >= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator>=", sizeof("operator>=") - 1);
+ buf += sizeof("operator>=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_greater
+ : public __node
+{
+public:
+
+ __operator_greater() {}
+ __operator_greater(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator>") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") > (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator>", sizeof("operator>") - 1);
+ buf += sizeof("operator>") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_brackets
+ : public __node
+{
+public:
+
+ virtual size_t first_size() const {return sizeof("operator[]") - 1;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "operator[]", sizeof("operator[]") - 1);
+ return buf + sizeof("operator[]") - 1;
+ }
+};
+
+class __operator_less_equal
+ : public __node
+{
+public:
+
+ __operator_less_equal() {}
+ __operator_less_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator<=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") <= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator<=", sizeof("operator<=") - 1);
+ buf += sizeof("operator<=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_less
+ : public __node
+{
+public:
+
+ __operator_less() {}
+ __operator_less(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator<") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") < (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator<", sizeof("operator<") - 1);
+ buf += sizeof("operator<") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_left_shift
+ : public __node
+{
+public:
+
+ __operator_left_shift() {}
+ __operator_left_shift(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator<<") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") << (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator<<", sizeof("operator<<") - 1);
+ buf += sizeof("operator<<") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_left_shift_equal
+ : public __node
+{
+public:
+
+ __operator_left_shift_equal() {}
+ __operator_left_shift_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator<<=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") <<= (", 7);
+ buf += 7;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator<<=", sizeof("operator<<=") - 1);
+ buf += sizeof("operator<<=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_minus
+ : public __node
+{
+public:
+
+ __operator_minus() {}
+ __operator_minus(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator-") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") - (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator-", sizeof("operator-") - 1);
+ buf += sizeof("operator-") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_minus_equal
+ : public __node
+{
+public:
+
+ __operator_minus_equal() {}
+ __operator_minus_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator-=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") -= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator-=", sizeof("operator-=") - 1);
+ buf += sizeof("operator-=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_times
+ : public __node
+{
+public:
+
+ __operator_times() {}
+ __operator_times(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator*") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") * (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator*", sizeof("operator*") - 1);
+ buf += sizeof("operator*") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_times_equal
+ : public __node
+{
+public:
+
+ __operator_times_equal() {}
+ __operator_times_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator*=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") *= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator*=", sizeof("operator*=") - 1);
+ buf += sizeof("operator*=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_decrement
+ : public __node
+{
+public:
+
+ __operator_decrement() {}
+ explicit __operator_decrement(bool prefix, __node* op)
+ {
+ __size_ = prefix;
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 4+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator--") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ if (__size_)
+ {
+ *buf++ = '-';
+ *buf++ = '-';
+ *buf++ = '(';
+ }
+ else
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ if (__size_)
+ *buf++ = ')';
+ else
+ {
+ *buf++ = ')';
+ *buf++ = '-';
+ *buf++ = '-';
+ }
+ }
+ else
+ {
+ strncpy(buf, "operator--", sizeof("operator--") - 1);
+ buf += sizeof("operator--") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_not_equal
+ : public __node
+{
+public:
+
+ __operator_not_equal() {}
+ __operator_not_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator!=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") != (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator!=", sizeof("operator!=") - 1);
+ buf += sizeof("operator!=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_negate
+ : public __node
+{
+public:
+
+ __operator_negate() {}
+ explicit __operator_negate(__node* op)
+ {
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 3+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator-") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '-';
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator-", sizeof("operator-") - 1);
+ buf += sizeof("operator-") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_logical_not
+ : public __node
+{
+public:
+
+ __operator_logical_not() {}
+ explicit __operator_logical_not(__node* op)
+ {
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 3+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator!") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '!';
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator!", sizeof("operator!") - 1);
+ buf += sizeof("operator!") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_logical_or
+ : public __node
+{
+public:
+
+ __operator_logical_or() {}
+ __operator_logical_or(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator||") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") || (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator||", sizeof("operator||") - 1);
+ buf += sizeof("operator||") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_bit_or
+ : public __node
+{
+public:
+
+ __operator_bit_or() {}
+ __operator_bit_or(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator|") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") | (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator|", sizeof("operator|") - 1);
+ buf += sizeof("operator|") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_or_equal
+ : public __node
+{
+public:
+
+ __operator_or_equal() {}
+ __operator_or_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator|=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") |= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator|=", sizeof("operator|=") - 1);
+ buf += sizeof("operator|=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_pointer_to_member
+ : public __node
+{
+public:
+
+ __operator_pointer_to_member() {}
+ __operator_pointer_to_member(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator->*") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") ->* (", 7);
+ buf += 7;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator->*", sizeof("operator->*") - 1);
+ buf += sizeof("operator->*") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_plus
+ : public __node
+{
+public:
+
+ __operator_plus() {}
+ __operator_plus(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator+") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") + (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator+", sizeof("operator+") - 1);
+ buf += sizeof("operator+") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_plus_equal
+ : public __node
+{
+public:
+
+ __operator_plus_equal() {}
+ __operator_plus_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator+=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") += (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator+=", sizeof("operator+=") - 1);
+ buf += sizeof("operator+=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_increment
+ : public __node
+{
+public:
+
+ __operator_increment() {}
+ explicit __operator_increment(bool prefix, __node* op)
+ {
+ __size_ = prefix;
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 4+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator++") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ if (__size_)
+ {
+ *buf++ = '+';
+ *buf++ = '+';
+ *buf++ = '(';
+ }
+ else
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ if (__size_)
+ *buf++ = ')';
+ else
+ {
+ *buf++ = ')';
+ *buf++ = '+';
+ *buf++ = '+';
+ }
+ }
+ else
+ {
+ strncpy(buf, "operator++", sizeof("operator++") - 1);
+ buf += sizeof("operator++") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_unary_plus
+ : public __node
+{
+public:
+
+ __operator_unary_plus() {}
+ explicit __operator_unary_plus(__node* op)
+ {
+ __left_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = 3+__left_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator+") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '+';
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator+", sizeof("operator+") - 1);
+ buf += sizeof("operator+") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_)
+ return __left_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_arrow
+ : public __node
+{
+public:
+
+ __operator_arrow() {}
+ __operator_arrow(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator->") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") -> (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator->", sizeof("operator->") - 1);
+ buf += sizeof("operator->") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_conditional
+ : public __node
+{
+public:
+
+ __operator_conditional() {}
+ __operator_conditional(__node* op1, __node* op2, __node* op3)
+ {
+ __name_ = (const char*)op1;
+ __left_ = op2;
+ __right_ = op3;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ {
+ __node* op1 = (__node*)__name_;
+ const_cast<long&>(__cached_size_) = op1->size() + __left_->size() + 12 + __right_->size();
+ }
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator?") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ __node* op1 = (__node*)__name_;
+ *buf++ = '(';
+ buf = op1->get_demangled_name(buf);
+ strncpy(buf, ") ? (", 5);
+ buf += 5;
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") : (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator?", sizeof("operator?") - 1);
+ buf += sizeof("operator?") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__name_)
+ r = r && ((__node*)__name_)->fix_forward_references(t_begin, t_end);
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_mod
+ : public __node
+{
+public:
+
+ __operator_mod() {}
+ __operator_mod(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator%") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") % (", 5);
+ buf += 5;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator%", sizeof("operator%") - 1);
+ buf += sizeof("operator%") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_mod_equal
+ : public __node
+{
+public:
+
+ __operator_mod_equal() {}
+ __operator_mod_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator%=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") %= (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator%=", sizeof("operator%=") - 1);
+ buf += sizeof("operator%=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_right_shift
+ : public __node
+{
+public:
+
+ __operator_right_shift() {}
+ __operator_right_shift(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator>>") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") >> (", 6);
+ buf += 6;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator>>", sizeof("operator>>") - 1);
+ buf += sizeof("operator>>") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_right_shift_equal
+ : public __node
+{
+public:
+
+ __operator_right_shift_equal() {}
+ __operator_right_shift_equal(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_)
+ const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size();
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator>>=") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, ") >>= (", 7);
+ buf += 7;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator>>=", sizeof("operator>>=") - 1);
+ buf += sizeof("operator>>=") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __operator_sizeof_type
+ : public __node
+{
+public:
+
+ __operator_sizeof_type() {}
+ __operator_sizeof_type(__node* op)
+ {
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__right_)
+ const_cast<long&>(__cached_size_) = __right_->size() + 9;
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__right_)
+ {
+ strncpy(buf, "sizeof (", 8);
+ buf += 8;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1);
+ buf += sizeof("operator sizeof") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__right_)
+ return __right_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __operator_sizeof_expression
+ : public __node
+{
+public:
+
+ __operator_sizeof_expression() {}
+ __operator_sizeof_expression(__node* op)
+ {
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__right_)
+ const_cast<long&>(__cached_size_) = __right_->size() + 9;
+ else
+ const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__right_)
+ {
+ strncpy(buf, "sizeof (", 8);
+ buf += 8;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ else
+ {
+ strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1);
+ buf += sizeof("operator sizeof") - 1;
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__right_)
+ return __right_->fix_forward_references(t_begin, t_end);
+ return true;
+ }
+};
+
+class __typeid
+ : public __node
+{
+public:
+
+ __typeid(__node* op)
+ {
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __right_->size() + 8;
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "typeid(", 7);
+ buf += 7;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __throw
+ : public __node
+{
+public:
+
+ __throw(__node* op)
+ {
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __right_->size() + 6;
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "throw ", 6);
+ return __right_->get_demangled_name(buf+6);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __rethrow
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("throw") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "throw", n);
+ return buf+n;
+ }
+};
+
+class __operator_sizeof_param_pack
+ : public __node
+{
+public:
+
+ __operator_sizeof_param_pack(__node* op)
+ {
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __right_->size() + 11;
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "sizeof...(", 10);
+ buf += 10;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __const_cast
+ : public __node
+{
+public:
+
+ __const_cast(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 14 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "const_cast<", 11);
+ buf += 11;
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '>';
+ *buf++ = '(';
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __dynamic_cast
+ : public __node
+{
+public:
+
+ __dynamic_cast(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 16 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "dynamic_cast<", 13);
+ buf += 13;
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '>';
+ *buf++ = '(';
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __reinterpret_cast
+ : public __node
+{
+public:
+
+ __reinterpret_cast(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 20 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "reinterpret_cast<", 17);
+ buf += 17;
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '>';
+ *buf++ = '(';
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __static_cast
+ : public __node
+{
+public:
+
+ __static_cast(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 15 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "static_cast<", 12);
+ buf += 12;
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '>';
+ *buf++ = '(';
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __call_expr
+ : public __node
+{
+public:
+
+ __call_expr(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t off = __left_->size() + 2;
+ if (__right_)
+ off += __right_->size();
+ const_cast<long&>(__cached_size_) = off;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '(';
+ if (__right_)
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __delete_array_expr
+ : public __node
+{
+public:
+
+ __delete_array_expr(bool global, __node* op)
+ {
+ __size_ = global;
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = (__size_ ? 2 : 0) + 9 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_)
+ {
+ *buf++ = ':';
+ *buf++ = ':';
+ }
+ strncpy(buf, "delete[] ", 9);
+ return __right_->get_demangled_name(buf+9);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __delete_expr
+ : public __node
+{
+public:
+
+ __delete_expr(bool global, __node* op)
+ {
+ __size_ = global;
+ __right_ = op;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = (__size_ ? 2 : 0) + 7 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_)
+ {
+ *buf++ = ':';
+ *buf++ = ':';
+ }
+ strncpy(buf, "delete ", 7);
+ return __right_->get_demangled_name(buf+7);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __new_expr
+ : public __node
+{
+public:
+
+ __new_expr(bool global, bool is_array, bool has_init,
+ __node* expr, __node* type, __node* init)
+ {
+ __size_ = (unsigned)global |
+ ((unsigned)is_array << 1) |
+ ((unsigned)has_init << 2);
+ __left_ = expr;
+ __name_ = (const char*)type;
+ __right_ = init;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t off = 4;
+ if (__size_ & 1)
+ off += 2;
+ if (__size_ & 2)
+ off += 2;
+ if (__left_)
+ {
+ off += 2;
+ off += __left_->size();
+ }
+ __node* type = (__node*)__name_;
+ off += type->size();
+ if (__size_ & 4)
+ {
+ off += 2;
+ if (__right_)
+ off += __right_->size();
+ }
+ const_cast<long&>(__cached_size_) = off;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_ & 1)
+ {
+ *buf++ = ':';
+ *buf++ = ':';
+ }
+ *buf++ = 'n';
+ *buf++ = 'e';
+ *buf++ = 'w';
+ if (__size_ & 2)
+ {
+ *buf++ = '[';
+ *buf++ = ']';
+ }
+ if (__left_)
+ {
+ *buf++ = '(';
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ *buf++ = ' ';
+ __node* type = (__node*)__name_;
+ buf = type->get_demangled_name(buf);
+ if (__size_ & 4)
+ {
+ *buf++ = '(';
+ if (__right_)
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ __node* type = (__node*)__name_;
+ bool r = type->fix_forward_references(t_begin, t_end);
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);;
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);;
+ return r;
+ }
+};
+
+class __dot_star_expr
+ : public __node
+{
+public:
+
+ __dot_star_expr(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 2 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '.';
+ *buf++ = '*';
+ return __right_->get_demangled_name(buf);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __dot_expr
+ : public __node
+{
+public:
+
+ __dot_expr(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 1 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '.';
+ return __right_->get_demangled_name(buf);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __arrow_expr
+ : public __node
+{
+public:
+
+ __arrow_expr(__node* op1, __node* op2)
+ {
+ __left_ = op1;
+ __right_ = op2;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 2 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '-';
+ *buf++ = '>';
+ return __right_->get_demangled_name(buf);
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __std_qualified_name
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("std") - 1;
+public:
+
+ __std_qualified_name()
+ {
+ }
+ virtual size_t first_size() const
+ {
+ return n;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ *buf++ = 's';
+ *buf++ = 't';
+ *buf++ = 'd';
+ return buf;
+ }
+};
+
+class __sub_allocator
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("std::allocator") - 1;
+public:
+
+ virtual size_t first_size() const
+ {
+ return n;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "std::allocator", n);
+ return buf + n;
+ }
+};
+
+class __sub_basic_string
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("std::basic_string") - 1;
+public:
+
+ virtual size_t first_size() const
+ {
+ return n;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "std::basic_string", n);
+ return buf + n;
+ }
+};
+
+class __sub_string
+ : public __node
+{
+ static const size_t n = sizeof("std::string") - 1;
+ static const size_t ne = sizeof("std::basic_string<char, std::char_traits<char>, std::allocator<char> >") - 1;
+public:
+
+ virtual size_t first_size() const
+ {
+ if (__size_)
+ return ne;
+ return n;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_)
+ {
+ strncpy(buf, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >", ne);
+ buf += ne;
+ }
+ else
+ {
+ strncpy(buf, "std::string", n);
+ buf += n;
+ }
+ return buf;
+ }
+
+ virtual size_t base_size() const
+ {
+ return 12;
+ }
+ virtual char* get_base_name(char* buf) const
+ {
+ strncpy(buf, "basic_string", 12);
+ return buf + 12;
+ }
+
+ virtual __node* base_name() const
+ {
+ const_cast<size_t&>(__size_) = true;
+ return const_cast<__node*>(static_cast<const __node*>(this));
+ }
+};
+
+class __sub_istream
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("std::istream") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "std::istream", n);
+ return buf + n;
+ }
+};
+
+class __sub_ostream
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("std::ostream") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "std::ostream", n);
+ return buf + n;
+ }
+};
+
+class __sub_iostream
+ : public __node
+{
+ static const ptrdiff_t n = sizeof("std::iostream") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "std::iostream", n);
+ return buf + n;
+ }
+};
+
+class __sub
+ : public __node
+{
+public:
+
+ explicit __sub(__node* arg)
+ {
+ __left_ = arg;
+ }
+ explicit __sub(size_t arg)
+ {
+ __size_ = arg;
+ }
+ virtual size_t first_size() const
+ {
+ return __left_->first_size();
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ return __left_->first_demangled_name(buf);
+ }
+ virtual size_t second_size() const
+ {
+ return __left_->second_size();
+ }
+ virtual char* second_demangled_name(char* buf) const
+ {
+ return __left_->second_demangled_name(buf);
+ }
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return __left_->ends_with_template(parsing);
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return __left_->is_reference_or_pointer_to_function_or_array();
+ }
+ virtual bool is_function() const
+ {
+ return __left_->is_function();
+ }
+ virtual bool is_cv_qualifer() const
+ {
+ return __left_->is_cv_qualifer();
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return __left_->is_ctor_dtor_conv();
+ }
+ virtual bool is_array() const
+ {
+ return __left_->is_array();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ if (__left_ == 0)
+ {
+ if (__size_ < t_end - t_begin)
+ {
+ __left_ = t_begin[__size_];
+ __size_ = 0;
+ }
+ else
+ return false;
+ }
+ return true;
+ }
+ virtual size_t list_len() const
+ {
+ return __left_->list_len();
+ }
+ virtual bool is_sub() const
+ {
+ return true;
+ }
+};
+
+class __unscoped_template_name
+ : public __node
+{
+public:
+ __unscoped_template_name(__node* name, __node* args)
+ {__left_ = name; __right_ = args;}
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ return __right_->get_demangled_name(buf);
+ }
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return __right_->ends_with_template(parsing);
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+// length == 0: __left_ == NULL
+// length == 1: __left_ != NULL, __right_ == NULL
+// length > 1: __left_ != NULL, __right_ != NULL
+class __list
+ : public __node
+{
+public:
+ explicit __list(__node* type)
+ {__left_ = type;}
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ if (__left_ == NULL)
+ const_cast<long&>(__cached_size_) = 0;
+ else if (__right_ == NULL)
+ const_cast<long&>(__cached_size_) = __left_->size();
+ else
+ {
+ size_t off = __right_->size();
+ if (off > 0)
+ off += 2;
+ const_cast<long&>(__cached_size_) = __left_->size() + off;
+ }
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_ != NULL)
+ {
+ char* t = __left_->get_demangled_name(buf + (__size_ ? 2 : 0));
+ if (__size_ == 0)
+ buf = t;
+ else if (t != buf+2)
+ {
+ *buf++ = ',';
+ *buf++ = ' ';
+ buf = t;
+ }
+ if (__right_)
+ buf = __right_->get_demangled_name(buf);
+ }
+ return buf;
+ }
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ if (__right_ != NULL)
+ return __right_->ends_with_template(parsing);
+ if (__left_ != NULL)
+ return __left_->ends_with_template(parsing);
+ return false;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+ virtual size_t list_len() const
+ {
+ if (!__left_)
+ return 0;
+ if (!__right_)
+ return 1;
+ return 1 + __right_->list_len();
+ }
+};
+
+class __template_args
+ : public __node
+{
+public:
+ __template_args(__node* name, __node* list)
+ {
+ __left_ = name;
+ __right_ = list;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t off = 2;
+ if (__right_)
+ {
+ if (__right_->ends_with_template())
+ ++off;
+ off += __right_->size();
+ }
+ const_cast<long&>(__cached_size_) = __left_->size() + off;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = '<';
+ if (__right_)
+ {
+ buf = __right_->get_demangled_name(buf);
+ if (buf[-1] == '>')
+ *buf++ = ' ';
+ }
+ *buf++ = '>';
+ return buf;
+ }
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return true;
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return __left_->is_ctor_dtor_conv();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __function_args
+ : public __node
+{
+public:
+ __function_args(__node* list)
+ {__right_ = list;}
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = 2 + __right_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ *buf++ = '(';
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __cv_qualifiers
+ : public __node
+{
+public:
+ __cv_qualifiers(size_t cv, __node* type)
+ {
+ __left_ = type;
+ __size_ = __left_->is_function() ? cv << 5 : cv;
+ }
+
+ virtual size_t first_size() const
+ {
+ size_t s = __left_->first_size();
+ if (__size_ & 4)
+ s += sizeof(" restrict")-1;
+ if (__size_ & 2)
+ s += sizeof(" volatile")-1;
+ if (__size_ & 1)
+ s += sizeof(" const")-1;
+ if (__size_ & 8)
+ s += sizeof(" &")-1;
+ if (__size_ & 16)
+ s += sizeof(" &&")-1;
+ return s;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->first_demangled_name(buf);
+ if (__size_ & 1)
+ {
+ const size_t n = sizeof(" const")-1;
+ strncpy(buf, " const", n);
+ buf += n;
+ }
+ if (__size_ & 2)
+ {
+ const size_t n = sizeof(" volatile")-1;
+ strncpy(buf, " volatile", n);
+ buf += n;
+ }
+ if (__size_ & 4)
+ {
+ const size_t n = sizeof(" restrict")-1;
+ strncpy(buf, " restrict", n);
+ buf += n;
+ }
+ if (__size_ & 8)
+ {
+ *buf++ = ' ';
+ *buf++ = '&';
+ }
+ if (__size_ & 16)
+ {
+ *buf++ = ' ';
+ *buf++ = '&';
+ *buf++ = '&';
+ }
+ return buf;
+ }
+ virtual size_t second_size() const
+ {
+ size_t s = __left_->second_size();
+ if (__size_ & 128)
+ s += sizeof(" restrict")-1;
+ if (__size_ & 64)
+ s += sizeof(" volatile")-1;
+ if (__size_ & 32)
+ s += sizeof(" const")-1;
+ if (__size_ & 256)
+ s += sizeof(" &")-1;
+ if (__size_ & 512)
+ s += sizeof(" &&")-1;
+ return s;
+ }
+ virtual char* second_demangled_name(char* buf) const
+ {
+ buf = __left_->second_demangled_name(buf);
+ if (__size_ & 32)
+ {
+ const size_t n = sizeof(" const")-1;
+ strncpy(buf, " const", n);
+ buf += n;
+ }
+ if (__size_ & 64)
+ {
+ const size_t n = sizeof(" volatile")-1;
+ strncpy(buf, " volatile", n);
+ buf += n;
+ }
+ if (__size_ & 128)
+ {
+ const size_t n = sizeof(" restrict")-1;
+ strncpy(buf, " restrict", n);
+ buf += n;
+ }
+ if (__size_ & 256)
+ {
+ *buf++ = ' ';
+ *buf++ = '&';
+ }
+ if (__size_ & 512)
+ {
+ *buf++ = ' ';
+ *buf++ = '&';
+ *buf++ = '&';
+ }
+ return buf;
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return __left_->is_reference_or_pointer_to_function_or_array();
+ }
+ virtual bool is_function() const
+ {
+ return __left_->is_function();
+ }
+ virtual bool is_cv_qualifer() const
+ {
+ return true;
+ }
+ virtual __node* extract_cv(__node*& rt) const
+ {
+ if (rt == this)
+ {
+ rt = __left_;
+ return const_cast<__node*>(static_cast<const __node*>(this));
+ }
+ return 0;
+ }
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ if (parsing)
+ return __left_->ends_with_template(parsing);
+ return false;
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return __left_->is_ctor_dtor_conv();
+ }
+ virtual bool is_array() const
+ {
+ return __left_->is_array();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+ virtual size_t list_len() const
+ {
+ return __left_->list_len();
+ }
+};
+
+class __extended_qualifier
+ : public __node
+{
+public:
+ __extended_qualifier(__node* name, __node* type)
+ {
+ __left_ = type;
+ __right_ = name;
+ __size_ = __left_->is_function() ? 1 : 0;
+ }
+
+ virtual size_t first_size() const
+ {
+ size_t s = __left_->first_size();
+ if (__size_ == 0)
+ s += __right_->size() + 1;
+ return s;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->first_demangled_name(buf);
+ if (__size_ == 0)
+ {
+ *buf++ = ' ';
+ buf = __right_->get_demangled_name(buf);
+ }
+ return buf;
+ }
+ virtual size_t second_size() const
+ {
+ size_t s = __left_->second_size();
+ if (__size_ == 1)
+ s += __right_->size() + 1;
+ return s;
+ }
+ virtual char* second_demangled_name(char* buf) const
+ {
+ buf = __left_->second_demangled_name(buf);
+ if (__size_ == 1)
+ {
+ *buf++ = ' ';
+ buf = __right_->get_demangled_name(buf);
+ }
+ return buf;
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return __left_->is_reference_or_pointer_to_function_or_array();
+ }
+ virtual bool is_function() const
+ {
+ return __left_->is_function();
+ }
+ virtual bool is_cv_qualifer() const
+ {
+ return true;
+ }
+ virtual __node* extract_cv(__node*& rt) const
+ {
+ if (rt == this)
+ {
+ rt = __left_;
+ return const_cast<__node*>(static_cast<const __node*>(this));
+ }
+ return 0;
+ }
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return __left_->ends_with_template(parsing);
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return __left_->is_ctor_dtor_conv();
+ }
+ virtual bool is_array() const
+ {
+ return __left_->is_array();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+ virtual size_t list_len() const
+ {
+ return __left_->list_len();
+ }
+};
+
+class __function
+ : public __node
+{
+public:
+
+ __function(__node* name, __node* signature, size_t ret_goes_first = true)
+ {
+ __size_ = ret_goes_first;
+ __left_ = name;
+ __right_ = signature;
+ }
+
+ virtual size_t first_size() const
+ {
+ size_t off = 0;
+ if (__size_)
+ {
+ off = __right_->first_size();
+ if (off > 0 && (__left_ == NULL ||
+ !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
+ ++off;
+ }
+ else
+ off = 5;
+ if (__left_)
+ off += __left_->first_size();
+ else
+ ++off;
+ return off;
+ }
+
+ virtual size_t second_size() const
+ {
+ size_t off = 0;
+ if (__left_ == NULL)
+ off = 1;
+ off += __right_->second_size();
+ if (!__size_)
+ {
+ off += 2;
+ off += __right_->first_size();
+ }
+ return off;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_)
+ {
+ const char* t = buf;
+ buf = __right_->first_demangled_name(buf);
+ if (buf != t && (__left_ == NULL ||
+ !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
+ *buf++ = ' ';
+ }
+ else
+ {
+ strncpy(buf, "auto ", 5);
+ buf += 5;
+ }
+ if (__left_)
+ buf = __left_->first_demangled_name(buf);
+ else
+ *buf++ = '(';
+ return buf;
+ }
+ virtual char* second_demangled_name(char* buf) const
+ {
+ if (__left_ == NULL)
+ *buf++ = ')';
+ buf = __right_->second_demangled_name(buf);
+ if (!__size_)
+ {
+ *buf++ = '-';
+ *buf++ = '>';
+ buf = __right_->first_demangled_name(buf);
+ }
+ return buf;
+ }
+ virtual char* get_demangled_name(char* buf) const
+ {
+ if (__size_)
+ {
+ const char* t = buf;
+ buf = __right_->first_demangled_name(buf);
+ if (buf != t && (__left_ == NULL ||
+ !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
+ *buf++ = ' ';
+ }
+ else
+ {
+ strncpy(buf, "auto ", 5);
+ buf += 5;
+ }
+ if (__left_)
+ buf = __left_->first_demangled_name(buf);
+ buf = __right_->second_demangled_name(buf);
+ if (!__size_)
+ {
+ *buf++ = '-';
+ *buf++ = '>';
+ buf = __right_->first_demangled_name(buf);
+ }
+ return buf;
+ }
+
+ virtual size_t size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t off = 0;
+ if (__size_)
+ {
+ off = __right_->first_size();
+ if (off > 0 && (__left_ == NULL ||
+ !__right_->__left_->is_reference_or_pointer_to_function_or_array()))
+ ++off;
+ }
+ else
+ off = 5;
+ if (__left_)
+ off += __left_->first_size();
+ off += __right_->second_size();
+ if (!__size_)
+ {
+ off += 2;
+ off += __right_->first_size();
+ }
+ const_cast<long&>(__cached_size_) = off;
+ }
+ return __cached_size_;
+ }
+
+ virtual bool is_function() const
+ {
+ return true;
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return __left_->is_ctor_dtor_conv();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __function_signature
+ : public __node
+{
+public:
+ __function_signature(__node* ret, __node* args)
+ {
+ __left_ = ret;
+ __right_ = args;
+ }
+ virtual size_t first_size() const
+ {
+ return __left_ ? __left_->first_size() : 0;
+ }
+
+ virtual size_t second_size() const
+ {
+ return 2 + (__right_ ? __right_->size() : 0)
+ + (__left_ ? __left_->second_size() : 0);
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ buf = __left_->first_demangled_name(buf);
+ return buf;
+ }
+
+ virtual char* second_demangled_name(char* buf) const
+ {
+ *buf++ = '(';
+ if (__right_)
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ if (__left_)
+ buf = __left_->second_demangled_name(buf);
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = r && __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __pointer_to
+ : public __node
+{
+public:
+
+ explicit __pointer_to(__node* type)
+ {
+ __left_ = type;
+ }
+ virtual size_t first_size() const
+ {
+ return __left_->first_size() + (__left_->is_array() ? 3 : 1);
+ }
+ virtual size_t second_size() const
+ {
+ return __left_->second_size() + (__left_->is_array() ? 1 : 0);
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->first_demangled_name(buf);
+ if (__left_->is_array())
+ {
+ *buf++ = ' ';
+ *buf++ = '(';
+ *buf++ = '*';
+ }
+ else
+ *buf++ = '*';
+ return buf;
+ }
+ virtual char* second_demangled_name(char* buf) const
+ {
+ if (__left_->is_array())
+ *buf++ = ')';
+ return __left_->second_demangled_name(buf);
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return __left_->is_function() ||
+ __left_->is_reference_or_pointer_to_function_or_array();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+ virtual size_t list_len() const
+ {
+ return __left_->list_len();
+ }
+};
+
+class __lvalue_reference_to
+ : public __node
+{
+public:
+
+ explicit __lvalue_reference_to(__node* type)
+ {
+ __left_ = type;
+ }
+ virtual size_t first_size() const
+ {
+ return __left_->first_size() + (__left_->is_array() ? 3 : 1);
+ }
+ virtual size_t second_size() const
+ {
+ return __left_->second_size() + (__left_->is_array() ? 1 : 0);
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->first_demangled_name(buf);
+ if (__left_->is_array())
+ {
+ *buf++ = ' ';
+ *buf++ = '(';
+ *buf++ = '&';
+ }
+ else
+ *buf++ = '&';
+ return buf;
+ }
+ virtual char* second_demangled_name(char* buf) const
+ {
+ if (__left_->is_array())
+ *buf++ = ')';
+ return __left_->second_demangled_name(buf);
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return __left_->is_function();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+ virtual size_t list_len() const
+ {
+ return __left_->list_len();
+ }
+};
+
+class __rvalue_reference_to
+ : public __node
+{
+public:
+
+ explicit __rvalue_reference_to(__node* type)
+ {
+ __left_ = type;
+ }
+ virtual size_t first_size() const
+ {
+ return __left_->first_size() + (__left_->is_array() ? 4 : 2);
+ }
+ virtual size_t second_size() const
+ {
+ return __left_->second_size() + (__left_->is_array() ? 1 : 0);
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->first_demangled_name(buf);
+ if (__left_->is_array())
+ {
+ strncpy(buf, " (&&", 4);
+ buf += 4;
+ }
+ else
+ {
+ *buf++ = '&';
+ *buf++ = '&';
+ }
+ return buf;
+ }
+ virtual char* second_demangled_name(char* buf) const
+ {
+ if (__left_->is_array())
+ *buf++ = ')';
+ return __left_->second_demangled_name(buf);
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return __left_->is_function();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+ virtual size_t list_len() const
+ {
+ return __left_->list_len();
+ }
+};
+
+class __d_complex
+ : public __node
+{
+ static const size_t n = sizeof(" complex") - 1;
+public:
+
+ explicit __d_complex(__node* type)
+ {
+ __left_ = type;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __left_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, " complex", n);
+ return buf + n;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __imaginary
+ : public __node
+{
+ static const size_t n = sizeof(" imaginary") - 1;
+public:
+
+ explicit __imaginary(__node* type)
+ {
+ __left_ = type;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = n + __left_->size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ strncpy(buf, " imaginary", n);
+ return buf + n;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __pack_expansion
+ : public __node
+{
+public:
+
+ explicit __pack_expansion(__node* type)
+ {
+ __left_ = type;
+ }
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t len = __left_->list_len();
+ size_t off = 0;
+ if (len != 0)
+ {
+ if (__left_->is_sub() || len == 1)
+ off = __left_->size();
+ else
+ {
+ __node* top = __left_;
+ __node* bottom = top;
+ while (!bottom->__left_->is_sub())
+ bottom = bottom->__left_;
+ __node* sub = bottom->__left_;
+ __node* i = sub->__left_;
+ bool first = true;
+ top->reset_cached_size();
+ while (i)
+ {
+ if (!first)
+ off += 2;
+ bottom->__left_ = i->__left_;
+ off += top->size();
+ top->reset_cached_size();
+ i = i->__right_;
+ first = false;
+ }
+ bottom->__left_ = sub;
+ }
+ }
+ const_cast<long&>(__cached_size_) = off;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ size_t len = __left_->list_len();
+ if (len != 0)
+ {
+ if (__left_->is_sub() || len == 1)
+ buf = __left_->get_demangled_name(buf);
+ else
+ {
+ __node* top = __left_;
+ __node* bottom = top;
+ while (!bottom->__left_->is_sub())
+ bottom = bottom->__left_;
+ __node* sub = bottom->__left_;
+ __node* i = sub->__left_;
+ bool first = true;
+ top->reset_cached_size();
+ while (i)
+ {
+ if (!first)
+ {
+ *buf++ = ',';
+ *buf++ = ' ';
+ }
+ bottom->__left_ = i->__left_;
+ buf = top->get_demangled_name(buf);
+ top->reset_cached_size();
+ i = i->__right_;
+ first = false;
+ }
+ bottom->__left_ = sub;
+ }
+ }
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __void
+ : public __node
+{
+ static const size_t n = sizeof("void") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "void", n);
+ return buf + n;
+ }
+};
+
+class __wchar_t
+ : public __node
+{
+ static const size_t n = sizeof("wchar_t") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "wchar_t", n);
+ return buf + n;
+ }
+};
+
+class __wchar_t_literal
+ : public __node
+{
+public:
+ explicit __wchar_t_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+9;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(wchar_t)", 9);
+ buf += 9;
+ strncpy(buf, __name_, __size_);
+ return buf + __size_;
+ }
+};
+
+class __bool
+ : public __node
+{
+ static const size_t n = sizeof("bool") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "bool", n);
+ return buf + n;
+ }
+};
+
+class __bool_literal
+ : public __node
+{
+public:
+ explicit __bool_literal(const char* __name, unsigned __size)
+ {
+ __name_ = __name;
+ __size_ = __size;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, __name_, __size_);
+ return buf + __size_;
+ }
+};
+
+class __char
+ : public __node
+{
+ static const size_t n = sizeof("char") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "char", n);
+ return buf + n;
+ }
+};
+
+class __char_literal
+ : public __node
+{
+public:
+ explicit __char_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+6;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(char)", 6);
+ buf += 6;
+ if (*__name_ == 'n')
+ {
+ *buf++ = '-'; // strncpy(buf+6, "-", 1);
+ strncpy(buf, __name_+1, __size_-1);
+ buf += __size_ - 1;
+ }
+ else
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ return buf;
+ }
+};
+
+class __signed_char
+ : public __node
+{
+ static const size_t n = sizeof("signed char") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "signed char", n);
+ return buf + n;
+ }
+};
+
+class __signed_char_literal
+ : public __node
+{
+public:
+ explicit __signed_char_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+13;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(signed char)", 13);
+ buf += 13;
+ if (*__name_ == 'n')
+ {
+ *buf++ = '-';
+ strncpy(buf, __name_+1, __size_-1);
+ buf += __size_ - 1;
+ }
+ else
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ return buf;
+ }
+};
+
+class __unsigned_char
+ : public __node
+{
+ static const size_t n = sizeof("unsigned char") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "unsigned char", n);
+ return buf + n;
+ }
+};
+
+class __unsigned_char_literal
+ : public __node
+{
+public:
+ explicit __unsigned_char_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+15;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(unsigned char)", 15);
+ buf += 15;
+ strncpy(buf, __name_, __size_);
+ return buf + __size_;
+ }
+};
+
+class __short
+ : public __node
+{
+ static const size_t n = sizeof("short") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "short", n);
+ return buf + n;
+ }
+};
+
+class __short_literal
+ : public __node
+{
+public:
+ explicit __short_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+7;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(short)", 7);
+ buf += 7;
+ if (*__name_ == 'n')
+ {
+ *buf++ = '-';
+ strncpy(buf, __name_+1, __size_-1);
+ buf += __size_ - 1;
+ }
+ else
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ return buf;
+ }
+};
+
+class __unsigned_short
+ : public __node
+{
+ static const size_t n = sizeof("unsigned short") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "unsigned short", n);
+ return buf + n;
+ }
+};
+
+class __unsigned_short_literal
+ : public __node
+{
+public:
+ explicit __unsigned_short_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+16;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(unsigned short)", 16);
+ buf += 16;
+ strncpy(buf, __name_, __size_);
+ return buf + __size_;
+ }
+};
+
+class __int
+ : public __node
+{
+ static const size_t n = sizeof("int") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ *buf++ = 'i';
+ *buf++ = 'n';
+ *buf++ = 't';
+ return buf;
+ }
+};
+
+class __int_literal
+ : public __node
+{
+public:
+ explicit __int_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (*__name_ == 'n')
+ {
+ *buf++ = '-';
+ strncpy(buf, __name_+1, __size_-1);
+ buf += __size_ - 1;
+ }
+ else
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ return buf;
+ }
+};
+
+class __unsigned_int
+ : public __node
+{
+ static const size_t n = sizeof("unsigned int") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "unsigned int", n);
+ return buf + n;
+ }
+};
+
+class __unsigned_int_literal
+ : public __node
+{
+public:
+ explicit __unsigned_int_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+1;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ *buf++ = 'u';
+ return buf;
+ }
+};
+
+class __long
+ : public __node
+{
+ static const size_t n = sizeof("long") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "long", n);
+ return buf + n;
+ }
+};
+
+class __long_literal
+ : public __node
+{
+public:
+ explicit __long_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+1;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (*__name_ == 'n')
+ {
+ *buf++ = '-'; // strncpy(buf, "-", 1);
+ strncpy(buf, __name_+1, __size_-1);
+ buf += __size_ - 1;
+ }
+ else
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ *buf++ = 'l';
+ return buf;
+ }
+};
+
+class __unsigned_long
+ : public __node
+{
+ static const size_t n = sizeof("unsigned long") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "unsigned long", n);
+ return buf + n;
+ }
+};
+
+class __unsigned_long_literal
+ : public __node
+{
+public:
+ explicit __unsigned_long_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+2;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ *buf++ = 'u';
+ *buf++ = 'l';
+ return buf;
+ }
+};
+
+class __long_long
+ : public __node
+{
+ static const size_t n = sizeof("long long") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "long long", n);
+ return buf + n;
+ }
+};
+
+class __long_long_literal
+ : public __node
+{
+public:
+ explicit __long_long_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+2;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (*__name_ == 'n')
+ {
+ *buf++ = '-';
+ strncpy(buf, __name_+1, __size_-1);
+ buf += __size_ - 1;
+ }
+ else
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ *buf++ = 'l';
+ *buf++ = 'l';
+ return buf;
+ }
+};
+
+class __unsigned_long_long
+ : public __node
+{
+ static const size_t n = sizeof("unsigned long long") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "unsigned long long", n);
+ return buf + n;
+ }
+};
+
+class __unsigned_long_long_literal
+ : public __node
+{
+public:
+ explicit __unsigned_long_long_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+3;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ *buf++ = 'u';
+ *buf++ = 'l';
+ *buf++ = 'l';
+ return buf;
+ }
+};
+
+class __int128
+ : public __node
+{
+ static const size_t n = sizeof("__int128") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "__int128", n);
+ return buf + n;
+ }
+};
+
+class __int128_literal
+ : public __node
+{
+public:
+ explicit __int128_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+10;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(__int128)", 10);
+ buf += 10;
+ if (*__name_ == 'n')
+ {
+ *buf++ = '-';
+ strncpy(buf, __name_+1, __size_-1);
+ buf += __size_ - 1;
+ }
+ else
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ return buf;
+ }
+};
+
+class __unsigned_int128
+ : public __node
+{
+ static const size_t n = sizeof("unsigned __int128") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "unsigned __int128", n);
+ return buf + n;
+ }
+};
+
+class __unsigned_int128_literal
+ : public __node
+{
+public:
+ explicit __unsigned_int128_literal(const char* __first, const char* __last)
+ {
+ __name_ = __first;
+ __size_ = __last - __first;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __size_+19;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "(unsigned __int128)", 19);
+ buf += 19;
+ strncpy(buf, __name_, __size_);
+ return buf + __size_;
+ }
+};
+
+class __float_literal
+ : public __node
+{
+public:
+ explicit __float_literal(float value)
+ {
+ __value_ = value;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ char num[20] = {0};
+ float v = static_cast<float>(__value_);
+ const_cast<long&>(__cached_size_) = sprintf(num, "%a", v)+1;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ char num[20] = {0};
+ float v = static_cast<float>(__value_);
+ int n = sprintf(num, "%a", v);
+ strncpy(buf, num, n);
+ buf += n;
+ *buf++ = 'f';
+ return buf;
+ }
+};
+
+class __float
+ : public __node
+{
+ static const size_t n = sizeof("float") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "float", n);
+ return buf + n;
+ }
+};
+
+class __double_literal
+ : public __node
+{
+public:
+ explicit __double_literal(double value)
+ {
+ __value_ = value;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ char num[30] = {0};
+ double v = static_cast<double>(__value_);
+ const_cast<long&>(__cached_size_) = sprintf(num, "%a", v);
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ char num[30] = {0};
+ double v = static_cast<double>(__value_);
+ int n = sprintf(num, "%a", v);
+ strncpy(buf, num, n);
+ return buf + n;
+ }
+};
+
+class __double
+ : public __node
+{
+ static const size_t n = sizeof("double") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "double", n);
+ return buf + n;
+ }
+};
+
+class __long_double
+ : public __node
+{
+ static const size_t n = sizeof("long double") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "long double", n);
+ return buf + n;
+ }
+};
+
+class __float128
+ : public __node
+{
+ static const size_t n = sizeof("__float128") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "__float128", n);
+ return buf + n;
+ }
+};
+
+class __ellipsis
+ : public __node
+{
+ static const size_t n = sizeof("...") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ *buf++ = '.';
+ *buf++ = '.';
+ *buf++ = '.';
+ return buf;
+ }
+};
+
+class __decimal64
+ : public __node
+{
+ static const size_t n = sizeof("decimal64") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "decimal64", n);
+ return buf + n;
+ }
+};
+
+class __decimal128
+ : public __node
+{
+ static const size_t n = sizeof("decimal128") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "decimal128", n);
+ return buf + n;
+ }
+};
+
+class __decimal32
+ : public __node
+{
+ static const size_t n = sizeof("decimal32") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "decimal32", n);
+ return buf + n;
+ }
+};
+
+class __decimal16
+ : public __node
+{
+ static const size_t n = sizeof("decimal16") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "decimal16", n);
+ return buf + n;
+ }
+};
+
+class __d_char32_t
+ : public __node
+{
+ static const size_t n = sizeof("char32_t") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "char32_t", n);
+ return buf + n;
+ }
+};
+
+class __d_char16_t
+ : public __node
+{
+ static const size_t n = sizeof("char16_t") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "char16_t", n);
+ return buf + n;
+ }
+};
+
+class __auto
+ : public __node
+{
+ static const size_t n = sizeof("auto") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "auto", n);
+ return buf + n;
+ }
+};
+
+class __nullptr_t
+ : public __node
+{
+ static const size_t n = sizeof("std::nullptr_t") - 1;
+public:
+
+ virtual size_t first_size() const {return n;}
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "std::nullptr_t", n);
+ return buf + n;
+ }
+};
+
+class __array
+ : public __node
+{
+public:
+
+ explicit __array(__node* type)
+ {
+ __left_ = type;
+ }
+
+ __array(__node* type, size_t dim)
+ {
+ __left_ = type;
+ __size_ = dim;
+ }
+
+ __array(__node* type, __node* dim)
+ {
+ __left_ = type;
+ __right_ = dim;
+ }
+
+ virtual size_t size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t r = __left_->size() + 3;
+ if (__right_ != 0)
+ r += __right_->size();
+ else if (__size_ != 0)
+ r += snprintf(0, 0, "%ld", __size_);
+ const_cast<long&>(__cached_size_) = r;
+ }
+ return __cached_size_;
+ }
+
+ virtual char* get_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ' ';
+ *buf++ = '[';
+ if (__right_ != 0)
+ buf = __right_->get_demangled_name(buf);
+ else if (__size_ != 0)
+ {
+ size_t rs = sprintf(buf, "%ld", __size_);
+ buf += rs;
+ }
+ *buf++ = ']';
+ return buf;
+ }
+
+ virtual size_t first_size() const
+ {
+ return __left_->first_size();
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ return __left_->first_demangled_name(buf);
+ }
+
+ virtual size_t second_size() const
+ {
+ size_t r = 2 + __left_->second_size();
+ if (!__left_->is_array())
+ ++r;
+ if (__right_ != 0)
+ r += __right_->size();
+ else if (__size_ != 0)
+ r += snprintf(0, 0, "%ld", __size_);
+ return r;
+ }
+
+ virtual char* second_demangled_name(char* buf) const
+ {
+ *buf++ = ' ';
+ *buf++ = '[';
+ if (__right_ != 0)
+ buf = __right_->get_demangled_name(buf);
+ else if (__size_ != 0)
+ {
+ size_t off = sprintf(buf, "%ld", __size_);
+ buf += off;
+ }
+ char* t = buf;
+ buf = __left_->second_demangled_name(buf);
+ *t = ']';
+ if (buf == t)
+ ++buf;
+ return buf;
+ }
+ virtual bool is_array() const
+ {
+ return true;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+class __pointer_to_member_type
+ : public __node
+{
+public:
+
+ __pointer_to_member_type(__node* class_type, __node* member_type)
+ {
+ __left_ = class_type;
+ __right_ = member_type;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + 3
+ + __right_->first_size()
+ + __right_->second_size();
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __right_->first_demangled_name(buf);
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ':';
+ *buf++ = ':';
+ *buf++ = '*';
+ return __right_->second_demangled_name(buf);
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool is_reference_or_pointer_to_function_or_array() const
+ {
+ return __right_->is_function();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __decltype_node
+ : public __node
+{
+public:
+
+ explicit __decltype_node(__node* expr)
+ {
+ __right_ = expr;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = 10 + __right_->size();
+ return __cached_size_;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "decltype(", 9);
+ buf += 9;
+ buf = __right_->get_demangled_name(buf);
+ *buf++ = ')';
+ return buf;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __nested_delimeter
+ : public __node
+{
+public:
+
+ explicit __nested_delimeter(__node* prev, __node* arg)
+ {
+ __left_ = prev;
+ __right_ = arg;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __left_->size() + __right_->size() + 2;
+ return __cached_size_;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ':';
+ *buf++ = ':';
+ return __right_->get_demangled_name(buf);
+ }
+
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return __right_->ends_with_template(parsing);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return __right_->is_ctor_dtor_conv();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end) &&
+ __right_->fix_forward_references(t_begin, t_end);
+ }
+ virtual __node* extract_cv(__node*& rt) const
+ {
+ return __right_->extract_cv(const_cast<__node*&>(__right_));
+ }
+};
+
+class __unresolved_name
+ : public __node
+{
+public:
+
+ __unresolved_name(__node* prev, __node* arg)
+ {
+ __left_ = prev;
+ __right_ = arg;
+ }
+
+ __unresolved_name(bool global, __node* prev, __node* arg)
+ {
+ __size_ = global;
+ __left_ = prev;
+ __right_ = arg;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = (__left_ ? __left_->size() + 2 : 0) +
+ __right_->size() + __size_ * 2;
+ return __cached_size_;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__size_)
+ {
+ *buf++ = ':';
+ *buf++ = ':';
+ }
+ if (__left_)
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ':';
+ *buf++ = ':';
+ }
+ return __right_->get_demangled_name(buf);
+ }
+
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return __right_->ends_with_template(parsing);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return __right_->is_ctor_dtor_conv();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = __left_->fix_forward_references(t_begin, t_end);
+ return r && __right_->fix_forward_references(t_begin, t_end);
+ }
+ virtual __node* extract_cv(__node*& rt) const
+ {
+ return __right_->extract_cv(const_cast<__node*&>(__right_));
+ }
+};
+
+class __string_literal
+ : public __node
+{
+public:
+
+ virtual size_t first_size() const
+ {
+ return 14;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ strncpy(buf, "string literal", 14);
+ return buf + 14;
+ }
+};
+
+class __constructor
+ : public __node
+{
+public:
+
+ explicit __constructor(__node* name)
+ {
+ __right_ = name;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __right_->base_size();
+ return __cached_size_;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ return __right_->get_base_name(buf);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool ends_with_template(bool parsing = false) const
+ {
+ return __right_->ends_with_template(parsing);
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return true;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __destructor
+ : public __node
+{
+public:
+
+ explicit __destructor(__node* name)
+ {
+ __right_ = name;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ const_cast<long&>(__cached_size_) = __right_->base_size() + 1;
+ return __cached_size_;
+ }
+
+ virtual char* first_demangled_name(char* buf) const
+ {
+ *buf++ = '~';
+ return __right_->get_base_name(buf);
+ }
+ virtual __node* base_name() const
+ {
+ return __right_->base_name();
+ }
+ virtual bool is_ctor_dtor_conv() const
+ {
+ return true;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __right_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __dot_suffix
+ : public __node
+{
+public:
+ __dot_suffix(__node* name, const char* suffix, unsigned sz)
+ {
+ __left_ = name;
+ __name_ = suffix;
+ __size_ = sz;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t off = __left_->size();
+ off += __size_ + 3;
+ const_cast<long&>(__cached_size_) = off;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ buf = __left_->get_demangled_name(buf);
+ *buf++ = ' ';
+ *buf++ = '(';
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ *buf++ = ')';
+ return buf;
+ }
+ virtual __node* base_name() const
+ {
+ return __left_->base_name();
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ return __left_->fix_forward_references(t_begin, t_end);
+ }
+};
+
+class __vector_type
+ : public __node
+{
+public:
+ __vector_type(__node* type, const char* num, size_t sz)
+ {
+ __left_ = type;
+ __name_ = num;
+ __size_ = sz;
+ }
+
+ __vector_type(__node* type, __node* num)
+ {
+ __left_ = type;
+ __right_ = num;
+ }
+
+ virtual size_t first_size() const
+ {
+ if (__cached_size_ == -1)
+ {
+ size_t off = 5;
+ if (__left_)
+ off = __left_->size();
+ off += 9;
+ if (__right_)
+ off += __right_->size();
+ else if (__size_ > 0)
+ off += __size_;
+ const_cast<long&>(__cached_size_) = off;
+ }
+ return __cached_size_;
+ }
+ virtual char* first_demangled_name(char* buf) const
+ {
+ if (__left_)
+ buf = __left_->get_demangled_name(buf);
+ else
+ {
+ strncpy(buf, "pixel", 5);
+ buf += 5;
+ }
+ strncpy(buf, " vector[", 8);
+ buf += 8;
+ if (__right_)
+ buf = __right_->get_demangled_name(buf);
+ else if (__size_ > 0)
+ {
+ strncpy(buf, __name_, __size_);
+ buf += __size_;
+ }
+ *buf++ = ']';
+ return buf;
+ }
+ virtual __node* base_name() const
+ {
+ if (__left_)
+ return __left_->base_name();
+ return __left_;
+ }
+ virtual bool fix_forward_references(__node** t_begin, __node** t_end)
+ {
+ bool r = true;
+ if (__left_)
+ r = __left_->fix_forward_references(t_begin, t_end);
+ if (__right_)
+ r = r && __right_->fix_forward_references(t_begin, t_end);
+ return r;
+ }
+};
+
+
+enum {invalid_args = -3, invalid_mangled_name, memory_alloc_failure, success,
+ not_yet_implemented};
+
+__demangle_tree::__demangle_tree(const char* mangled_name, char* buf, size_t bs)
+ : __mangled_name_begin_(0), __mangled_name_end_(0),
+ __status_(invalid_mangled_name), __root_(0),
+ __node_begin_(0), __node_end_(0), __node_cap_(0),
+ __sub_begin_(0), __sub_end_(0), __sub_cap_(0),
+ __t_begin_(0), __t_end_(0), __t_cap_(0),
+ __tag_templates_(true),
+ __fix_forward_references_(false)
+{
+ size_t n = strlen(mangled_name);
+ size_t ms = n + 2*n*sizeof(__node) + 2*n*sizeof(__node*);
+ char* m;
+ if (ms <= bs)
+ {
+ m = buf;
+ __owns_buf_ = false;
+ }
+ else
+ {
+ m = static_cast<char*>(malloc(ms));
+ __owns_buf_ = true;
+ }
+ if (m == NULL)
+ {
+ __status_ = memory_alloc_failure;
+ return;
+ }
+ __node_begin_ = __node_end_ = (__node*)(m);
+ __node_cap_ = __node_begin_ + 2*n;
+ __sub_begin_ = __sub_end_ = (__node**)(__node_cap_);
+ __sub_cap_ = __sub_begin_ + n;
+ __t_begin_ = __t_end_ = (__node**)(__sub_cap_);
+ __t_cap_ = __t_begin_ + n;
+ __mangled_name_begin_ = (const char*)(__t_cap_);
+ __mangled_name_end_ = __mangled_name_begin_ + n;
+ strncpy(const_cast<char*>(__mangled_name_begin_), mangled_name, n);
+}
+
+__demangle_tree::~__demangle_tree()
+{
+ if (__owns_buf_)
+ free(__node_begin_);
+}
+
+__demangle_tree::__demangle_tree(__demangle_tree& t)
+ : __mangled_name_begin_(t.__mangled_name_begin_),
+ __mangled_name_end_(t.__mangled_name_end_),
+ __status_(t.__status_), __root_(t.__root_),
+ __node_begin_(t.__node_begin_), __node_end_(t.__node_end_),
+ __node_cap_(t.__node_cap_),
+ __sub_begin_(t.__sub_begin_), __sub_end_(t.__sub_end_),
+ __sub_cap_(t.__sub_cap_),
+ __t_begin_(t.__t_begin_), __t_end_(t.__t_end_),
+ __t_cap_(t.__t_cap_),
+ __tag_templates_(t.__tag_templates_),
+ __fix_forward_references_(t.__fix_forward_references_),
+ __owns_buf_(t.__owns_buf_)
+{
+ t.__mangled_name_begin_ = 0;
+ t.__mangled_name_end_ = 0;
+ t.__status_ = invalid_mangled_name;
+ t.__root_ = 0;
+ t.__node_begin_ = t.__node_end_ = t.__node_cap_ = 0;
+ t.__sub_begin_ = t.__sub_end_ = t.__sub_cap_ = 0;
+ t.__t_begin_ = t.__t_end_ = t.__t_cap_ = 0;
+ t.__owns_buf_ = false;
+}
+
+__demangle_tree::__demangle_tree(__demangle_tree_rv rv)
+ : __mangled_name_begin_(rv.ptr_->__mangled_name_begin_),
+ __mangled_name_end_(rv.ptr_->__mangled_name_end_),
+ __status_(rv.ptr_->__status_), __root_(rv.ptr_->__root_),
+ __node_begin_(rv.ptr_->__node_begin_), __node_end_(rv.ptr_->__node_end_),
+ __node_cap_(rv.ptr_->__node_cap_),
+ __sub_begin_(rv.ptr_->__sub_begin_), __sub_end_(rv.ptr_->__sub_end_),
+ __sub_cap_(rv.ptr_->__sub_cap_),
+ __t_begin_(rv.ptr_->__t_begin_), __t_end_(rv.ptr_->__t_end_),
+ __t_cap_(rv.ptr_->__t_cap_),
+ __tag_templates_(rv.ptr_->__tag_templates_),
+ __fix_forward_references_(rv.ptr_->__fix_forward_references_),
+ __owns_buf_(rv.ptr_->__owns_buf_)
+{
+ rv.ptr_->__mangled_name_begin_ = 0;
+ rv.ptr_->__mangled_name_end_ = 0;
+ rv.ptr_->__status_ = invalid_mangled_name;
+ rv.ptr_->__root_ = 0;
+ rv.ptr_->__node_begin_ = rv.ptr_->__node_end_ = rv.ptr_->__node_cap_ = 0;
+ rv.ptr_->__sub_begin_ = rv.ptr_->__sub_end_ = rv.ptr_->__sub_cap_ = 0;
+ rv.ptr_->__t_begin_ = rv.ptr_->__t_end_ = rv.ptr_->__t_cap_ = 0;
+ rv.ptr_->__owns_buf_ = false;
+}
+
+int
+__demangle_tree::__status() const
+{
+ return __status_;
+}
+
+size_t
+__demangle_tree::size() const
+{
+ return __status_ == success ? __root_->size() : 0;
+}
+
+char*
+__demangle_tree::__get_demangled_name(char* buf) const
+{
+ if (__status_ == success)
+ return __root_->get_demangled_name(buf);
+ return 0;
+}
+
+template <class _Tp>
+bool
+__demangle_tree::__make()
+{
+ if (__node_end_ < __node_cap_)
+ {
+ ::new (__node_end_) _Tp();
+ __root_ = __node_end_;
+ ++__node_end_;
+ return true;
+ }
+ __status_ = memory_alloc_failure;
+ return false;
+}
+
+template <class _Tp, class _A0>
+bool
+__demangle_tree::__make(_A0 __a0)
+{
+ if (__node_end_ < __node_cap_)
+ {
+ ::new (__node_end_) _Tp(__a0);
+ __root_ = __node_end_;
+ ++__node_end_;
+ return true;
+ }
+ __status_ = memory_alloc_failure;
+ return false;
+}
+
+template <class _Tp, class _A0, class _A1>
+bool
+__demangle_tree::__make(_A0 __a0, _A1 __a1)
+{
+ if (__node_end_ < __node_cap_)
+ {
+ ::new (__node_end_) _Tp(__a0, __a1);
+ __root_ = __node_end_;
+ ++__node_end_;
+ return true;
+ }
+ __status_ = memory_alloc_failure;
+ return false;
+}
+
+template <class _Tp, class _A0, class _A1, class _A2>
+bool
+__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2)
+{
+ if (__node_end_ < __node_cap_)
+ {
+ ::new (__node_end_) _Tp(__a0, __a1, __a2);
+ __root_ = __node_end_;
+ ++__node_end_;
+ return true;
+ }
+ __status_ = memory_alloc_failure;
+ return false;
+}
+
+template <class _Tp, class _A0, class _A1, class _A2, class _A3>
+bool
+__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3)
+{
+ if (__node_end_ < __node_cap_)
+ {
+ ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3);
+ __root_ = __node_end_;
+ ++__node_end_;
+ return true;
+ }
+ __status_ = memory_alloc_failure;
+ return false;
+}
+
+template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4>
+bool
+__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4)
+{
+ if (__node_end_ < __node_cap_)
+ {
+ ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4);
+ __root_ = __node_end_;
+ ++__node_end_;
+ return true;
+ }
+ __status_ = memory_alloc_failure;
+ return false;
+}
+
+template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4,
+ class _A5>
+bool
+__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4,
+ _A5 __a5)
+{
+ if (__node_end_ < __node_cap_)
+ {
+ ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4, __a5);
+ __root_ = __node_end_;
+ ++__node_end_;
+ return true;
+ }
+ __status_ = memory_alloc_failure;
+ return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
+// [R | O] # & or &&
+
+const char*
+__demangle_tree::__parse_cv_qualifiers(const char* first, const char* last,
+ unsigned& cv, bool look_for_ref_quals)
+{
+ if (look_for_ref_quals)
+ {
+ for (; first != last; ++first)
+ {
+ switch (*first)
+ {
+ case 'r':
+ cv |= 4;
+ break;
+ case 'V':
+ cv |= 2;
+ break;
+ case 'K':
+ cv |= 1;
+ break;
+ case 'R':
+ cv |= 8;
+ break;
+ case 'O':
+ cv |= 16;
+ break;
+ default:
+ return first;
+ }
+ }
+ }
+ else
+ {
+ for (; first != last; ++first)
+ {
+ switch (*first)
+ {
+ case 'r':
+ cv |= 4;
+ break;
+ case 'V':
+ cv |= 2;
+ break;
+ case 'K':
+ cv |= 1;
+ break;
+ default:
+ return first;
+ }
+ }
+ }
+ return first;
+}
+
+// <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)
+// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+// ::= u <source-name> # vendor extended type
+
+const char*
+__demangle_tree::__parse_builtin_type(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'v':
+ if (__make<__void>())
+ ++first;
+ break;
+ case 'w':
+ if (__make<__wchar_t>())
+ ++first;
+ break;
+ case 'b':
+ if (__make<__bool>())
+ ++first;
+ break;
+ case 'c':
+ if (__make<__char>())
+ ++first;
+ break;
+ case 'a':
+ if (__make<__signed_char>())
+ ++first;
+ break;
+ case 'h':
+ if (__make<__unsigned_char>())
+ ++first;
+ break;
+ case 's':
+ if (__make<__short>())
+ ++first;
+ break;
+ case 't':
+ if (__make<__unsigned_short>())
+ ++first;
+ break;
+ case 'i':
+ if (__make<__int>())
+ ++first;
+ break;
+ case 'j':
+ if (__make<__unsigned_int>())
+ ++first;
+ break;
+ case 'l':
+ if (__make<__long>())
+ ++first;
+ break;
+ case 'm':
+ if (__make<__unsigned_long>())
+ ++first;
+ break;
+ case 'x':
+ if (__make<__long_long>())
+ ++first;
+ break;
+ case 'y':
+ if (__make<__unsigned_long_long>())
+ ++first;
+ break;
+ case 'n':
+ if (__make<__int128>())
+ ++first;
+ break;
+ case 'o':
+ if (__make<__unsigned_int128>())
+ ++first;
+ break;
+ case 'f':
+ if (__make<__float>())
+ ++first;
+ break;
+ case 'd':
+ if (__make<__double>())
+ ++first;
+ break;
+ case 'e':
+ if (__make<__long_double>())
+ ++first;
+ break;
+ case 'g':
+ if (__make<__float128>())
+ ++first;
+ break;
+ case 'z':
+ if (__make<__ellipsis>())
+ ++first;
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'd':
+ if (__make<__decimal64>())
+ first += 2;
+ break;
+ case 'e':
+ if (__make<__decimal128>())
+ first += 2;
+ break;
+ case 'f':
+ if (__make<__decimal32>())
+ first += 2;
+ break;
+ case 'h':
+ if (__make<__decimal16>())
+ first += 2;
+ break;
+ case 'i':
+ if (__make<__d_char32_t>())
+ first += 2;
+ break;
+ case 's':
+ if (__make<__d_char16_t>())
+ first += 2;
+ break;
+ case 'a':
+ if (__make<__auto>())
+ first += 2;
+ break;
+ case 'n':
+ if (__make<__nullptr_t>())
+ first += 2;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <bare-function-type> ::= <signature type>+
+// # types are possible return type, then parameter types
+
+const char*
+__demangle_tree::__parse_bare_function_type(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ __tag_templates_ = false;
+ const char* t = __parse_type(first, last);
+ if (t != first && __make<__list>(__root_))
+ {
+ const char* t0 = t;
+ __node* head = __root_;
+ __node* prev = head;
+ while (true)
+ {
+ t = __parse_type(t0, last);
+ if (t != t0)
+ {
+ if (__make<__list>(__root_))
+ {
+ t0 = t;
+ prev->__right_ = __root_;
+ __root_->__size_ = prev->__size_ + 1;
+ prev = __root_;
+ }
+ else
+ break;
+ }
+ else
+ {
+ first = t;
+ __root_ = head;
+ break;
+ }
+ }
+ }
+ __tag_templates_ = true;
+ }
+ return first;
+}
+
+// <function-type> ::= F [Y] <bare-function-type> E
+
+const char*
+__demangle_tree::__parse_function_type(const char* first, const char* last)
+{
+ if (first != last && *first == 'F')
+ {
+ const char* t = first+1;
+ if (t != last)
+ {
+ bool externC = false;
+ if (*t == 'Y')
+ {
+ externC = true;
+ if (++t == last)
+ return first;
+ }
+ const char* t1 = __parse_type(t, last);
+ if (t1 != t)
+ {
+ __node* ret = __root_;
+ t = t1;
+ t1 = __parse_bare_function_type(t, last);
+ if (t1 != t && t1 != last && *t1 == 'E')
+ {
+ if (dynamic_cast<__void*>(__root_->__left_) != NULL)
+ __root_->__left_ = NULL;
+ if (__make<__function_signature>(ret, __root_))
+ {
+ if (__make<__function>((__node*)0, __root_))
+ first = t1+1;
+ }
+ }
+ }
+ }
+ }
+ return first;
+}
+
+const char*
+__demangle_tree::__parse_hex_number(const char* first, const char* last, unsigned long long& n)
+{
+ const char* t = first;
+ for (; t != last && isxdigit(*t); ++t)
+ {
+ if (t == first)
+ n = 0;
+ if (isdigit(*t))
+ n = n * 16 + *t - '0';
+ else if (isupper(*t))
+ n = n * 16 + *t - 'A' + 10;
+ else
+ n = n * 16 + *t - 'a' + 10;
+ }
+ first = t;
+ return first;
+}
+
+// <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
+
+const char*
+__demangle_tree::__parse_expr_primary(const char* first, const char* last)
+{
+ if (last - first >= 4 && *first == 'L')
+ {
+ switch (first[1])
+ {
+ case 'w':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__wchar_t_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'b':
+ if (first[3] == 'E')
+ {
+ switch (first[2])
+ {
+ case '0':
+ if (__make<__bool_literal>("false", 5))
+ first += 4;
+ break;
+ case '1':
+ if (__make<__bool_literal>("true", 4))
+ first += 4;
+ break;
+ }
+ }
+ break;
+ case 'c':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__char_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'a':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__signed_char_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'h':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__unsigned_char_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 's':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__short_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 't':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__unsigned_short_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'i':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__int_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'j':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__unsigned_int_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'l':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__long_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'm':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__unsigned_long_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'x':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__long_long_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'y':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__unsigned_long_long_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'n':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__int128_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'o':
+ {
+ const char* t = __parse_number(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__unsigned_int128_literal>(first+2, t))
+ first = t+1;
+ }
+ }
+ break;
+ case 'f':
+ {
+ if (last - (first+2) <= 8)
+ return first;
+ unsigned long long j;
+ const char* t = __parse_hex_number(first+2, first+10, j);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ unsigned i = static_cast<unsigned>(j);
+ float value = *(float*)&i;
+ if (__make<__float_literal>(value))
+ first = t+1;
+ }
+ }
+ break;
+ case 'd':
+ {
+ if (last - (first+2) <= 16)
+ return first;
+ unsigned long long j;
+ const char* t = __parse_hex_number(first+2, first+18, j);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ double value = *(double*)&j;
+ if (__make<__double_literal>(value))
+ first = t+1;
+ }
+ }
+ break;
+ case 'e':
+ break;
+ case '_':
+ if (first[2] == 'Z')
+ {
+ const char* t = __parse_encoding(first+3, last);
+ if (t != first+3 && t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ default:
+ {
+ // might be named type
+ const char* t = __parse_type(first+1, last);
+ 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 (__make<__cast_literal>(__root_, t, n))
+ {
+ first = n+1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ first = t+1;
+ break;
+ }
+ }
+ }
+// assert(!"case in __parse_expr_primary not implemented");
+ __status_ = not_yet_implemented;
+ }
+ }
+ return first;
+}
+
+// <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
+
+const char*
+__demangle_tree::__parse_unnamed_type_name(const char* first, const char* last)
+{
+ if (last - first > 2 && first[0] == 'U')
+ {
+ switch (first[1])
+ {
+ case 't':
+ case 'l':
+ first += 2;
+ __status_ = not_yet_implemented;
+ break;
+ }
+ }
+ return first;
+}
+
+// <ctor-dtor-name> ::= C1 # complete object constructor
+// ::= C2 # base object constructor
+// ::= C3 # complete object allocating constructor
+// ::= D0 # deleting destructor
+// ::= D1 # complete object destructor
+// ::= D2 # base object destructor
+
+const char*
+__demangle_tree::__parse_ctor_dtor_name(const char* first, const char* last)
+{
+ if (last-first >= 2)
+ {
+ switch (first[0])
+ {
+ case 'C':
+ switch (first[1])
+ {
+ case '1':
+ case '2':
+ case '3':
+ if (__make<__constructor>(__root_->base_name()))
+ first += 2;
+ break;
+ }
+ break;
+ case 'D':
+ switch (first[1])
+ {
+ case '0':
+ case '1':
+ case '2':
+ if (__make<__destructor>(__root_->base_name()))
+ first += 2;
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+const char*
+__demangle_tree::__parse_unscoped_template_name(const char* first, const char* last)
+{
+// assert(!"__parse_unscoped_template_name not implemented");
+ __status_ = not_yet_implemented;
+ return first;
+}
+
+// <discriminator> := _ <non-negative number> # when number < 10
+// := __ <non-negative number> _ # when number >= 10
+// extension := decimal-digit+
+
+const char*
+__demangle_tree::__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 (isdigit(*t1))
+ first = t1+1;
+ else if (*t1 == '_')
+ {
+ for (++t1; t1 != last && isdigit(*t1); ++t1)
+ ;
+ if (t1 != last && *t1 == '_')
+ first = t1 + 1;
+ }
+ }
+ }
+ else if (isdigit(*first))
+ {
+ const char* t1 = first+1;
+ for (; t1 != last && isdigit(*t1); ++t1)
+ ;
+ first = t1;
+ }
+ }
+ 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*
+__demangle_tree::__parse_local_name(const char* first, const char* last)
+{
+ if (first != last && *first == 'Z')
+ {
+ const char* t = __parse_encoding(first+1, last);
+ if (t != first+1 && t != last && *t == 'E' && ++t != last)
+ {
+ __node* encoding = __root_;
+ switch (*t)
+ {
+ case 's':
+ {
+ const char*t1 = __parse_discriminator(t+1, last);
+ if (__make<__string_literal>())
+ {
+ if (__make<__nested_delimeter>(encoding, __root_))
+ first = t1;
+ }
+ }
+ break;
+ case 'd':
+// assert(!"__parse_local_name d not implemented");
+ __status_ = not_yet_implemented;
+ break;
+ default:
+ {
+ const char*t1 = __parse_name(t, last);
+ if (t1 != t)
+ {
+ // parse but ignore discriminator
+ t1 = __parse_discriminator(t1, last);
+ if (__make<__nested_delimeter>(encoding, __root_))
+ first = t1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+// ::= <simple-id> # e.g., ~A<2*N>
+
+const char*
+__demangle_tree::__parse_destructor_name(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t = __parse_unresolved_type(first, last);
+ if (t == first)
+ t = __parse_simple_id(first, last);
+ if (t != first && __make<__destructor>(__root_))
+ first = t;
+ }
+ return first;
+}
+
+// <simple-id> ::= <source-name> [ <template-args> ]
+
+const char*
+__demangle_tree::__parse_simple_id(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t = __parse_source_name(first, last);
+ if (t != first)
+ first = __parse_template_args(t, last);
+ else
+ first = t;
+ }
+ return first;
+}
+
+// <base-unresolved-name> ::= <simple-id> # unresolved name
+// extension ::= <operator-name> # unresolved operator-function-id
+// extension ::= <operator-name> <template-args> # unresolved operator template-id
+// ::= on <operator-name> # unresolved operator-function-id
+// ::= 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*
+__demangle_tree::__parse_base_unresolved_name(const char* first, const char* last)
+{
+ 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);
+ if (t != first+2)
+ first = __parse_template_args(t, last);
+ else
+ first = t;
+ }
+ else
+ {
+ const char* t = __parse_destructor_name(first+2, last);
+ if (t != first+2)
+ first = t;
+ }
+ }
+ else
+ {
+ const char* t = __parse_simple_id(first, last);
+ if (t == first)
+ {
+ t = __parse_operator_name(first, last);
+ if (t != first)
+ t = __parse_template_args(t, last);
+ }
+ if (t != first)
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <unresolved-type> ::= <template-param>
+// ::= <decltype>
+// ::= <substitution>
+
+const char*
+__demangle_tree::__parse_unresolved_type(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'T':
+ t = __parse_template_param(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ break;
+ case 'D':
+ t = __parse_decltype(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ break;
+ case 'S':
+ t = __parse_substitution(first, last);
+ if (t != first)
+ first = t;
+ break;
+ }
+ }
+ return first;
+}
+
+// <unresolved-qualifier-level> ::= <source-name> [ <template-args> ]
+
+const char*
+__demangle_tree::__parse_unresolved_qualifier_level(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t = __parse_source_name(first, last);
+ if (t != first)
+ first = __parse_template_args(t, last);
+ }
+ return first;
+}
+
+// <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>
+// # A::x, N::y, A<T>::z; "gs" means leading "::"
+// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+// # T::N::x /decltype(p)::N::x
+// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+
+const char*
+__demangle_tree::__parse_unresolved_name(const char* first, const char* last)
+{
+ 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);
+ if (t2 != t)
+ {
+ if (__make<__unresolved_name>(global, (__node*)0, __root_))
+ first = t2;
+ }
+ else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
+ {
+ if (!global && t[2] == 'N')
+ {
+ t2 = __parse_unresolved_type(t+3, last);
+ if (t2 != t+3 && t2 != last)
+ {
+ t = __parse_template_args(t2, last);
+ if (t == last)
+ return first;
+ __node* name = __root_;
+ while (*t != 'E')
+ {
+ t2 = __parse_unresolved_qualifier_level(t, last);
+ if (t2 == t || t2 == last)
+ return first;
+ if (!__make<__nested_delimeter>(name, __root_))
+ return first;
+ name = __root_;
+ t = t2;
+ }
+ t2 = __parse_base_unresolved_name(++t, last);
+ if (t2 != t && __make<__unresolved_name>(false, name, __root_))
+ first = t2;
+ }
+ }
+ else
+ {
+ if (!global)
+ {
+ t2 = __parse_unresolved_type(t+2, last);
+ if (t2 != t+2)
+ {
+ t = t2;
+ __node* name = __root_;
+ t2 = __parse_base_unresolved_name(t, last);
+ if (t2 != t && __make<__unresolved_name>(false, name, __root_))
+ return t2;
+ return first;
+ }
+ }
+ t2 = __parse_unresolved_qualifier_level(t+2, last);
+ if (t2 != t+2 && t2 != last)
+ {
+ __node* name = __root_;
+ t = t2;
+ while (*t != 'E')
+ {
+ t2 = __parse_unresolved_qualifier_level(t, last);
+ if (t2 == t || t2 == last)
+ return first;
+ if (!__make<__nested_delimeter>(name, __root_))
+ return first;
+ name = __root_;
+ t = t2;
+ }
+ t2 = __parse_base_unresolved_name(++t, last);
+ if (t2 != t && __make<__unresolved_name>(global, name, __root_))
+ first = t2;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <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>
+
+const char*
+__demangle_tree::__parse_function_param(const char* first, const char* last)
+{
+ if (last - first >= 3 && *first == 'f')
+ {
+ if (first[1] == 'p')
+ {
+// assert(!"__parse_function_param not implemented");
+ __status_ = not_yet_implemented;
+ }
+ else if (first[1] == 'L')
+ {
+// assert(!"__parse_function_param not implemented");
+ __status_ = not_yet_implemented;
+ }
+ }
+ return first;
+}
+
+// at <type> # alignof (a type)
+
+const char*
+__demangle_tree::__parse_alignof_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'a' && first[1] == 't')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_alignof_expression>(__root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// cc <type> <expression> # const_cast<type> (expression)
+
+const char*
+__demangle_tree::__parse_const_cast_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'c')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ __node* type = __root_;
+ const char* t1 = __parse_expression(t, last);
+ if (t1 != t)
+ {
+ if (__make<__const_cast>(type, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// cl <expression>+ E # call
+
+const char*
+__demangle_tree::__parse_call_expr(const char* first, const char* last)
+{
+ if (last - first >= 4 && first[0] == 'c' && first[1] == 'l')
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (t == last)
+ return first;
+ __node* name = __root_;
+ __node* args = 0;
+ __node* prev = 0;
+ while (*t != 'E')
+ {
+ const char* t1 = __parse_expression(t, last);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!__make<__list>(__root_))
+ return first;
+ if (args == 0)
+ args = __root_;
+ if (prev)
+ {
+ prev->__right_ = __root_;
+ __root_->__size_ = prev->__size_ + 1;
+ }
+ prev = __root_;
+ t = t1;
+ }
+ ++t;
+ if (__make<__call_expr>(name, args))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// cv <type> <expression> # conversion with one argument
+// cv <type> _ <expression>* E # conversion with a different number of arguments
+
+const char*
+__demangle_tree::__parse_conversion_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'c' && first[1] == 'v')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2 && t != last)
+ {
+ __node* type = __root_;
+ __node* args = 0;
+ if (*t != '_')
+ {
+ const char* t1 = __parse_expression(t, last);
+ if (t1 == t)
+ return first;
+ args = __root_;
+ t = t1;
+ }
+ else
+ {
+ ++t;
+ if (t == last)
+ return first;
+ __node* prev = 0;
+ while (*t != 'E')
+ {
+ const char* t1 = __parse_expression(t, last);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!__make<__list>(__root_))
+ return first;
+ if (args == 0)
+ args = __root_;
+ if (prev)
+ {
+ prev->__right_ = __root_;
+ __root_->__size_ = prev->__size_ + 1;
+ }
+ prev = __root_;
+ t = t1;
+ }
+ ++t;
+ }
+ if (__make<__operator_cast>(type, args))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// [gs] da <expression> # delete[] expression
+
+const char*
+__demangle_tree::__parse_delete_array_expr(const char* first, const char* last)
+{
+ 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] == 'd' && t[1] == 'a')
+ {
+ t += 2;
+ const char* t1 = __parse_expression(t, last);
+ if (t1 != t)
+ {
+ if (__make<__delete_array_expr>(parsed_gs, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// dc <type> <expression> # dynamic_cast<type> (expression)
+
+const char*
+__demangle_tree::__parse_dynamic_cast_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 'c')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ __node* type = __root_;
+ const char* t1 = __parse_expression(t, last);
+ if (t1 != t)
+ {
+ if (__make<__dynamic_cast>(type, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// [gs] dl <expression> # delete expression
+
+const char*
+__demangle_tree::__parse_delete_expr(const char* first, const char* last)
+{
+ 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] == 'd' && t[1] == 'l')
+ {
+ t += 2;
+ const char* t1 = __parse_expression(t, last);
+ if (t1 != t)
+ {
+ if (__make<__delete_expr>(parsed_gs, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// ds <expression> <expression> # expr.*expr
+
+const char*
+__demangle_tree::__parse_dot_star_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 's')
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* expr = __root_;
+ const char* t1 = __parse_expression(t, last);
+ if (t1 != t)
+ {
+ if (__make<__dot_star_expr>(expr, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// dt <expression> <unresolved-name> # expr.name
+
+const char*
+__demangle_tree::__parse_dot_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'd' && first[1] == 't')
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* expr = __root_;
+ const char* t1 = __parse_unresolved_name(t, last);
+ if (t1 != t)
+ {
+ if (__make<__dot_expr>(expr, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// mm_ <expression> # prefix --
+
+const char*
+__demangle_tree::__parse_decrement_expr(const char* first, const char* last)
+{
+ if (last - first > 3 && first[0] == 'm' && first[1] == 'm' && first[2] == '_')
+ {
+ const char* t = __parse_expression(first+3, last);
+ if (t != first+3)
+ {
+ if (__make<__operator_decrement>(true, __root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// pp_ <expression> # prefix ++
+
+const char*
+__demangle_tree::__parse_increment_expr(const char* first, const char* last)
+{
+ if (last - first > 3 && first[0] == 'p' && first[1] == 'p' && first[2] == '_')
+ {
+ const char* t = __parse_expression(first+3, last);
+ if (t != first+3)
+ {
+ if (__make<__operator_increment>(true, __root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// [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
+
+const char*
+__demangle_tree::__parse_new_expr(const char* first, const char* last)
+{
+ 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;
+ __node* expr = 0;
+ __node* prev = 0;
+ while (*t != '_')
+ {
+ const char* t1 = __parse_expression(t, last);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!__make<__list>(__root_))
+ return first;
+ if (expr == 0)
+ expr = __root_;
+ if (prev)
+ {
+ prev->__right_ = __root_;
+ __root_->__size_ = prev->__size_ + 1;
+ }
+ prev = __root_;
+ t = t1;
+ }
+ ++t;
+ const char* t1 = __parse_type(t, last);
+ if (t1 == t || t1 == last)
+ return first;
+ t = t1;
+ __node* type = __root_;
+ __node* init = 0;
+ prev = 0;
+ bool has_init = false;
+ if (last - t >= 3 && t[0] == 'p' && t[1] == 'i')
+ {
+ t += 2;
+ has_init = true;
+ while (*t != 'E')
+ {
+ t1 = __parse_expression(t, last);
+ if (t1 == t || t1 == last)
+ return first;
+ if (!__make<__list>(__root_))
+ return first;
+ if (init == 0)
+ init = __root_;
+ if (prev)
+ {
+ prev->__right_ = __root_;
+ __root_->__size_ = prev->__size_ + 1;
+ }
+ prev = __root_;
+ t = t1;
+ }
+ }
+ if (*t != 'E')
+ return first;
+ if (__make<__new_expr>(parsed_gs, is_array, has_init,
+ expr, type, init))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// pt <expression> <unresolved-name> # expr->name
+
+const char*
+__demangle_tree::__parse_arrow_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'p' && first[1] == 't')
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* expr = __root_;
+ const char* t1 = __parse_unresolved_name(t, last);
+ if (t1 != t)
+ {
+ if (__make<__arrow_expr>(expr, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// rc <type> <expression> # reinterpret_cast<type> (expression)
+
+const char*
+__demangle_tree::__parse_reinterpret_cast_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 'r' && first[1] == 'c')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ __node* type = __root_;
+ const char* t1 = __parse_expression(t, last);
+ if (t1 != t)
+ {
+ if (__make<__reinterpret_cast>(type, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// sc <type> <expression> # static_cast<type> (expression)
+
+const char*
+__demangle_tree::__parse_static_cast_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'c')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ __node* type = __root_;
+ const char* t1 = __parse_expression(t, last);
+ if (t1 != t)
+ {
+ if (__make<__static_cast>(type, __root_))
+ first = t1;
+ }
+ }
+ }
+ return first;
+}
+
+// st <type> # sizeof (a type)
+
+const char*
+__demangle_tree::__parse_sizeof_type_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 't')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_sizeof_expression>(__root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sZ <template-param> # size of a parameter pack
+
+const char*
+__demangle_tree::__parse_sizeof_param_pack_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T')
+ {
+ const char* t = __parse_template_param(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_sizeof_param_pack>(__root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sZ <function-param> # size of a function parameter pack
+
+const char*
+__demangle_tree::__parse_sizeof_function_param_pack_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f')
+ {
+ const char* t = __parse_function_param(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_sizeof_param_pack>(__root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// sp <expression> # pack expansion
+
+const char*
+__demangle_tree::__parse_pack_expansion(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 's' && first[1] == 'p')
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__pack_expansion>(__root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// te <expression> # typeid (expression)
+// ti <type> # typeid (type)
+
+const char*
+__demangle_tree::__parse_typeid_expr(const char* first, const char* last)
+{
+ 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);
+ else
+ t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__typeid>(__root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// tw <expression> # throw expression
+
+const char*
+__demangle_tree::__parse_throw_expr(const char* first, const char* last)
+{
+ if (last - first >= 3 && first[0] == 't' && first[1] == 'w')
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__throw>(__root_))
+ first = t;
+ }
+ }
+ return first;
+}
+
+// <expression> ::= <unary operator-name> <expression>
+// ::= <binary operator-name> <expression> <expression>
+// ::= <ternary operator-name> <expression> <expression> <expression>
+// ::= cl <expression>+ E # call
+// ::= cv <type> <expression> # conversion with one argument
+// ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+// ::= [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)
+// ::= [gs] dl <expression> # delete expression
+// ::= [gs] da <expression> # delete[] expression
+// ::= pp_ <expression> # prefix ++
+// ::= mm_ <expression> # prefix --
+// ::= ti <type> # typeid (type)
+// ::= te <expression> # typeid (expression)
+// ::= dc <type> <expression> # dynamic_cast<type> (expression)
+// ::= sc <type> <expression> # static_cast<type> (expression)
+// ::= cc <type> <expression> # const_cast<type> (expression)
+// ::= rc <type> <expression> # reinterpret_cast<type> (expression)
+// ::= st <type> # sizeof (a type)
+// ::= at <type> # alignof (a type)
+// ::= <template-param>
+// ::= <function-param>
+// ::= dt <expression> <unresolved-name> # expr.name
+// ::= pt <expression> <unresolved-name> # expr->name
+// ::= ds <expression> <expression> # expr.*expr
+// ::= sZ <template-param> # size of a parameter pack
+// ::= sZ <function-param> # size of a function parameter pack
+// ::= 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
+// ::= <expr-primary>
+
+const char*
+__demangle_tree::__parse_expression(const char* first, const char* last)
+{
+ 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':
+ t = __parse_expr_primary(first, last);
+ break;
+ case 'T':
+ t = __parse_template_param(first, last);
+ break;
+ case 'f':
+ t = __parse_function_param(first, last);
+ break;
+ case 'a':
+ if (t[1] == 't')
+ t = __parse_alignof_expr(first, last);
+ break;
+ case 'c':
+ switch (t[1])
+ {
+ case 'c':
+ t = __parse_const_cast_expr(first, last);
+ break;
+ case 'l':
+ t = __parse_call_expr(first, last);
+ break;
+ case 'v':
+ t = __parse_conversion_expr(first, last);
+ break;
+ }
+ break;
+ case 'd':
+ switch (t[1])
+ {
+ case 'a':
+ t = __parse_delete_array_expr(first, last);
+ break;
+ case 'c':
+ t = __parse_dynamic_cast_expr(first, last);
+ break;
+ case 'l':
+ t = __parse_delete_expr(first, last);
+ break;
+ case 's':
+ t = __parse_dot_star_expr(first, last);
+ break;
+ case 't':
+ t = __parse_dot_expr(first, last);
+ break;
+ }
+ break;
+ case 'm':
+ t = __parse_decrement_expr(first, last);
+ break;
+ case 'n':
+ switch (t[1])
+ {
+ case 'a':
+ case 'w':
+ t = __parse_new_expr(first, last);
+ break;
+ }
+ break;
+ case 'p':
+ switch (t[1])
+ {
+ case 'p':
+ t = __parse_increment_expr(first, last);
+ break;
+ case 't':
+ t = __parse_arrow_expr(first, last);
+ break;
+ }
+ break;
+ case 'r':
+ t = __parse_reinterpret_cast_expr(first, last);
+ break;
+ case 's':
+ switch (t[1])
+ {
+ case 'c':
+ t = __parse_static_cast_expr(first, last);
+ break;
+ case 'p':
+ t = __parse_pack_expansion(first, last);
+ break;
+ case 't':
+ t = __parse_sizeof_type_expr(first, last);
+ break;
+ case 'Z':
+ if (last - t >= 3)
+ {
+ switch (t[2])
+ {
+ case 'T':
+ t = __parse_sizeof_param_pack_expr(first, last);
+ break;
+ case 'f':
+ t = __parse_sizeof_function_param_pack_expr(first, last);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case 't':
+ switch (t[1])
+ {
+ case 'e':
+ case 'i':
+ t = __parse_typeid_expr(first, last);
+ break;
+ case 'r':
+ if (__make<__rethrow>())
+ t = first +2;
+ break;
+ case 'w':
+ t = __parse_throw_expr(first, last);
+ break;
+ }
+ break;
+ }
+ if ((!parsed_gs && t == first) || (parsed_gs && t == first+2))
+ {
+ int op;
+ t = __parse_operator_name(first, last, &op);
+ if (t == first)
+ first = __parse_unresolved_name(first, last);
+ else
+ first = t;
+ }
+ else
+ first = t;
+ }
+ return first;
+}
+
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+
+const char*
+__demangle_tree::__parse_array_type(const char* first, const char* last)
+{
+ if (first != last && *first == 'A' && first+1 != last)
+ {
+ if (first[1] == '_')
+ {
+ const char* t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__array>(__root_))
+ first = t;
+ }
+ }
+ else if ('1' <= first[1] && first[1] <= '9')
+ {
+ size_t dim = first[1] - '0';
+ const char* t = first+2;
+ for (; t != last && isdigit(*t); ++t)
+ dim = dim * 10 + *t - '0';
+ if (t != last && *t == '_')
+ {
+ const char* t2 = __parse_type(t+1, last);
+ if (t2 != t+1)
+ {
+ if (__make<__array>(__root_, dim))
+ first = t2;
+ }
+ }
+ }
+ else
+ {
+ const char* t = __parse_expression(first+1, last);
+ if (t != first+1 && t != last && *t == '_')
+ {
+ __node* dim = __root_;
+ const char* t2 = __parse_type(++t, last);
+ if (t2 != t)
+ {
+ if (__make<__array>(__root_, dim))
+ first = t2;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <class-enum-type> ::= <name>
+
+const char*
+__demangle_tree::__parse_class_enum_type(const char* first, const char* last)
+{
+ return __parse_name(first, last);
+}
+
+// <pointer-to-member-type> ::= M <class type> <member type>
+
+const char*
+__demangle_tree::__parse_pointer_to_member_type(const char* first, const char* last)
+{
+ if (first != last && *first == 'M')
+ {
+ const char* t = __parse_type(first+1, last);
+ if (t != first+1)
+ {
+ __node* class_type = __root_;
+ const char* t2 = __parse_type(t, last, true, true);
+ if (t2 != t)
+ {
+ if (__make<__pointer_to_member_type>(class_type, __root_))
+ first = t2;
+ }
+ }
+ }
+ 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)
+
+const char*
+__demangle_tree::__parse_decltype(const char* first, const char* last)
+{
+ if (last - first >= 4 && first[0] == 'D')
+ {
+ switch (first[1])
+ {
+ case 't':
+ case 'T':
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ {
+ if (__make<__decltype_node>(__root_))
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <template-param> ::= T_ # first template parameter
+// ::= T <parameter-2 non-negative number> _
+
+const char*
+__demangle_tree::__parse_template_param(const char* first, const char* last)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'T')
+ {
+ if (first[1] == '_')
+ {
+ if (__t_begin_ != __t_end_)
+ {
+ if (__make<__sub>(*__t_begin_))
+ first += 2;
+ }
+ else
+ {
+ if (__make<__sub>(size_t(0)))
+ {
+ first += 2;
+ __fix_forward_references_ = true;
+ }
+ }
+ }
+ else if (isdigit(first[1]))
+ {
+ const char* t = first+1;
+ size_t sub = *t - '0';
+ for (++t; t != last && isdigit(*t); ++t)
+ {
+ sub *= 10;
+ sub += *t - '0';
+ }
+ if (t == last || *t != '_')
+ return first;
+ ++sub;
+ if (sub < __t_end_ - __t_begin_)
+ {
+ if (__make<__sub>(__t_begin_[sub]))
+ first = t+1;
+ }
+ else
+ {
+ if (__make<__sub>(sub))
+ {
+ first = t+1;
+ __fix_forward_references_ = true;
+ }
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// extension:
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+
+const char*
+__demangle_tree::__parse_vector_type(const char* first, const char* last)
+{
+ if (last - first > 3 && first[0] == 'D' && first[1] == 'v')
+ {
+ if ('1' <= first[2] && first[2] <= '9')
+ {
+ const char* t = first+3;
+ while (*t != '_')
+ {
+ if (!isdigit(*t) || ++t == last)
+ return first;
+ }
+ const char* num = first + 2;
+ size_t sz = t - num;
+ if (++t != last)
+ {
+ if (*t != 'p')
+ {
+ const char* t1 = __parse_type(t, last);
+ if (t1 != t)
+ {
+ if (__make<__vector_type>(__root_, num, sz))
+ first = t1;
+ }
+ }
+ else
+ {
+ ++t;
+ if (__make<__vector_type>((__node*)0, num, sz))
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ __node* num = 0;
+ const char* t1 = first+2;
+ if (*t1 != '_')
+ {
+ const char* t = __parse_expression(t1, last);
+ if (t != t1)
+ num = __root_;
+ t1 = t;
+ }
+ if (t1 != last && *t1 == '_' && ++t1 != last)
+ {
+ const char* t = __parse_type(t1, last);
+ if (t != t1)
+ {
+ if (__make<__vector_type>(__root_, num))
+ first = t;
+ }
+ }
+ }
+ }
+ return first;
+}
+
+// <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 := <vector-type> # <vector-type> starts with Dv
+
+const char*
+__demangle_tree::__parse_type(const char* first, const char* last,
+ bool try_to_parse_template_args,
+ bool look_for_ref_quals)
+{
+ unsigned cv = 0;
+ const char* t = __parse_cv_qualifiers(first, last, cv, look_for_ref_quals);
+ if (t != first)
+ {
+ const char* t2 = __parse_type(t, last, try_to_parse_template_args);
+ if (t2 != t)
+ {
+ if (__make<__cv_qualifiers>(cv, __root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t2;
+ }
+ }
+ }
+ return first;
+ }
+ if (first != last)
+ {
+ switch (*first)
+ {
+ case 'A':
+ t = __parse_array_type(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ break;
+ case 'C':
+ t = __parse_type(first+1, last, try_to_parse_template_args);
+ if (t != first+1)
+ {
+ if (__make<__d_complex>(__root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ return first;
+ }
+ break;
+ case 'F':
+ t = __parse_function_type(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ break;
+ case 'G':
+ t = __parse_type(first+1, last, try_to_parse_template_args);
+ if (t != first+1)
+ {
+ if (__make<__imaginary>(__root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ return first;
+ }
+ break;
+ case 'M':
+ t = __parse_pointer_to_member_type(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ break;
+ case 'O':
+ t = __parse_type(first+1, last, try_to_parse_template_args);
+ if (t != first+1)
+ {
+ if (__make<__rvalue_reference_to>(__root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ return first;
+ }
+ break;
+ case 'P':
+ t = __parse_type(first+1, last, try_to_parse_template_args);
+ if (t != first+1)
+ {
+ if (__make<__pointer_to>(__root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ return first;
+ }
+ break;
+ case 'R':
+ t = __parse_type(first+1, last, try_to_parse_template_args);
+ if (t != first+1)
+ {
+ if (__make<__lvalue_reference_to>(__root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ return first;
+ }
+ break;
+ case 'T':
+ t = __parse_template_param(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ if (try_to_parse_template_args)
+ {
+ const char* t2 = __parse_template_args(t, last);
+ if (t2 != t)
+ {
+ if (__sub_end_ < __sub_cap_)
+ {
+ *__sub_end_++ = __root_;
+ first = t2;
+ }
+ else
+ __status_ = memory_alloc_failure;
+ }
+ else
+ {
+ first = t;
+ }
+ }
+ else
+ {
+ first = t;
+ }
+ }
+ }
+ break;
+ case 'U':
+ if (first+1 != last)
+ {
+ t = __parse_source_name(first+1, last);
+ if (t != first+1)
+ {
+ __node* name = __root_;
+ const char* t2 = __parse_type(t, last, try_to_parse_template_args);
+ if (t2 != t)
+ {
+ if (__make<__extended_qualifier>(name, __root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t2;
+ }
+ }
+ return first;
+ }
+ }
+ }
+ break;
+ case 'S':
+ if (first+1 != last && first[1] == 't')
+ {
+ t = __parse_class_enum_type(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ t = __parse_substitution(first, last);
+ if (t != first)
+ {
+ first = t;
+ // Parsed a substitution. If the substitution is a
+ // <template-param> it might be followed by <template-args>.
+ t = __parse_template_args(first, last);
+ if (t != first)
+ {
+ // Need to create substitution for <template-template-param> <template-args>
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ }
+ }
+ break;
+ case 'D':
+ if (first+1 != last)
+ {
+ switch (first[1])
+ {
+ case 'p':
+ t = __parse_type(first+2, last, try_to_parse_template_args);
+ if (t != first+1)
+ {
+ if (__make<__pack_expansion>(__root_))
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ return first;
+ }
+ break;
+ case 't':
+ case 'T':
+ t = __parse_decltype(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ return first;
+ }
+ break;
+ case 'v':
+ t = __parse_vector_type(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ return first;
+ }
+ break;
+ }
+ }
+ // drop through
+ default:
+ // must check for builtin-types before class-enum-types to avoid
+ // ambiguities with operator-names
+ t = __parse_builtin_type(first, last);
+ if (t != first)
+ {
+ first = t;
+ }
+ else
+ {
+ t = __parse_class_enum_type(first, last);
+ if (t != first)
+ {
+ if (__sub_end_ == __sub_cap_)
+ __status_ = memory_alloc_failure;
+ else
+ {
+ *__sub_end_++ = __root_;
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+
+const char*
+__demangle_tree::__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 && isdigit(*first))
+ ++first;
+ }
+ }
+ }
+ return first;
+}
+
+// <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*
+__demangle_tree::__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;
+}
+
+// <special-name> ::= TV <type> # virtual table
+// ::= TT <type> # VTT structure (construction vtable index)
+// ::= TI <type> # typeinfo structure
+// ::= TS <type> # typeinfo name (null-terminated byte string)
+// ::= Tc <call-offset> <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// # first call-offset is 'this' adjustment
+// # second call-offset is result adjustment
+// ::= T <call-offset> <base encoding>
+// # base is the nominal target function of thunk
+// ::= GV <object name> # Guard variable for one-time initialization
+// # No <type>
+// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+// extension ::= GR <object name> # reference temporary for object
+
+const char*
+__demangle_tree::__parse_special_name(const char* first, const char* last)
+{
+ 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);
+ if (t != first+2 && __make<__vtable>(__root_))
+ first = t;
+ break;
+ case 'T':
+ // TT <type> # VTT structure (construction vtable index)
+ t = __parse_type(first+2, last);
+ if (t != first+2 && __make<__VTT>(__root_))
+ first = t;
+ break;
+ case 'I':
+ // TI <type> # typeinfo structure
+ t = __parse_type(first+2, last);
+ if (t != first+2 && __make<__typeinfo>(__root_))
+ first = t;
+ break;
+ case 'S':
+ // TS <type> # typeinfo name (null-terminated byte string)
+ t = __parse_type(first+2, last);
+ if (t != first+2 && __make<__typeinfo_name>(__root_))
+ 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);
+ if (t != t1 && __make<__covariant_return_thunk>(__root_))
+ first = t;
+ }
+ break;
+ case 'C':
+ // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first
+ t = __parse_type(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t0 = __parse_number(t, last);
+ if (t0 != t && t0 != last && *t0 == '_')
+ {
+ const char* t1 = __parse_type(++t0, last);
+ if (t1 != t0)
+ {
+ if (__make<__construction_vtable>(__root_, op1))
+ first = t1;
+ }
+ }
+ }
+ 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);
+ if (t != t0)
+ {
+ if (first[2] == 'v')
+ {
+ if (__make<__virtual_thunk>(__root_))
+ first = t;
+ }
+ else
+ {
+ if (__make<__non_virtual_thunk>(__root_))
+ 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);
+ if (t != first+2 && __make<__guard_variable>(__root_))
+ first = t;
+ break;
+ case 'R':
+ // extension ::= GR <object name> # reference temporary for object
+ t = __parse_name(first+2, last);
+ if (t != first+2 && __make<__reference_temporary>(__root_))
+ first = t;
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <operator-name>
+// ::= aa # &&
+// ::= ad # & (unary)
+// ::= an # &
+// ::= aN # &=
+// ::= aS # =
+// ::= at # alignof (a type)
+// ::= az # alignof (an expression)
+// ::= cl # ()
+// ::= cm # ,
+// ::= co # ~
+// ::= cv <type> # (cast)
+// ::= da # delete[]
+// ::= de # * (unary)
+// ::= dl # delete
+// ::= dv # /
+// ::= dV # /=
+// ::= eo # ^
+// ::= eO # ^=
+// ::= eq # ==
+// ::= ge # >=
+// ::= gt # >
+// ::= ix # []
+// ::= le # <=
+// ::= 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 # >>=
+// ::= st # sizeof (a type)
+// ::= sz # sizeof (an expression)
+// ::= v <digit> <source-name> # vendor extended operator
+
+const char*
+__demangle_tree::__parse_operator_name(const char* first, const char* last, int* type)
+{
+ if (last - first >= 2)
+ {
+ switch (*first)
+ {
+ case 'a':
+ switch (first[1])
+ {
+ case 'a':
+ // &&
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_logical_and>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_logical_and>())
+ first += 2;
+ }
+ break;
+ case 'd':
+ // & (unary)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_addressof>(__root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_addressof>())
+ first += 2;
+ }
+ break;
+ case 'n':
+ // &
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_bit_and>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_bit_and>())
+ first += 2;
+ }
+ break;
+ case 'N':
+ // &=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_and_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_and_equal>())
+ first += 2;
+ }
+ break;
+ case 'S':
+ // =
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_equal>())
+ first += 2;
+ }
+ break;
+ case 't':
+ // alignof (a type)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_alignof_type>(__root_))
+ {
+ *type = -1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_alignof_type>())
+ first += 2;
+ }
+ break;
+ case 'z':
+ // alignof (an expression)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_alignof_expression>(__root_))
+ {
+ *type = -1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_alignof_expression>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'c':
+ switch (first[1])
+ {
+ case 'l':
+ // ()
+ if (__make<__operator_paren>())
+ {
+ first += 2;
+ if (type)
+ *type = -1;
+ }
+ break;
+ case 'm':
+ // ,
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_comma>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_comma>())
+ first += 2;
+ }
+ break;
+ case 'o':
+ // ~
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_tilda>(__root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_tilda>())
+ first += 2;
+ }
+ break;
+ case 'v':
+ // cast <type>
+ {
+ const char* t = __parse_type(first+2, last, false);
+ if (t != first+2)
+ {
+ __node* cast_type = __root_;
+ if (type)
+ {
+ const char* t2 = __parse_expression(t, last);
+ if (t2 != t)
+ {
+ if (__make<__operator_cast>(cast_type, __root_))
+ {
+ *type = -1;
+ first = t2;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_cast>(cast_type))
+ first = t;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case 'd':
+ switch (first[1])
+ {
+ case 'a':
+ // delete[]
+ if (__make<__operator_delete_array>())
+ {
+ first += 2;
+ if (type)
+ *type = -1;
+ }
+ break;
+ case 'e':
+ // * (unary)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_dereference>(__root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_dereference>())
+ first += 2;
+ }
+ break;
+ case 'l':
+ // delete
+ if (__make<__operator_delete>())
+ {
+ first += 2;
+ if (type)
+ *type = -1;
+ }
+ break;
+ case 'v':
+ // /
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_divide>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_divide>())
+ first += 2;
+ }
+ break;
+ case 'V':
+ // /=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_divide_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_divide_equal>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'e':
+ switch (first[1])
+ {
+ case 'o':
+ // ^
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_xor>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_xor>())
+ first += 2;
+ }
+ break;
+ case 'O':
+ // ^=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_xor_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_xor_equal>())
+ first += 2;
+ }
+ break;
+ case 'q':
+ // ==
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_equality>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_equality>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'g':
+ switch (first[1])
+ {
+ case 'e':
+ // >=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_greater_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_greater_equal>())
+ first += 2;
+ }
+ break;
+ case 't':
+ // >
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_greater>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_greater>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'i':
+ // []
+ if (first[1] == 'x' && __make<__operator_brackets>())
+ {
+ first += 2;
+ if (type)
+ *type = -1;
+ }
+ break;
+ case 'l':
+ switch (first[1])
+ {
+ case 'e':
+ // <=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_less_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_less_equal>())
+ first += 2;
+ }
+ break;
+ case 's':
+ // <<
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_left_shift>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_left_shift>())
+ first += 2;
+ }
+ break;
+ case 'S':
+ // <<=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_left_shift_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_left_shift_equal>())
+ first += 2;
+ }
+ break;
+ case 't':
+ // <
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_less>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_less>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'm':
+ switch (first[1])
+ {
+ case 'i':
+ // -
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_minus>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_minus>())
+ first += 2;
+ }
+ break;
+ case 'I':
+ // -=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_minus_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_minus_equal>())
+ first += 2;
+ }
+ break;
+ case 'l':
+ // *
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_times>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_times>())
+ first += 2;
+ }
+ break;
+ case 'L':
+ // *=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_times_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_times_equal>())
+ first += 2;
+ }
+ break;
+ case 'm':
+ // -- (postfix in <expression> context)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_decrement>(false, __root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_decrement>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'n':
+ switch (first[1])
+ {
+ case 'a':
+ // new[]
+ if (__make<__operator_new_array>())
+ {
+ first += 2;
+ if (type)
+ *type = -1;
+ }
+ break;
+ case 'e':
+ // !=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_not_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_not_equal>())
+ first += 2;
+ }
+ break;
+ case 'g':
+ // - (unary)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_negate>(__root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_negate>())
+ first += 2;
+ }
+ break;
+ case 't':
+ // !
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_logical_not>(__root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_logical_not>())
+ first += 2;
+ }
+ break;
+ case 'w':
+ // new
+ if (__make<__operator_new>())
+ {
+ first += 2;
+ if (type)
+ *type = -1;
+ }
+ break;
+ }
+ break;
+ case 'o':
+ switch (first[1])
+ {
+ case 'o':
+ // ||
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_logical_or>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_logical_or>())
+ first += 2;
+ }
+ break;
+ case 'r':
+ // |
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_bit_or>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_bit_or>())
+ first += 2;
+ }
+ break;
+ case 'R':
+ // |=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_or_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_or_equal>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'p':
+ switch (first[1])
+ {
+ case 'm':
+ // ->*
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_pointer_to_member>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_pointer_to_member>())
+ first += 2;
+ }
+ break;
+ case 'l':
+ // +
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_plus>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_plus>())
+ first += 2;
+ }
+ break;
+ case 'L':
+ // +=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_plus_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_plus_equal>())
+ first += 2;
+ }
+ break;
+ case 'p':
+ // ++ (postfix in <expression> context)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_increment>(false, __root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_increment>())
+ first += 2;
+ }
+ break;
+ case 's':
+ // + (unary)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_unary_plus>(__root_))
+ {
+ *type = 1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_unary_plus>())
+ first += 2;
+ }
+ break;
+ case 't':
+ // ->
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_arrow>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_arrow>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 'q':
+ // ?
+ if (first[1] == 'u')
+ {
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ __node* op2 = __root_;
+ const char* t3 = __parse_expression(t2, last);
+ if (t3 != t2)
+ {
+ if (__make<__operator_conditional>(op1, op2, __root_))
+ {
+ *type = 3;
+ first = t3;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_conditional>())
+ first += 2;
+ }
+ }
+ break;
+ case 'r':
+ switch (first[1])
+ {
+ case 'm':
+ // %
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_mod>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_mod>())
+ first += 2;
+ }
+ break;
+ case 'M':
+ // %=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_mod_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_mod_equal>())
+ first += 2;
+ }
+ break;
+ case 's':
+ // >>
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_right_shift>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_right_shift>())
+ first += 2;
+ }
+ break;
+ case 'S':
+ // >>=
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ __node* op1 = __root_;
+ const char* t2 = __parse_expression(t, last);
+ if (t != t2)
+ {
+ if (__make<__operator_right_shift_equal>(op1, __root_))
+ {
+ *type = 2;
+ first = t2;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_right_shift_equal>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ case 's':
+ switch (first[1])
+ {
+ case 't':
+ // sizeof (a type)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_sizeof_type>(__root_))
+ {
+ *type = -1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_sizeof_type>())
+ first += 2;
+ }
+ break;
+ case 'z':
+ // sizeof (an expression)
+ if (type)
+ {
+ const char* t = __parse_expression(first+2, last);
+ if (t != first+2)
+ {
+ if (__make<__operator_sizeof_expression>(__root_))
+ {
+ *type = -1;
+ first = t;
+ }
+ }
+ }
+ else
+ {
+ if (__make<__operator_sizeof_expression>())
+ first += 2;
+ }
+ break;
+ }
+ break;
+ }
+ }
+ return first;
+}
+
+// <source-name> ::= <positive length number> <identifier>
+
+const char*
+__demangle_tree::__parse_source_name(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ char c = *first;
+ if ('1' <= c && c <= '9' && first+1 != last)
+ {
+ const char* t = first+1;
+ size_t n = c - '0';
+ for (c = *t; '0' <= c && c <= '9'; c = *t)
+ {
+ n = n * 10 + c - '0';
+ if (++t == last)
+ return first;
+ }
+ if (last - t >= n && __make<__source_name>(t, n))
+ first = t + n;
+ }
+ }
+ return first;
+}
+
+// <unqualified-name> ::= <operator-name>
+// ::= <ctor-dtor-name>
+// ::= <source-name>
+// ::= <unnamed-type-name>
+
+const char*
+__demangle_tree::__parse_unqualified_name(const char* first, const char* last)
+{
+ const char* t = __parse_source_name(first, last);
+ if (t == first)
+ {
+ t = __parse_ctor_dtor_name(first, last);
+ if (t == first)
+ {
+ t = __parse_operator_name(first, last);
+ if (t == first)
+ first = __parse_unnamed_type_name(first, last);
+ else
+ first = t;
+ }
+ else
+ first = t;
+ }
+ else
+ first = t;
+ return first;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+// ::= St <unqualified-name> # ::std::
+// extension ::= StL<unqualified-name>
+
+const char*
+__demangle_tree::__parse_unscoped_name(const char* first, const char* last)
+{
+ if (last - first >= 2)
+ {
+ const char* t0 = first;
+ if (first[0] == 'S' && first[1] == 't')
+ {
+ t0 += 2;
+ if (t0 != last && *t0 == 'L')
+ ++t0;
+ }
+ const char* t1 = __parse_unqualified_name(t0, last);
+ if (t1 != t0)
+ {
+ if (t0 != first)
+ {
+ __node* name = __root_;
+ if (__make<__std_qualified_name>())
+ {
+ if (__make<__nested_delimeter>(__root_, name))
+ first = t1;
+ }
+ }
+ else
+ first = t1;
+ }
+ }
+ return first;
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+// ::= N [<CV-qualifiers>] <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*
+__demangle_tree::__parse_nested_name(const char* first, const char* last)
+{
+ if (first != last && *first == 'N')
+ {
+ unsigned cv = 0;
+ const char* t0 = __parse_cv_qualifiers(first+1, last, cv, true);
+ __node* prev = NULL;
+ if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't')
+ {
+ t0 += 2;
+ if (!__make<__std_qualified_name>())
+ return first;
+ prev = __root_;
+ }
+ while (t0 != last)
+ {
+ bool can_sub = true;
+ bool make_nested = true;
+ const char* t1;
+ switch (*t0)
+ {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t1 = __parse_source_name(t0, last);
+ if (t1 == t0 || t1 == last)
+ return first;
+ if (*t1 == 'M')
+ {
+ // This is a data-member-prefix
+ ++t1;
+ }
+ else if (*t1 == 'I')
+ {
+ // has following <template-args>
+ if (prev)
+ {
+ if (!__make<__nested_delimeter>(prev, __root_))
+ return first;
+ make_nested = false;
+ }
+ if (__sub_end_ == __sub_cap_)
+ {
+ __status_ = memory_alloc_failure;
+ return first;
+ }
+ else
+ *__sub_end_++ = __root_;
+ const char* t2 = __parse_template_args(t1, last);
+ if (t2 == t1)
+ return first;
+ t1 = t2;
+ }
+ break;
+ case 'D':
+ if (t0+1 != last && (t0[1] == 't' || t0[1] == 'T'))
+ {
+ t1 = __parse_decltype(t0, last);
+ break;
+ }
+ // check for Dt, DT here, else drop through
+ case 'C':
+ t1 = __parse_ctor_dtor_name(t0, last);
+ if (t1 == t0 || t1 == last)
+ return first;
+ if (*t1 == 'I')
+ {
+ // has following <template-args>
+ if (prev)
+ {
+ if (!__make<__nested_delimeter>(prev, __root_))
+ return first;
+ make_nested = false;
+ }
+ if (__sub_end_ == __sub_cap_)
+ {
+ __status_ = memory_alloc_failure;
+ return first;
+ }
+ else
+ *__sub_end_++ = __root_;
+ const char* t2 = __parse_template_args(t1, last);
+ if (t2 == t1)
+ return first;
+ t1 = t2;
+ }
+ break;
+ case 'U':
+ assert(!"__parse_nested_name U");
+ // could have following <template-args>
+ break;
+ case 'T':
+ t1 = __parse_template_param(t0, last);
+ if (t1 == t0 || t1 == last)
+ return first;
+ if (*t1 == 'I')
+ {
+ // has following <template-args>
+ if (prev)
+ {
+ if (!__make<__nested_delimeter>(prev, __root_))
+ return first;
+ make_nested = false;
+ }
+ if (__sub_end_ == __sub_cap_)
+ {
+ __status_ = memory_alloc_failure;
+ return first;
+ }
+ else
+ *__sub_end_++ = __root_;
+ const char* t2 = __parse_template_args(t1, last);
+ if (t2 == t1)
+ return first;
+ t1 = t2;
+ }
+ break;
+ case 'S':
+ t1 = __parse_substitution(t0, last);
+ if (t1 == t0 || t1 == last)
+ return first;
+ if (*t1 == 'I')
+ {
+ const char* t2 = __parse_template_args(t1, last);
+ if (t2 == t1)
+ return first;
+ t1 = t2;
+ }
+ else
+ can_sub = false;
+ break;
+ case 'L':
+ // extension: ignore L here
+ ++t0;
+ continue;
+ default:
+ t1 = __parse_operator_name(t0, last);
+ if (t1 == t0 || t1 == last)
+ return first;
+ if (*t1 == 'I')
+ {
+ // has following <template-args>
+ if (prev)
+ {
+ if (!__make<__nested_delimeter>(prev, __root_))
+ return first;
+ make_nested = false;
+ }
+ if (__sub_end_ == __sub_cap_)
+ {
+ __status_ = memory_alloc_failure;
+ return first;
+ }
+ else
+ *__sub_end_++ = __root_;
+ const char* t2 = __parse_template_args(t1, last);
+ if (t2 == t1)
+ return first;
+ t1 = t2;
+ }
+ break;
+ }
+ if (t1 == t0 || t1 == last)
+ return first;
+ if (prev && make_nested)
+ {
+ if (!__make<__nested_delimeter>(prev, __root_))
+ return first;
+ can_sub = true;
+ }
+ if (can_sub && *t1 != 'E')
+ {
+ if (__sub_end_ == __sub_cap_)
+ {
+ __status_ = memory_alloc_failure;
+ return first;
+ }
+ else
+ *__sub_end_++ = __root_;
+ }
+ if (*t1 == 'E')
+ {
+ if (cv != 0)
+ {
+ if (!__make<__cv_qualifiers>(cv, __root_))
+ return first;
+ }
+ first = t1+1;
+ break;
+ }
+ prev = __root_;
+ t0 = t1;
+ }
+ }
+ 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*
+__demangle_tree::__parse_template_arg(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t;
+ switch (*first)
+ {
+ case 'X':
+ t = __parse_expression(first+1, last);
+ if (t != first+1)
+ {
+ if (t != last && *t == 'E')
+ first = t+1;
+ }
+ break;
+ case 'J':
+ t = first+1;
+ if (t == last)
+ return first;
+ if (*t == 'E')
+ {
+ if (__make<__list>((__node*)0))
+ first = t+1;
+ }
+ else
+ {
+ __node* list = NULL;
+ __node* prev = NULL;
+ do
+ {
+ const char* t2 = __parse_template_arg(t, last);
+ if (t2 == t || !__make<__list>(__root_))
+ return first;
+ if (list == 0)
+ list = __root_;
+ if (prev)
+ {
+ prev->__right_ = __root_;
+ __root_->__size_ = prev->__size_ + 1;
+ }
+ prev = __root_;
+ t = t2;
+ } while (t != last && *t != 'E');
+ first = t+1;
+ __root_ = list;
+ }
+ break;
+ case 'L':
+ // <expr-primary> or LZ <encoding> E
+ if (first+1 != last && first[1] == 'Z')
+ {
+ t = __parse_encoding(first+2, last);
+ if (t != first+2 && t != last && *t == 'E')
+ first = t+1;
+ }
+ else
+ first = __parse_expr_primary(first, last);
+ break;
+ default:
+ // <type>
+ first = __parse_type(first, last);
+ break;
+ }
+ }
+ return first;
+}
+
+// <template-args> ::= I <template-arg>* E
+// extension, the abi says <template-arg>+
+
+const char*
+__demangle_tree::__parse_template_args(const char* first, const char* last)
+{
+ if (last - first >= 2 && *first == 'I')
+ {
+ __node* args = NULL;
+ __node* prev = NULL;
+ __node* name = __root_;
+ if (__tag_templates_)
+ __t_end_ = __t_begin_;
+ const char* t = first+1;
+ while (*t != 'E')
+ {
+ bool prev_tag_templates = __tag_templates_;
+ __node** prev_t_begin = __t_begin_;
+ __node** prev_t_end = __t_end_;
+ if (__tag_templates_)
+ __t_begin_ = __t_end_;
+ const char* t2 = __parse_template_arg(t, last);
+ if (prev_tag_templates)
+ {
+ __tag_templates_ = prev_tag_templates;
+ __t_begin_ = prev_t_begin;
+ __t_end_ = prev_t_end;
+ }
+ if (t2 == t || t2 == last)
+ break;
+ if (!__make<__list>(__root_))
+ return first;
+ if (args == 0)
+ args = __root_;
+ if (prev)
+ {
+ prev->__right_ = __root_;
+ __root_->__size_ = prev->__size_ + 1;
+ }
+ prev = __root_;
+ if (__tag_templates_)
+ {
+ if (__t_end_ == __t_cap_)
+ {
+ __status_ = memory_alloc_failure;
+ return first;
+ }
+ if (__root_->__left_)
+ *__t_end_++ = __root_->__left_;
+ else
+ *__t_end_++ = __root_;
+ }
+ t = t2;
+ }
+ if (t != last && *t == 'E')
+ {
+ if (__make<__template_args>(name, args))
+ first = t+1;
+ }
+ }
+ return first;
+}
+
+// <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*
+__demangle_tree::__parse_substitution(const char* first, const char* last)
+{
+ if (last - first >= 2)
+ {
+ if (*first == 'S')
+ {
+ switch (first[1])
+ {
+ case 'a':
+ if (__make<__sub_allocator>())
+ first += 2;
+ break;
+ case 'b':
+ if (__make<__sub_basic_string>())
+ first += 2;
+ break;
+ case 's':
+ if (__make<__sub_string>())
+ first += 2;
+ break;
+ case 'i':
+ if (__make<__sub_istream>())
+ first += 2;
+ break;
+ case 'o':
+ if (__make<__sub_ostream>())
+ first += 2;
+ break;
+ case 'd':
+ if (__make<__sub_iostream>())
+ first += 2;
+ break;
+ case '_':
+ if (__sub_begin_ != __sub_end_)
+ {
+ if (__make<__sub>(*__sub_begin_))
+ first += 2;
+ }
+ break;
+ default:
+ if (isdigit(first[1]) || isupper(first[1]))
+ {
+ size_t sub = 0;
+ const char* t = first+1;
+ if (isdigit(*t))
+ sub = *t - '0';
+ else
+ sub = *t - 'A' + 10;
+ for (++t; t != last && (isdigit(*t) || isupper(*t)); ++t)
+ {
+ sub *= 36;
+ if (isdigit(*t))
+ sub += *t - '0';
+ else
+ sub += *t - 'A' + 10;
+ }
+ if (t == last || *t != '_')
+ return first;
+ ++sub;
+ if (sub < __sub_end_ - __sub_begin_)
+ {
+ if (__make<__sub>(__sub_begin_[sub]))
+ first = t+1;
+ }
+ }
+ break;
+ }
+ }
+ }
+ return first;
+}
+
+// <name> ::= <nested-name>
+// ::= <local-name> # See Scope Encoding below
+// ::= <unscoped-template-name> <template-args>
+// ::= <unscoped-name>
+
+const char*
+__demangle_tree::__parse_name(const char* first, const char* last)
+{
+ if (first != last)
+ {
+ const char* t0 = first;
+ // extension: ignore L here
+ if (*t0 == 'L')
+ ++t0;
+ const char* t = __parse_nested_name(t0, last);
+ if (t == t0)
+ {
+ t = __parse_local_name(t0, last);
+ if (t == t0)
+ {
+ // not <nested-name> nor <local-name>
+ // Try to parse <unscoped-template-name> <template-args> or
+ // <unscoped-name> which are nearly ambiguous.
+ // This logic occurs nowhere else.
+ if (last - t0 >= 2)
+ {
+ if (t0[0] == 'S' && (t0[1] == '_' ||
+ isdigit(t0[1]) ||
+ isupper(t0[1]) ||
+ t0[1] == 'a' ||
+ t0[1] == 'b'))
+ {
+ t = __parse_substitution(t0, last);
+ if (t != t0)
+ {
+ const char* t2 = __parse_template_args(t, last);
+ if (t2 != t)
+ first = t2;
+ }
+ }
+ else // Not a substitution, except maybe St
+ {
+ t = __parse_unscoped_name(t0, last);
+ if (t != t0)
+ {
+ // unscoped-name might be <unscoped-template-name>
+ if (t != last && *t == 'I')
+ {
+ if (__sub_end_ == __sub_cap_)
+ {
+ __status_ = memory_alloc_failure;
+ return first;
+ }
+ *__sub_end_++ = __root_;
+ const char* t2 = __parse_template_args(t, last);
+ if (t2 != t)
+ first = t2;
+ }
+ else
+ {
+ // <unscoped-name>
+ first = t;
+ }
+ }
+ }
+ }
+ }
+ else
+ first = t;
+ }
+ else
+ first = t;
+ }
+ return first;
+}
+
+// extension
+// <dot-suffix> := .<anything and everything>
+
+const char*
+__demangle_tree::__parse_dot_suffix(const char* first, const char* last)
+{
+ if (first != last && *first == '.')
+ {
+ if (__make<__dot_suffix>(__root_, first, last-first))
+ first = last;
+ }
+ return first;
+}
+
+// <encoding> ::= <function name> <bare-function-type>
+// ::= <data name>
+// ::= <special-name>
+
+const char*
+__demangle_tree::__parse_encoding(const char* first, const char* last)
+{
+ const char* t = __parse_name(first, last);
+ if (t != first)
+ {
+ if (t != last && *t != 'E' && *t != '.')
+ {
+ __node* name = __root_;
+ bool has_return = name->ends_with_template(true) &&
+ !name->is_ctor_dtor_conv();
+ __node* ret = NULL;
+ const char* t2;
+ __tag_templates_ = false;
+ if (has_return)
+ {
+ t2 = __parse_type(t, last);
+ if (t2 != t)
+ {
+ ret = __root_;
+ t = t2;
+ }
+ else
+ return first;
+ }
+ t2 = __parse_bare_function_type(t, last);
+ if (t2 != t)
+ {
+ if (dynamic_cast<__void*>(__root_->__left_) != NULL)
+ __root_->__left_ = NULL;
+ if (__make<__function_signature>(ret, __root_))
+ {
+ __node* cv = name->extract_cv(name);
+ if (__make<__function>(name, __root_))
+ {
+ if (cv)
+ {
+ cv->__left_ = __root_;
+ cv->__size_ <<= 5;
+ __root_ = cv;
+ }
+ first = t2;
+ }
+ }
+ }
+ __tag_templates_ = true;
+ }
+ else
+ first = t;
+ }
+ else
+ first = __parse_special_name(first, last);
+ return first;
+}
+
+// <mangled-name> ::= _Z<encoding>
+// ::= <type>
+
+void
+__demangle_tree::__parse()
+{
+ if (__mangled_name_begin_ == __mangled_name_end_)
+ {
+ __status_ = invalid_mangled_name;
+ return;
+ }
+ const char* t = NULL;
+ if (__mangled_name_end_ - __mangled_name_begin_ >= 2 &&
+ __mangled_name_begin_[0] == '_' &&
+ __mangled_name_begin_[1] == 'Z')
+ {
+ t = __parse_encoding(__mangled_name_begin_+2, __mangled_name_end_);
+ if (t != __mangled_name_begin_+2 && t != __mangled_name_end_ && *t == '.')
+ t = __parse_dot_suffix(t, __mangled_name_end_);
+ }
+ else
+ t = __parse_type(__mangled_name_begin_, __mangled_name_end_);
+ if (t == __mangled_name_end_ && __root_)
+ {
+ if (__fix_forward_references_)
+ {
+ if (__root_->fix_forward_references(__t_begin_, __t_end_))
+ __status_ = success;
+ }
+ else
+ __status_ = success;
+ }
+}
+
+__demangle_tree
+__demangle(const char* mangled_name, char* buf, size_t bs)
+{
+ __demangle_tree t(mangled_name, buf, bs);
+ if (t.__status() == invalid_mangled_name)
+ t.__parse();
+ return t;
+}
+
+__demangle_tree
+__demangle(const char* mangled_name)
+{
+ return __demangle(mangled_name, 0, 0);
+}
+
+char*
+__demangle(__demangle_tree dmg_tree, char* buf, size_t* n, int* status)
+{
+ if (dmg_tree.__status() != success)
+ {
+ if (status)
+ *status = dmg_tree.__status();
+ return NULL;
+ }
+#ifdef DEBUGGING
+display(dmg_tree.__root_);
+printf("\n");
+#endif
+ const size_t bs = buf == NULL ? 0 : *n;
+ ptrdiff_t sm = dmg_tree.__mangled_name_end_ - dmg_tree.__mangled_name_begin_;
+ ptrdiff_t est = sm + 60 * (
+ (dmg_tree.__node_end_ - dmg_tree.__node_begin_) +
+ (dmg_tree.__sub_end_ - dmg_tree.__sub_begin_) +
+ (dmg_tree.__t_end_ - dmg_tree.__t_begin_));
+ const unsigned N = 4096;
+ char tmp[N];
+ ptrdiff_t s;
+ if (est <= bs)
+ {
+ char* e = dmg_tree.__get_demangled_name(buf);
+ *e++ = '\0';
+ s = e - buf;
+ }
+ else if (est <= N)
+ {
+ char* e = dmg_tree.__get_demangled_name(tmp);
+ *e++ = '\0';
+ s = e - tmp;
+ }
+ else
+ s = dmg_tree.size() + 1;
+ if (s > bs)
+ {
+ buf = static_cast<char*>(realloc(buf, s));
+ if (buf == NULL)
+ {
+ if (status)
+ *status = memory_alloc_failure;
+ return NULL;
+ }
+ if (n)
+ *n = s;
+ }
+ if (est > bs)
+ {
+ if (est <= N)
+ strncpy(buf, tmp, s);
+ else
+ *dmg_tree.__get_demangled_name(buf) = '\0';
+ }
+ if (status)
+ *status = success;
+ return buf;
+}
+
+} // __libcxxabi
+
+#pragma GCC visibility pop
+#pragma GCC visibility push(default)
+
+extern "C"
+{
+
+char*
+__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status)
+{
+ if (mangled_name == NULL || (buf != NULL && n == NULL))
+ {
+ if (status)
+ *status = __libcxxabi::invalid_args;
+ return NULL;
+ }
+ const size_t bs = 64 * 1024;
+ __attribute((aligned(16))) char static_buf[bs];
+
+ buf = __libcxxabi::__demangle(__libcxxabi::__demangle(mangled_name,
+ static_buf, bs),
+ buf, n, status);
+ return buf;
+}
+
+} // extern "C"
+
+} // abi
diff --git a/system/lib/libcxxabi/src/cxa_exception.cpp b/system/lib/libcxxabi/src/cxa_exception.cpp
new file mode 100644
index 00000000..b866f9e4
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_exception.cpp
@@ -0,0 +1,622 @@
+//===------------------------- cxa_exception.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the "Exception Handling APIs"
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxxabi.h"
+
+#include <exception> // for std::terminate
+#include <cstdlib> // for malloc, free
+#include <string> // for memset
+#include <pthread.h>
+
+#include "cxa_exception.hpp"
+#include "cxa_handlers.hpp"
+
+// +---------------------------+-----------------------------+---------------+
+// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
+// +---------------------------+-----------------------------+---------------+
+// ^
+// |
+// +-------------------------------------------------------+
+// |
+// +---------------------------+-----------------------------+
+// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
+// +---------------------------+-----------------------------+
+
+namespace __cxxabiv1 {
+
+#pragma GCC visibility push(default)
+
+// Utility routines
+static
+inline
+__cxa_exception*
+cxa_exception_from_thrown_object(void* thrown_object)
+{
+ return static_cast<__cxa_exception*>(thrown_object) - 1;
+}
+
+// Note: This is never called when exception_header is masquerading as a
+// __cxa_dependent_exception.
+static
+inline
+void*
+thrown_object_from_cxa_exception(__cxa_exception* exception_header)
+{
+ return static_cast<void*>(exception_header + 1);
+}
+
+// Get the exception object from the unwind pointer.
+// Relies on the structure layout, where the unwind pointer is right in
+// front of the user's exception object
+static
+inline
+__cxa_exception*
+cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception)
+{
+ return cxa_exception_from_thrown_object(unwind_exception + 1 );
+}
+
+static
+inline
+size_t
+cxa_exception_size_from_exception_thrown_size(size_t size)
+{
+ return size + sizeof (__cxa_exception);
+}
+
+static void setExceptionClass(_Unwind_Exception* unwind_exception) {
+ unwind_exception->exception_class = kOurExceptionClass;
+}
+
+static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) {
+ unwind_exception->exception_class = kOurDependentExceptionClass;
+}
+
+// Is it one of ours?
+static bool isOurExceptionClass(const _Unwind_Exception* unwind_exception) {
+ return (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+}
+
+static bool isDependentException(_Unwind_Exception* unwind_exception) {
+ return (unwind_exception->exception_class & 0xFF) == 0x01;
+}
+
+// This does not need to be atomic
+static inline int incrementHandlerCount(__cxa_exception *exception) {
+ return ++exception->handlerCount;
+}
+
+// This does not need to be atomic
+static inline int decrementHandlerCount(__cxa_exception *exception) {
+ return --exception->handlerCount;
+}
+
+#include "fallback_malloc.ipp"
+
+// Allocate some memory from _somewhere_
+static void *do_malloc(size_t size) {
+ void *ptr = std::malloc(size);
+ if (NULL == ptr) // if malloc fails, fall back to emergency stash
+ ptr = fallback_malloc(size);
+ return ptr;
+}
+
+static void do_free(void *ptr) {
+ is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr);
+}
+
+/*
+ If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
+ stored in exc is called. Otherwise the exceptionDestructor stored in
+ exc is called, and then the memory for the exception is deallocated.
+
+ This is never called for a __cxa_dependent_exception.
+*/
+static
+void
+exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
+{
+ __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception);
+ if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
+ std::__terminate(exception_header->terminateHandler);
+ // Just in case there exists a dependent exception that is pointing to this,
+ // check the reference count and only destroy this if that count goes to zero.
+ __cxa_decrement_exception_refcount(unwind_exception + 1);
+}
+
+static LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) {
+// Section 2.5.3 says:
+// * For purposes of this ABI, several things are considered exception handlers:
+// ** A terminate() call due to a throw.
+// and
+// * Upon entry, Following initialization of the catch parameter,
+// a handler must call:
+// * void *__cxa_begin_catch(void *exceptionObject );
+ (void) __cxa_begin_catch(&exception_header->unwindHeader);
+ std::__terminate(exception_header->terminateHandler);
+}
+
+extern "C" {
+
+// Allocate a __cxa_exception object, and zero-fill it.
+// Reserve "thrown_size" bytes on the end for the user's exception
+// object. Zero-fill the object. If memory can't be allocated, call
+// std::terminate. Return a pointer to the memory to be used for the
+// user's exception object.
+void * __cxa_allocate_exception (size_t thrown_size) throw() {
+ size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
+ __cxa_exception* exception_header = static_cast<__cxa_exception*>(do_malloc(actual_size));
+ if (NULL == exception_header)
+ std::terminate();
+ std::memset(exception_header, 0, actual_size);
+ return thrown_object_from_cxa_exception(exception_header);
+}
+
+
+// Free a __cxa_exception object allocated with __cxa_allocate_exception.
+void __cxa_free_exception (void * thrown_object) throw() {
+ do_free(cxa_exception_from_thrown_object(thrown_object));
+}
+
+
+// This function shall allocate a __cxa_dependent_exception and
+// return a pointer to it. (Really to the object, not past its' end).
+// Otherwise, it will work like __cxa_allocate_exception.
+void * __cxa_allocate_dependent_exception () {
+ size_t actual_size = sizeof(__cxa_dependent_exception);
+ void *ptr = do_malloc(actual_size);
+ if (NULL == ptr)
+ std::terminate();
+ std::memset(ptr, 0, actual_size);
+ return ptr;
+}
+
+
+// This function shall free a dependent_exception.
+// It does not affect the reference count of the primary exception.
+void __cxa_free_dependent_exception (void * dependent_exception) {
+ do_free(dependent_exception);
+}
+
+
+// 2.4.3 Throwing the Exception Object
+/*
+After constructing the exception object with the throw argument value,
+the generated code calls the __cxa_throw runtime library routine. This
+routine never returns.
+
+The __cxa_throw routine will do the following:
+
+* Obtain the __cxa_exception header from the thrown exception object address,
+which can be computed as follows:
+ __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1);
+* Save the current unexpected_handler and terminate_handler in the __cxa_exception header.
+* Save the tinfo and dest arguments in the __cxa_exception header.
+* Set the exception_class field in the unwind header. This is a 64-bit value
+representing the ASCII string "XXXXC++\0", where "XXXX" is a
+vendor-dependent string. That is, for implementations conforming to this
+ABI, the low-order 4 bytes of this 64-bit value will be "C++\0".
+* Increment the uncaught_exception flag.
+* Call _Unwind_RaiseException in the system unwind library, Its argument is the
+pointer to the thrown exception, which __cxa_throw itself received as an argument.
+__Unwind_RaiseException begins the process of stack unwinding, described
+in Section 2.5. In special cases, such as an inability to find a
+handler, _Unwind_RaiseException may return. In that case, __cxa_throw
+will call terminate, assuming that there was no handler for the
+exception.
+*/
+LIBCXXABI_NORETURN
+void
+__cxa_throw(void* thrown_object, std::type_info* tinfo, void (*dest)(void*))
+{
+ __cxa_eh_globals *globals = __cxa_get_globals();
+ __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
+
+ exception_header->unexpectedHandler = std::get_unexpected();
+ exception_header->terminateHandler = std::get_terminate();
+ exception_header->exceptionType = tinfo;
+ exception_header->exceptionDestructor = dest;
+ setExceptionClass(&exception_header->unwindHeader);
+ exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety.
+ globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local
+
+ exception_header->unwindHeader.exception_cleanup = exception_cleanup_func;
+#if __arm__
+ _Unwind_SjLj_RaiseException(&exception_header->unwindHeader);
+#else
+ _Unwind_RaiseException(&exception_header->unwindHeader);
+#endif
+ // This only happens when there is no handler, or some unexpected unwinding
+ // error happens.
+ failed_throw(exception_header);
+}
+
+
+// 2.5.3 Exception Handlers
+/*
+The adjusted pointer is computed by the personality routine during phase 1
+ and saved in the exception header (either __cxa_exception or
+ __cxa_dependent_exception).
+
+ Requires: exception is native
+*/
+void*
+__cxa_get_exception_ptr(void* unwind_exception) throw()
+{
+ return cxa_exception_from_exception_unwind_exception
+ (
+ static_cast<_Unwind_Exception*>(unwind_exception)
+ )->adjustedPtr;
+}
+
+/*
+This routine can catch foreign or native exceptions. If native, the exception
+can be a primary or dependent variety. This routine may remain blissfully
+ignorant of whether the native exception is primary or dependent.
+
+If the exception is native:
+* Increment's the exception's handler count.
+* Push the exception on the stack of currently-caught exceptions if it is not
+ already there (from a rethrow).
+* Decrements the uncaught_exception count.
+* Returns the adjusted pointer to the exception object, which is stored in
+ the __cxa_exception by the personality routine.
+
+If the exception is foreign, this means it did not originate from one of throw
+routines. The foreign exception does not necessarily have a __cxa_exception
+header. However we can catch it here with a catch (...), or with a call
+to terminate or unexpected during unwinding.
+* Do not try to increment the exception's handler count, we don't know where
+ it is.
+* Push the exception on the stack of currently-caught exceptions only if the
+ stack is empty. The foreign exception has no way to link to the current
+ top of stack. If the stack is not empty, call terminate. Even with an
+ empty stack, this is hacked in by pushing a pointer to an imaginary
+ __cxa_exception block in front of the foreign exception. It would be better
+ if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it
+ doesn't. It has a stack of __cxa_exception (which has a next* in it).
+* Do not decrement the uncaught_exception count because we didn't increment it
+ in __cxa_throw (or one of our rethrow functions).
+* If we haven't terminated, assume the exception object is just past the
+ _Unwind_Exception and return a pointer to that.
+*/
+void*
+__cxa_begin_catch(void* unwind_arg) throw()
+{
+ _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
+ bool native_exception = isOurExceptionClass(unwind_exception);
+ __cxa_eh_globals* globals = __cxa_get_globals();
+ // exception_header is a hackish offset from a foreign exception, but it
+ // works as long as we're careful not to try to access any __cxa_exception
+ // parts.
+ __cxa_exception* exception_header =
+ cxa_exception_from_exception_unwind_exception
+ (
+ static_cast<_Unwind_Exception*>(unwind_exception)
+ );
+ if (native_exception)
+ {
+ // Increment the handler count, removing the flag about being rethrown
+ exception_header->handlerCount = exception_header->handlerCount < 0 ?
+ -exception_header->handlerCount + 1 : exception_header->handlerCount + 1;
+ // place the exception on the top of the stack if it's not already
+ // there by a previous rethrow
+ if (exception_header != globals->caughtExceptions)
+ {
+ exception_header->nextException = globals->caughtExceptions;
+ globals->caughtExceptions = exception_header;
+ }
+ globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
+ return exception_header->adjustedPtr;
+ }
+ // Else this is a foreign exception
+ // If the caughtExceptions stack is not empty, terminate
+ if (globals->caughtExceptions != 0)
+ std::terminate();
+ // Push the foreign exception on to the stack
+ globals->caughtExceptions = exception_header;
+ return unwind_exception + 1;
+}
+
+
+/*
+Upon exit for any reason, a handler must call:
+ void __cxa_end_catch ();
+
+This routine can be called for either a native or foreign exception.
+For a native exception:
+* Locates the most recently caught exception and decrements its handler count.
+* Removes the exception from the caught exception stack, if the handler count goes to zero.
+* If the handler count goes down to zero, and the exception was not re-thrown
+ by throw, it locates the primary exception (which may be the same as the one
+ it's handling) and decrements its reference count. If that reference count
+ goes to zero, the function destroys the exception. In any case, if the current
+ exception is a dependent exception, it destroys that.
+
+For a foreign exception:
+* If it has been rethrown, there is nothing to do.
+* Otherwise delete the exception and pop the catch stack to empty.
+*/
+void __cxa_end_catch()
+{
+ static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception),
+ "sizeof(__cxa_exception) must be equal to sizeof(__cxa_dependent_exception)");
+ __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
+ __cxa_exception* exception_header = globals->caughtExceptions;
+ // If we've rethrown a foreign exception, then globals->caughtExceptions
+ // will have been made an empty stack by __cxa_rethrow() and there is
+ // nothing more to be done. Do nothing!
+ if (NULL != exception_header)
+ {
+ bool native_exception = isOurExceptionClass(&exception_header->unwindHeader);
+ if (native_exception)
+ {
+ // This is a native exception
+ if (exception_header->handlerCount < 0)
+ {
+ // The exception has been rethrown by __cxa_rethrow, so don't delete it
+ if (0 == incrementHandlerCount(exception_header))
+ {
+ // Remove from the chain of uncaught exceptions
+ globals->caughtExceptions = exception_header->nextException;
+ // but don't destroy
+ }
+ // Keep handlerCount negative in case there are nested catch's
+ // that need to be told that this exception is rethrown. Don't
+ // erase this rethrow flag until the exception is recaught.
+ }
+ else
+ {
+ // The native exception has not been rethrown
+ if (0 == decrementHandlerCount(exception_header))
+ {
+ // Remove from the chain of uncaught exceptions
+ globals->caughtExceptions = exception_header->nextException;
+ // Destroy this exception, being careful to distinguish
+ // between dependent and primary exceptions
+ if (isDependentException(&exception_header->unwindHeader))
+ {
+ // Reset exception_header to primaryException and deallocate the dependent exception
+ __cxa_dependent_exception* dep_exception_header =
+ reinterpret_cast<__cxa_dependent_exception*>(exception_header);
+ exception_header =
+ cxa_exception_from_thrown_object(dep_exception_header->primaryException);
+ __cxa_free_dependent_exception(dep_exception_header);
+ }
+ // Destroy the primary exception only if its referenceCount goes to 0
+ // (this decrement must be atomic)
+ __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header));
+ }
+ }
+ }
+ else
+ {
+ // The foreign exception has not been rethrown. Pop the stack
+ // and delete it. If there are nested catch's and they try
+ // to touch a foreign exception in any way, that is undefined
+ // behavior. They likely can't since the only way to catch
+ // a foreign exception is with catch (...)!
+ _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader);
+ globals->caughtExceptions = 0;
+ }
+ }
+}
+
+// Note: exception_header may be masquerading as a __cxa_dependent_exception
+// and that's ok. exceptionType is there too.
+// However watch out for foreign exceptions. Return null for them.
+std::type_info * __cxa_current_exception_type() {
+// get the current exception
+ __cxa_eh_globals *globals = __cxa_get_globals_fast();
+ if (NULL == globals)
+ return NULL; // If there have never been any exceptions, there are none now.
+ __cxa_exception *exception_header = globals->caughtExceptions;
+ if (NULL == exception_header)
+ return NULL; // No current exception
+ if (!isOurExceptionClass(&exception_header->unwindHeader))
+ return NULL;
+ return exception_header->exceptionType;
+}
+
+// 2.5.4 Rethrowing Exceptions
+/* This routine can rethrow native or foreign exceptions.
+If the exception is native:
+* marks the exception object on top of the caughtExceptions stack
+ (in an implementation-defined way) as being rethrown.
+* If the caughtExceptions stack is empty, it calls terminate()
+ (see [C++FDIS] [except.throw], 15.1.8).
+* It then calls _Unwind_RaiseException which should not return
+ (terminate if it does).
+ Note: exception_header may be masquerading as a __cxa_dependent_exception
+ and that's ok.
+*/
+LIBCXXABI_NORETURN
+void
+__cxa_rethrow()
+{
+ __cxa_eh_globals* globals = __cxa_get_globals();
+ __cxa_exception* exception_header = globals->caughtExceptions;
+ if (NULL == exception_header)
+ std::terminate(); // throw; called outside of a exception handler
+ bool native_exception = isOurExceptionClass(&exception_header->unwindHeader);
+ if (native_exception)
+ {
+ // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
+ exception_header->handlerCount = -exception_header->handlerCount;
+ globals->uncaughtExceptions += 1;
+ // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
+ }
+ else // this is a foreign exception
+ {
+ // The only way to communicate to __cxa_end_catch that we've rethrown
+ // a foreign exception, so don't delete us, is to pop the stack here
+ // which must be empty afterwards. Then __cxa_end_catch will do
+ // nothing
+ globals->caughtExceptions = 0;
+ }
+#if __arm__
+ (void) _Unwind_SjLj_Resume_or_Rethrow(&exception_header->unwindHeader);
+#else
+ (void)_Unwind_RaiseException(&exception_header->unwindHeader);
+#endif
+
+ // If we get here, some kind of unwinding error has occurred.
+ // There is some weird code generation bug happening with
+ // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn)
+ // If we call failed_throw here. Turns up with -O2 or higher, and -Os.
+ __cxa_begin_catch(&exception_header->unwindHeader);
+ if (native_exception)
+ std::__terminate(exception_header->terminateHandler);
+ // Foreign exception: can't get exception_header->terminateHandler
+ std::terminate();
+}
+
+/*
+ If thrown_object is not null, atomically increment the referenceCount field
+ of the __cxa_exception header associated with the thrown object referred to
+ by thrown_object.
+
+ Requires: If thrown_object is not NULL, it is a native exception.
+*/
+void
+__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);
+ }
+}
+
+/*
+ If thrown_object is not null, atomically decrement the referenceCount field
+ of the __cxa_exception header associated with the thrown object referred to
+ by thrown_object. If the referenceCount drops to zero, destroy and
+ deallocate the exception.
+
+ Requires: If thrown_object is not NULL, it is a native exception.
+*/
+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 (NULL != exception_header->exceptionDestructor)
+ exception_header->exceptionDestructor(thrown_object);
+ __cxa_free_exception(thrown_object);
+ }
+ }
+}
+
+/*
+ Returns a pointer to the thrown object (if any) at the top of the
+ caughtExceptions stack. Atommically increment the exception's referenceCount.
+ If there is no such thrown object or if the thrown object is foreign,
+ returns null.
+
+ We can use __cxa_get_globals_fast here to get the globals because if there have
+ been no exceptions thrown, ever, on this thread, we can return NULL without
+ the need to allocate the exception-handling globals.
+*/
+void*
+__cxa_current_primary_exception() throw()
+{
+// get the current exception
+ __cxa_eh_globals* globals = __cxa_get_globals_fast();
+ if (NULL == globals)
+ return NULL; // If there are no globals, there is no exception
+ __cxa_exception* exception_header = globals->caughtExceptions;
+ if (NULL == exception_header)
+ return NULL; // No current exception
+ if (!isOurExceptionClass(&exception_header->unwindHeader))
+ return NULL; // Can't capture a foreign exception (no way to refcount it)
+ if (isDependentException(&exception_header->unwindHeader)) {
+ __cxa_dependent_exception* dep_exception_header =
+ reinterpret_cast<__cxa_dependent_exception*>(exception_header);
+ exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException);
+ }
+ void* thrown_object = thrown_object_from_cxa_exception(exception_header);
+ __cxa_increment_exception_refcount(thrown_object);
+ return thrown_object;
+}
+
+/*
+ If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
+ stored in exc is called. Otherwise the referenceCount stored in the
+ primary exception is decremented, destroying the primary if necessary.
+ Finally the dependent exception is destroyed.
+*/
+static
+void
+dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception)
+{
+ __cxa_dependent_exception* dep_exception_header =
+ reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1;
+ if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
+ std::__terminate(dep_exception_header->terminateHandler);
+ __cxa_decrement_exception_refcount(dep_exception_header->primaryException);
+ __cxa_free_dependent_exception(dep_exception_header);
+}
+
+/*
+ If thrown_object is not null, allocate, initialize and thow a dependent
+ exception.
+*/
+void
+__cxa_rethrow_primary_exception(void* thrown_object)
+{
+ if ( thrown_object != NULL )
+ {
+ // thrown_object guaranteed to be native because
+ // __cxa_current_primary_exception returns NULL for foreign exceptions
+ __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
+ __cxa_dependent_exception* dep_exception_header =
+ static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception());
+ dep_exception_header->primaryException = thrown_object;
+ __cxa_increment_exception_refcount(thrown_object);
+ dep_exception_header->exceptionType = exception_header->exceptionType;
+ dep_exception_header->unexpectedHandler = std::get_unexpected();
+ dep_exception_header->terminateHandler = std::get_terminate();
+ setDependentExceptionClass(&dep_exception_header->unwindHeader);
+ __cxa_get_globals()->uncaughtExceptions += 1;
+ dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup;
+#if __arm__
+ _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader);
+#else
+ _Unwind_RaiseException(&dep_exception_header->unwindHeader);
+#endif
+ // Some sort of unwinding error. Note that terminate is a handler.
+ __cxa_begin_catch(&dep_exception_header->unwindHeader);
+ }
+ // If we return client will call terminate()
+}
+
+bool
+__cxa_uncaught_exception() throw()
+{
+ // This does not report foreign exceptions in flight
+ __cxa_eh_globals* globals = __cxa_get_globals_fast();
+ if (globals == 0)
+ return false;
+ return globals->uncaughtExceptions != 0;
+}
+
+} // extern "C"
+
+#pragma GCC visibility pop
+
+} // abi
diff --git a/system/lib/libcxxabi/src/cxa_exception.hpp b/system/lib/libcxxabi/src/cxa_exception.hpp
new file mode 100644
index 00000000..cf019d4c
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_exception.hpp
@@ -0,0 +1,118 @@
+//===------------------------- cxa_exception.hpp --------------------------===//
+//
+// 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.
+//
+//
+// This file implements the "Exception Handling APIs"
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception> // for std::unexpected_handler and std::terminate_handler
+#include <cxxabi.h>
+#include "unwind.h"
+
+namespace __cxxabiv1 {
+
+#pragma GCC visibility push(hidden)
+
+static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0
+static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1
+static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++
+
+ struct __cxa_exception {
+#if __LP64__
+ // This is a new field to support C++ 0x exception_ptr.
+ // For binary compatibility it is at the start of this
+ // struct which is prepended to the object thrown in
+ // __cxa_allocate_exception.
+ size_t referenceCount;
+#endif
+
+ // Manage the exception object itself.
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+ std::unexpected_handler unexpectedHandler;
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+#ifdef __ARM_EABI_UNWINDER__
+ __cxa_exception* nextPropagatingException;
+ int propagationCount;
+#else
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+#endif
+
+#if !__LP64__
+ // This is a new field to support C++ 0x exception_ptr.
+ // For binary compatibility it is placed where the compiler
+ // previously adding padded to 64-bit align unwindHeader.
+ size_t referenceCount;
+#endif
+
+ _Unwind_Exception unwindHeader;
+ };
+
+// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
+
+ struct __cxa_dependent_exception {
+#if __LP64__
+ void* primaryException;
+#endif
+
+ std::type_info *exceptionType;
+ void (*exceptionDestructor)(void *);
+ std::unexpected_handler unexpectedHandler;
+ std::terminate_handler terminateHandler;
+
+ __cxa_exception *nextException;
+
+ int handlerCount;
+
+#ifdef __ARM_EABI_UNWINDER__
+ __cxa_exception* nextPropagatingException;
+ int propagationCount;
+#else
+ int handlerSwitchValue;
+ const unsigned char *actionRecord;
+ const unsigned char *languageSpecificData;
+ void * catchTemp;
+ void *adjustedPtr;
+#endif
+
+#if !__LP64__
+ void* primaryException;
+#endif
+
+ _Unwind_Exception unwindHeader;
+ };
+
+ struct __cxa_eh_globals {
+ __cxa_exception * caughtExceptions;
+ unsigned int uncaughtExceptions;
+#ifdef __ARM_EABI_UNWINDER__
+ __cxa_exception* propagatingExceptions;
+#endif
+ };
+
+#pragma GCC visibility pop
+#pragma GCC visibility push(default)
+
+ extern "C" __cxa_eh_globals * __cxa_get_globals ();
+ extern "C" __cxa_eh_globals * __cxa_get_globals_fast ();
+
+ extern "C" void * __cxa_allocate_dependent_exception ();
+ extern "C" void __cxa_free_dependent_exception (void * dependent_exception);
+
+#pragma GCC visibility pop
+}
diff --git a/system/lib/libcxxabi/src/cxa_exception_storage.cpp b/system/lib/libcxxabi/src/cxa_exception_storage.cpp
new file mode 100644
index 00000000..2c269c7f
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_exception_storage.cpp
@@ -0,0 +1,91 @@
+//===--------------------- cxa_exception_storage.cpp ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the storage for the "Caught Exception Stack"
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html (section 2.2.2)
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxa_exception.hpp"
+
+#ifdef HAS_THREAD_LOCAL
+
+namespace __cxxabiv1 {
+
+namespace {
+ __cxa_eh_globals * __globals () {
+ static thread_local __cxa_eh_globals eh_globals;
+ return &eh_globals;
+ }
+ }
+
+extern "C" {
+ __cxa_eh_globals * __cxa_get_globals () { return __globals (); }
+ __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); }
+ }
+}
+
+#else
+
+#include <pthread.h>
+#include <cstdlib> // for calloc, free
+#include "abort_message.h"
+
+// In general, we treat all pthread errors as fatal.
+// We cannot call std::terminate() because that will in turn
+// call __cxa_get_globals() and cause infinite recursion.
+
+namespace __cxxabiv1 {
+namespace {
+ pthread_key_t key_;
+ pthread_once_t flag_ = PTHREAD_ONCE_INIT;
+
+ void destruct_ (void *p) {
+ std::free ( p );
+ if ( 0 != ::pthread_setspecific ( key_, NULL ) )
+ abort_message("cannot zero out thread value for __cxa_get_globals()");
+ }
+
+ void construct_ () {
+ if ( 0 != pthread_key_create ( &key_, destruct_ ) )
+ abort_message("cannot create pthread key for __cxa_get_globals()");
+ }
+}
+
+extern "C" {
+ __cxa_eh_globals * __cxa_get_globals () {
+ // Try to get the globals for this thread
+ __cxa_eh_globals* retVal = __cxa_get_globals_fast ();
+
+ // If this is the first time we've been asked for these globals, create them
+ if ( NULL == retVal ) {
+ retVal = static_cast<__cxa_eh_globals*>
+ (std::calloc (1, sizeof (__cxa_eh_globals)));
+ if ( NULL == retVal )
+ abort_message("cannot allocate __cxa_eh_globals");
+ if ( 0 != pthread_setspecific ( key_, retVal ) )
+ abort_message("pthread_setspecific failure in __cxa_get_globals()");
+ }
+ return retVal;
+ }
+
+ // Note that this implementation will reliably return NULL if not
+ // preceeded by a call to __cxa_get_globals(). This is an extension
+ // to the Itanium ABI and is taken advantage of in several places in
+ // libc++abi.
+ __cxa_eh_globals * __cxa_get_globals_fast () {
+ // First time through, create the key.
+ if (0 != pthread_once(&flag_, construct_))
+ abort_message("pthread_once failure in __cxa_get_globals_fast()");
+// static int init = construct_();
+ return static_cast<__cxa_eh_globals*>(::pthread_getspecific(key_));
+ }
+
+}
+}
+#endif
diff --git a/system/lib/libcxxabi/src/cxa_guard.cpp b/system/lib/libcxxabi/src/cxa_guard.cpp
new file mode 100644
index 00000000..814aaeb1
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_guard.cpp
@@ -0,0 +1,231 @@
+//===---------------------------- cxa_guard.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "abort_message.h"
+
+#include <pthread.h>
+#include <stdint.h>
+
+/*
+ This implementation must be careful to not call code external to this file
+ which will turn around and try to call __cxa_guard_acquire reentrantly.
+ For this reason, the headers of this file are as restricted as possible.
+ Previous implementations of this code for __APPLE__ have used
+ pthread_mutex_lock and the abort_message utility without problem. This
+ implementation also uses pthread_cond_wait which has tested to not be a
+ problem.
+*/
+
+namespace __cxxabiv1
+{
+
+namespace
+{
+
+#if LIBCXXABI_ARMEABI
+
+// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
+// be statically initialized to 0.
+typedef uint32_t guard_type;
+
+// Test the lowest bit.
+inline bool is_initialized(guard_type* guard_object) {
+ return (*guard_object) & 1;
+}
+
+inline void set_initialized(guard_type* guard_object) {
+ *guard_object |= 1;
+}
+
+#else
+
+typedef uint64_t guard_type;
+
+bool is_initialized(guard_type* guard_object) {
+ char* initialized = (char*)guard_object;
+ return *initialized;
+}
+
+void set_initialized(guard_type* guard_object) {
+ char* initialized = (char*)guard_object;
+ *initialized = 1;
+}
+
+#endif
+
+pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
+
+#if __APPLE__
+
+typedef uint32_t lock_type;
+
+#if __LITTLE_ENDIAN__
+
+inline
+lock_type
+get_lock(uint64_t x)
+{
+ return static_cast<lock_type>(x >> 32);
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ x = static_cast<uint64_t>(y) << 32;
+}
+
+#else // __LITTLE_ENDIAN__
+
+inline
+lock_type
+get_lock(uint64_t x)
+{
+ return static_cast<lock_type>(x);
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ x = y;
+}
+
+#endif // __LITTLE_ENDIAN__
+
+#else // __APPLE__
+
+typedef bool lock_type;
+
+inline
+lock_type
+get_lock(uint64_t x)
+{
+ union
+ {
+ uint64_t guard;
+ uint8_t lock[2];
+ } f = {x};
+ return f.lock[1] != 0;
+}
+
+inline
+void
+set_lock(uint64_t& x, lock_type y)
+{
+ union
+ {
+ uint64_t guard;
+ uint8_t lock[2];
+ } f = {0};
+ f.lock[1] = y;
+ x = f.guard;
+}
+
+inline
+lock_type
+get_lock(uint32_t x)
+{
+ union
+ {
+ uint32_t guard;
+ uint8_t lock[2];
+ } f = {x};
+ return f.lock[1] != 0;
+}
+
+inline
+void
+set_lock(uint32_t& x, lock_type y)
+{
+ union
+ {
+ uint32_t guard;
+ uint8_t lock[2];
+ } f = {0};
+ f.lock[1] = y;
+ x = f.guard;
+}
+
+#endif // __APPLE__
+
+} // unnamed namespace
+
+extern "C"
+{
+
+int __cxa_guard_acquire(guard_type* guard_object)
+{
+ char* initialized = (char*)guard_object;
+ if (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_acquire failed to acquire mutex");
+ int result = *initialized == 0;
+ if (result)
+ {
+#if __APPLE__
+ const lock_type id = pthread_mach_thread_np(pthread_self());
+ lock_type lock = get_lock(*guard_object);
+ if (lock)
+ {
+ // if this thread set lock for this same guard_object, abort
+ if (lock == id)
+ abort_message("__cxa_guard_acquire detected deadlock");
+ do
+ {
+ if (pthread_cond_wait(&guard_cv, &guard_mut))
+ abort_message("__cxa_guard_acquire condition variable wait failed");
+ lock = get_lock(*guard_object);
+ } while (lock);
+ result = !is_initialized(guard_object);
+ if (result)
+ set_lock(*guard_object, id);
+ }
+ else
+ set_lock(*guard_object, id);
+#else // __APPLE__
+ while (get_lock(*guard_object))
+ if (pthread_cond_wait(&guard_cv, &guard_mut))
+ abort_message("__cxa_guard_acquire condition variable wait failed");
+ result = *initialized == 0;
+ if (result)
+ set_lock(*guard_object, true);
+#endif // __APPLE__
+ }
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_acquire failed to release mutex");
+ return result;
+}
+
+void __cxa_guard_release(guard_type* guard_object)
+{
+ if (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_release failed to acquire mutex");
+ *guard_object = 0;
+ set_initialized(guard_object);
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_release failed to release mutex");
+ if (pthread_cond_broadcast(&guard_cv))
+ abort_message("__cxa_guard_release failed to broadcast condition variable");
+}
+
+void __cxa_guard_abort(guard_type* guard_object)
+{
+ if (pthread_mutex_lock(&guard_mut))
+ abort_message("__cxa_guard_abort failed to acquire mutex");
+ *guard_object = 0;
+ if (pthread_mutex_unlock(&guard_mut))
+ abort_message("__cxa_guard_abort failed to release mutex");
+ if (pthread_cond_broadcast(&guard_cv))
+ abort_message("__cxa_guard_abort failed to broadcast condition variable");
+}
+
+} // extern "C"
+
+} // __cxxabiv1
diff --git a/system/lib/libcxxabi/src/cxa_handlers.cpp b/system/lib/libcxxabi/src/cxa_handlers.cpp
new file mode 100644
index 00000000..be43181c
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_handlers.cpp
@@ -0,0 +1,196 @@
+//===------------------------- cxa_handlers.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the functionality associated with the terminate_handler,
+// unexpected_handler, and new_handler.
+//===----------------------------------------------------------------------===//
+
+#include <stdexcept>
+#include <new>
+#include <exception>
+#include "abort_message.h"
+#include "cxxabi.h"
+#include "cxa_handlers.hpp"
+#include "cxa_exception.hpp"
+#include "private_typeinfo.h"
+
+namespace std
+{
+
+static const char* cause = "uncaught";
+
+static void default_terminate_handler()
+{
+ // If there might be an uncaught exception
+ using namespace __cxxabiv1;
+ __cxa_eh_globals* globals = __cxa_get_globals_fast();
+ if (globals)
+ {
+ __cxa_exception* exception_header = globals->caughtExceptions;
+ // If there is an uncaught exception
+ if (exception_header)
+ {
+ _Unwind_Exception* unwind_exception =
+ reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
+ bool native_exception =
+ (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ if (native_exception)
+ {
+ void* thrown_object =
+ unwind_exception->exception_class == kOurDependentExceptionClass ?
+ ((__cxa_dependent_exception*)exception_header)->primaryException :
+ exception_header + 1;
+ const __shim_type_info* thrown_type =
+ static_cast<const __shim_type_info*>(exception_header->exceptionType);
+ // Try to get demangled name of thrown_type
+ int status;
+ char buf[1024];
+ size_t len = sizeof(buf);
+ const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status);
+ if (status != 0)
+ name = thrown_type->name();
+ // If the uncaught exception can be caught with std::exception&
+ const __shim_type_info* catch_type =
+ static_cast<const __shim_type_info*>(&typeid(exception));
+ if (catch_type->can_catch(thrown_type, thrown_object))
+ {
+ // Include the what() message from the exception
+ const exception* e = static_cast<const exception*>(thrown_object);
+ abort_message("terminating with %s exception of type %s: %s",
+ cause, name, e->what());
+ }
+ else
+ // Else just note that we're terminating with an exception
+ abort_message("terminating with %s exception of type %s",
+ cause, name);
+ }
+ else
+ // Else we're terminating with a foreign exception
+ abort_message("terminating with %s foreign exception", cause);
+ }
+ }
+ // Else just note that we're terminating
+ abort_message("terminating");
+}
+
+static void default_unexpected_handler()
+{
+ cause = "unexpected";
+ terminate();
+}
+
+static terminate_handler __terminate_handler = default_terminate_handler;
+static unexpected_handler __unexpected_handler = default_unexpected_handler;
+static new_handler __new_handler = 0;
+
+unexpected_handler
+set_unexpected(unexpected_handler func) _NOEXCEPT
+{
+ if (func == 0)
+ func = default_unexpected_handler;
+ return __sync_lock_test_and_set(&__unexpected_handler, func);
+}
+
+unexpected_handler
+get_unexpected() _NOEXCEPT
+{
+ return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
+}
+
+__attribute__((visibility("hidden"), noreturn))
+void
+__unexpected(unexpected_handler func)
+{
+ func();
+ // unexpected handler should not return
+ abort_message("unexpected_handler unexpectedly returned");
+}
+
+__attribute__((noreturn))
+void
+unexpected()
+{
+ __unexpected(get_unexpected());
+}
+
+terminate_handler
+set_terminate(terminate_handler func) _NOEXCEPT
+{
+ if (func == 0)
+ func = default_terminate_handler;
+ return __sync_lock_test_and_set(&__terminate_handler, func);
+}
+
+terminate_handler
+get_terminate() _NOEXCEPT
+{
+ return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
+}
+
+__attribute__((visibility("hidden"), noreturn))
+void
+__terminate(terminate_handler func) _NOEXCEPT
+{
+#if __has_feature(cxx_exceptions)
+ try
+ {
+#endif // __has_feature(cxx_exceptions)
+ func();
+ // handler should not return
+ abort_message("terminate_handler unexpectedly returned");
+#if __has_feature(cxx_exceptions)
+ }
+ catch (...)
+ {
+ // handler should not throw exception
+ abort_message("terminate_handler unexpectedly threw an exception");
+ }
+#endif // #if __has_feature(cxx_exceptions)
+}
+
+__attribute__((noreturn))
+void
+terminate() _NOEXCEPT
+{
+ // If there might be an uncaught exception
+ using namespace __cxxabiv1;
+ __cxa_eh_globals* globals = __cxa_get_globals_fast();
+ if (globals)
+ {
+ __cxa_exception* exception_header = globals->caughtExceptions;
+ if (exception_header)
+ {
+ _Unwind_Exception* unwind_exception =
+ reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
+ bool native_exception =
+ (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ if (native_exception)
+ {
+ __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+ __terminate(exception_header->terminateHandler);
+ }
+ }
+ }
+ __terminate(get_terminate());
+}
+
+new_handler
+set_new_handler(new_handler handler) _NOEXCEPT
+{
+ return __sync_lock_test_and_set(&__new_handler, handler);
+}
+
+new_handler
+get_new_handler() _NOEXCEPT
+{
+ return __sync_fetch_and_add(&__new_handler, (new_handler)0);
+}
+
+} // std
diff --git a/system/lib/libcxxabi/src/cxa_handlers.hpp b/system/lib/libcxxabi/src/cxa_handlers.hpp
new file mode 100644
index 00000000..a7f582c0
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_handlers.hpp
@@ -0,0 +1,26 @@
+//===------------------------- cxa_handlers.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the functionality associated with the terminate_handler,
+// unexpected_handler, and new_handler.
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+
+namespace std
+{
+
+__attribute__((visibility("hidden"), noreturn))
+void
+__unexpected(unexpected_handler func);
+
+__attribute__((visibility("hidden"), noreturn))
+void
+__terminate(terminate_handler func) _NOEXCEPT;
+
+} // std
diff --git a/system/lib/libcxxabi/src/cxa_new_delete.cpp b/system/lib/libcxxabi/src/cxa_new_delete.cpp
new file mode 100644
index 00000000..6352001b
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_new_delete.cpp
@@ -0,0 +1,231 @@
+//===------------------------ cxa_new_delete.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the new and delete operators.
+//===----------------------------------------------------------------------===//
+
+#include <new>
+#include <cstdlib>
+
+/*
+[new.delete.single]
+
+* Executes a loop: Within the loop, the function first attempts to allocate
+ the requested storage. Whether the attempt involves a call to the Standard C
+ library function malloc is unspecified.
+
+* Returns a pointer to the allocated storage if the attempt is successful.
+ Otherwise, if the current new_handler (18.6.2.5) is a null pointer value,
+ throws bad_alloc.
+
+* Otherwise, the function calls the current new_handler function (18.6.2.3).
+ If the called function returns, the loop repeats.
+
+* The loop terminates when an attempt to allocate the requested storage is
+ successful or when a called new_handler function does not return.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void *
+operator new(std::size_t size)
+#if !__has_feature(cxx_noexcept)
+ throw(std::bad_alloc)
+#endif
+{
+ if (size == 0)
+ size = 1;
+ void* p;
+ while ((p = std::malloc(size)) == 0)
+ {
+ std::new_handler nh = std::get_new_handler();
+ if (nh)
+ nh();
+ else
+ throw std::bad_alloc();
+ }
+ return p;
+}
+
+/*
+Note: The relationships among these operators is both carefully considered
+and standard in C++11. Please do not change them without fully understanding
+the consequences of doing so. Reference:
+http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2158.html
+*/
+/*
+[new.delete.single]
+
+Calls operator new(size). If the call returns normally, returns the result of
+that call. Otherwise, returns a null pointer.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void*
+operator new(size_t size, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ void* p = 0;
+ try
+ {
+ p = ::operator new(size);
+ }
+ catch (...)
+ {
+ }
+ return p;
+}
+
+/*
+[new.delete.array]
+
+Returns operator new(size).
+*/
+__attribute__((__weak__, __visibility__("default")))
+void*
+operator new[](size_t size)
+#if !__has_feature(cxx_noexcept)
+ throw(std::bad_alloc)
+#endif
+{
+ return ::operator new(size);
+}
+
+/*
+[new.delete.array]
+
+Calls operator new[](size). If the call returns normally, returns the result
+of that call. Otherwise, returns a null pointer.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void*
+operator new[](size_t size, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ void* p = 0;
+ try
+ {
+ p = ::operator new[](size);
+ }
+ catch (...)
+ {
+ }
+ return p;
+}
+
+/*
+[new.delete.single]
+
+If ptr is null, does nothing. Otherwise, reclaims the storage allocated by the
+earlier call to operator new.
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete(void* ptr)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ if (ptr)
+ std::free(ptr);
+}
+
+/*
+[new.delete.single]
+
+calls operator delete(ptr)
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete(void* ptr, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ ::operator delete(ptr);
+}
+
+/*
+[new.delete.array]
+
+Calls operator delete(ptr)
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete[] (void* ptr)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ ::operator delete(ptr);
+}
+
+/*
+[new.delete.array]
+
+calls operator delete[](ptr)
+*/
+__attribute__((__weak__, __visibility__("default")))
+void
+operator delete[] (void* ptr, const std::nothrow_t&)
+#if __has_feature(cxx_noexcept)
+ noexcept
+#else
+ throw()
+#endif
+{
+ ::operator delete[](ptr);
+}
+
+namespace std
+{
+
+// bad_alloc
+
+bad_alloc::bad_alloc() _NOEXCEPT
+{
+}
+
+bad_alloc::~bad_alloc() _NOEXCEPT
+{
+}
+
+const char*
+bad_alloc::what() const _NOEXCEPT
+{
+ return "std::bad_alloc";
+}
+
+// bad_array_new_length
+
+bad_array_new_length::bad_array_new_length() _NOEXCEPT
+{
+}
+
+bad_array_new_length::~bad_array_new_length() _NOEXCEPT
+{
+}
+
+const char*
+bad_array_new_length::what() const _NOEXCEPT
+{
+ return "bad_array_new_length";
+}
+
+} // std
diff --git a/system/lib/libcxxabi/src/cxa_personality.cpp b/system/lib/libcxxabi/src/cxa_personality.cpp
new file mode 100644
index 00000000..e49278c0
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_personality.cpp
@@ -0,0 +1,987 @@
+//===------------------------- cxa_exception.cpp --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the "Exception Handling APIs"
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+// http://www.intel.com/design/itanium/downloads/245358.htm
+//
+//===----------------------------------------------------------------------===//
+
+#include "unwind.h"
+#include "cxa_exception.hpp"
+#include "cxa_handlers.hpp"
+#include "private_typeinfo.h"
+#include <typeinfo>
+#include <stdlib.h>
+#include <assert.h>
+
+/*
+ Exception Header Layout:
+
++---------------------------+-----------------------------+---------------+
+| __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object |
++---------------------------+-----------------------------+---------------+
+ ^
+ |
+ +-------------------------------------------------------+
+ |
++---------------------------+-----------------------------+
+| __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 |
++---------------------------+-----------------------------+
+
+ Exception Handling Table Layout:
+
++-----------------+--------+
+| lpStartEncoding | (char) |
++---------+-------+--------+---------------+-----------------------+
+| lpStart | (encoded wtih lpStartEncoding) | defaults to funcStart |
++---------+-----+--------+-----------------+---------------+-------+
+| ttypeEncoding | (char) | Encoding of the type_info table |
++---------------+-+------+----+----------------------------+----------------+
+| classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null |
++-----------------++--------+-+----------------------------+----------------+
+| callSiteEncoding | (char) | Encoding for Call Site Table |
++------------------+--+-----+-----+------------------------+--------------------------+
+| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table |
++---------------------+-----------+------------------------------------------------+--+
+| Beginning of Call Site Table If the current ip lies within the |
+| ... (start, length) range of one of these |
+| call sites, there may be action needed. |
+| +-------------+---------------------------------+------------------------------+ |
+| | start | (encoded with callSiteEncoding) | offset relative to funcStart | |
+| | length | (encoded with callSiteEncoding) | lenght of code fragment | |
+| | landingPad | (encoded with callSiteEncoding) | offset relative to lpStart | |
+| | actionEntry | (ULEB128) | Action Table Index 1-based | |
+| | | | actionEntry == 0 -> cleanup | |
+| +-------------+---------------------------------+------------------------------+ |
+| ... |
++---------------------------------------------------------------------+------------+
+| Beginning of Action Table ttypeIndex == 0 : cleanup |
+| ... ttypeIndex > 0 : catch |
+| ttypeIndex < 0 : exception spec |
+| +--------------+-----------+--------------------------------------+ |
+| | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | |
+| | actionOffset | (SLEB128) | Offset into next Action Table entry | |
+| +--------------+-----------+--------------------------------------+ |
+| ... |
++---------------------------------------------------------------------+-----------------+
+| type_info Table, but classInfoOffset does *not* point here! |
+| +----------------+------------------------------------------------+-----------------+ |
+| | Nth type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == N | |
+| +----------------+------------------------------------------------+-----------------+ |
+| ... |
+| +----------------+------------------------------------------------+-----------------+ |
+| | 1st type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == 1 | |
+| +----------------+------------------------------------------------+-----------------+ |
+| +---------------------------------------+-----------+------------------------------+ |
+| | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | |
+| | ... | (ULEB128) | | |
+| | Mth ttypeIndex for 1st exception spec | (ULEB128) | | |
+| | 0 | (ULEB128) | | |
+| +---------------------------------------+------------------------------------------+ |
+| ... |
+| +---------------------------------------+------------------------------------------+ |
+| | 0 | (ULEB128) | throw() | |
+| +---------------------------------------+------------------------------------------+ |
+| ... |
+| +---------------------------------------+------------------------------------------+ |
+| | 1st ttypeIndex for Nth exception spec | (ULEB128) | | |
+| | ... | (ULEB128) | | |
+| | Mth ttypeIndex for Nth exception spec | (ULEB128) | | |
+| | 0 | (ULEB128) | | |
+| +---------------------------------------+------------------------------------------+ |
++---------------------------------------------------------------------------------------+
+
+Notes:
+
+* ttypeIndex in the Action Table, and in the exception spec table, is an index,
+ not a byte count, if positive. It is a negative index offset of
+ classInfoOffset and the sizeof entry depends on ttypeEncoding.
+ But if ttypeIndex is negative, it is a positive 1-based byte offset into the
+ type_info Table.
+ And if ttypeIndex is zero, it refers to a catch (...).
+
+* landingPad can be 0, this implies there is nothing to be done.
+
+* landingPad != 0 and actionEntry == 0 implies a cleanup needs to be done
+ @landingPad.
+
+* A cleanup can also be found under landingPad != 0 and actionEntry != 0 in
+ the Action Table with ttypeIndex == 0.
+*/
+
+namespace __cxxabiv1
+{
+
+extern "C"
+{
+
+// private API
+
+// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp
+
+// DWARF Constants
+enum
+{
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+ DW_EH_PE_indirect = 0x80,
+ DW_EH_PE_omit = 0xFF
+};
+
+/// Read a uleb128 encoded value and advance pointer
+/// See Variable Length Data Appendix C in:
+/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
+/// @param data reference variable holding memory pointer to decode from
+/// @returns decoded value
+static
+uintptr_t
+readULEB128(const uint8_t** data)
+{
+ uintptr_t result = 0;
+ uintptr_t shift = 0;
+ unsigned char byte;
+ const uint8_t *p = *data;
+ do
+ {
+ byte = *p++;
+ result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ *data = p;
+ return result;
+}
+
+/// Read a sleb128 encoded value and advance pointer
+/// See Variable Length Data Applendix C in:
+/// @link http://dwarfstd.org/Dwarf4.pdf @unlink
+/// @param data reference variable holding memory pointer to decode from
+/// @returns decoded value
+static
+uintptr_t
+readSLEB128(const uint8_t** data)
+{
+ uintptr_t result = 0;
+ uintptr_t shift = 0;
+ unsigned char byte;
+ const uint8_t *p = *data;
+ do
+ {
+ byte = *p++;
+ result |= static_cast<uintptr_t>(byte & 0x7F) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ *data = p;
+ if ((byte & 0x40) && (shift < (sizeof(result) << 3)))
+ result |= static_cast<uintptr_t>(~0) << shift;
+ return result;
+}
+
+/// Read a pointer encoded value and advance pointer
+/// See Variable Length Data in:
+/// @link http://dwarfstd.org/Dwarf3.pdf @unlink
+/// @param data reference variable holding memory pointer to decode from
+/// @param encoding dwarf encoding type
+/// @returns decoded value
+static
+uintptr_t
+readEncodedPointer(const uint8_t** data, uint8_t encoding)
+{
+ uintptr_t result = 0;
+ if (encoding == DW_EH_PE_omit)
+ return result;
+ const uint8_t* p = *data;
+ // first get value
+ switch (encoding & 0x0F)
+ {
+ case DW_EH_PE_absptr:
+ result = *((uintptr_t*)p);
+ p += sizeof(uintptr_t);
+ break;
+ case DW_EH_PE_uleb128:
+ result = readULEB128(&p);
+ break;
+ case DW_EH_PE_sleb128:
+ result = readSLEB128(&p);
+ break;
+ case DW_EH_PE_udata2:
+ result = *((uint16_t*)p);
+ p += sizeof(uint16_t);
+ break;
+ case DW_EH_PE_udata4:
+ result = *((uint32_t*)p);
+ p += sizeof(uint32_t);
+ break;
+ case DW_EH_PE_udata8:
+ result = *((uint64_t*)p);
+ p += sizeof(uint64_t);
+ break;
+ case DW_EH_PE_sdata2:
+ result = *((int16_t*)p);
+ p += sizeof(int16_t);
+ break;
+ case DW_EH_PE_sdata4:
+ result = *((int32_t*)p);
+ p += sizeof(int32_t);
+ break;
+ case DW_EH_PE_sdata8:
+ result = *((int64_t*)p);
+ p += sizeof(int64_t);
+ break;
+ default:
+ // not supported
+ abort();
+ break;
+ }
+ // then add relative offset
+ switch (encoding & 0x70)
+ {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ if (result)
+ result += (uintptr_t)(*data);
+ break;
+ case DW_EH_PE_textrel:
+ case DW_EH_PE_datarel:
+ case DW_EH_PE_funcrel:
+ case DW_EH_PE_aligned:
+ default:
+ // not supported
+ abort();
+ break;
+ }
+ // then apply indirection
+ if (result && (encoding & DW_EH_PE_indirect))
+ result = *((uintptr_t*)result);
+ *data = p;
+ return result;
+}
+
+static
+void
+call_terminate(bool native_exception, _Unwind_Exception* unwind_exception)
+{
+ __cxa_begin_catch(unwind_exception);
+ if (native_exception)
+ {
+ // Use the stored terminate_handler if possible
+ __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+ std::__terminate(exception_header->terminateHandler);
+ }
+ std::terminate();
+}
+
+static
+const __shim_type_info*
+get_shim_type_info(int64_t ttypeIndex, const uint8_t* classInfo,
+ uint8_t ttypeEncoding, bool native_exception,
+ _Unwind_Exception* unwind_exception)
+{
+ if (classInfo == 0)
+ {
+ // this should not happen. Indicates corrupted eh_table.
+ call_terminate(native_exception, unwind_exception);
+ }
+ switch (ttypeEncoding & 0x0F)
+ {
+ case DW_EH_PE_absptr:
+ ttypeIndex *= sizeof(void*);
+ break;
+ case DW_EH_PE_udata2:
+ case DW_EH_PE_sdata2:
+ ttypeIndex *= 2;
+ break;
+ case DW_EH_PE_udata4:
+ case DW_EH_PE_sdata4:
+ ttypeIndex *= 4;
+ break;
+ case DW_EH_PE_udata8:
+ case DW_EH_PE_sdata8:
+ ttypeIndex *= 8;
+ break;
+ default:
+ // this should not happen. Indicates corrupted eh_table.
+ call_terminate(native_exception, unwind_exception);
+ }
+ classInfo -= ttypeIndex;
+ return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding);
+}
+
+/*
+ This is checking a thrown exception type, excpType, against a posibly empty
+ list of catchType's which make up an exception spec.
+
+ An exception spec acts like a catch handler, but in reverse. This "catch
+ handler" will catch an excpType if and only if none of the catchType's in
+ the list will catch a excpType. If any catchType in the list can catch an
+ excpType, then this exception spec does not catch the excpType.
+*/
+static
+bool
+exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo,
+ uint8_t ttypeEncoding, const __shim_type_info* excpType,
+ void* adjustedPtr, _Unwind_Exception* unwind_exception)
+{
+ if (classInfo == 0)
+ {
+ // this should not happen. Indicates corrupted eh_table.
+ call_terminate(false, unwind_exception);
+ }
+ // specIndex is negative of 1-based byte offset into classInfo;
+ specIndex = -specIndex;
+ --specIndex;
+ const uint8_t* temp = classInfo + specIndex;
+ // If any type in the spec list can catch excpType, return false, else return true
+ // adjustments to adjustedPtr are ignored.
+ while (true)
+ {
+ uint64_t ttypeIndex = readULEB128(&temp);
+ if (ttypeIndex == 0)
+ break;
+ const __shim_type_info* catchType = get_shim_type_info(ttypeIndex,
+ classInfo,
+ ttypeEncoding,
+ true,
+ unwind_exception);
+ void* tempPtr = adjustedPtr;
+ if (catchType->can_catch(excpType, tempPtr))
+ return false;
+ }
+ return true;
+}
+
+static
+void*
+get_thrown_object_ptr(_Unwind_Exception* unwind_exception)
+{
+ // Even for foreign exceptions, the exception object is *probably* at unwind_exception + 1
+ // Regardless, this library is prohibited from touching a foreign exception
+ void* adjustedPtr = unwind_exception + 1;
+ if (unwind_exception->exception_class == kOurDependentExceptionClass)
+ adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException;
+ return adjustedPtr;
+}
+
+/*
+ There are 3 types of scans needed:
+
+ 1. Scan for handler with native or foreign exception. If handler found,
+ save state and return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND.
+ May also report an error on invalid input.
+ May terminate for invalid exception table.
+ _UA_SEARCH_PHASE
+
+ 2. Scan for handler with foreign exception. Must return _URC_HANDLER_FOUND,
+ or call terminate.
+ _UA_CLEANUP_PHASE && _UA_HANDLER_FRAME && !native_exception
+
+ 3. Scan for cleanups. If a handler is found and this isn't forced unwind,
+ then terminate, otherwise ignore the handler and keep looking for cleanup.
+ If a cleanup is found, return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND.
+ May also report an error on invalid input.
+ May terminate for invalid exception table.
+ _UA_CLEANUP_PHASE && !_UA_HANDLER_FRAME
+*/
+
+namespace
+{
+
+struct scan_results
+{
+ int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
+ const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance.
+ const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected
+ uintptr_t landingPad; // null -> nothing found, else something found
+ void* adjustedPtr; // Used in cxa_exception.cpp
+ _Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR,
+ // _URC_FATAL_PHASE2_ERROR,
+ // _URC_CONTINUE_UNWIND,
+ // _URC_HANDLER_FOUND
+};
+
+} // unnamed namespace
+
+static
+void
+scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception,
+ _Unwind_Exception* unwind_exception, _Unwind_Context* context)
+{
+ // Initialize results to found nothing but an error
+ results.ttypeIndex = 0;
+ results.actionRecord = 0;
+ results.languageSpecificData = 0;
+ results.landingPad = 0;
+ results.adjustedPtr = 0;
+ results.reason = _URC_FATAL_PHASE1_ERROR;
+ // Check for consistent actions
+ if (actions & _UA_SEARCH_PHASE)
+ {
+ // Do Phase 1
+ if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND))
+ {
+ // None of these flags should be set during Phase 1
+ // Client error
+ results.reason = _URC_FATAL_PHASE1_ERROR;
+ return;
+ }
+ }
+ else if (actions & _UA_CLEANUP_PHASE)
+ {
+ if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND))
+ {
+ // _UA_HANDLER_FRAME should only be set if phase 1 found a handler.
+ // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened.
+ // Client error
+ results.reason = _URC_FATAL_PHASE2_ERROR;
+ return;
+ }
+ }
+ else // Niether _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set
+ {
+ // One of these should be set.
+ // Client error
+ results.reason = _URC_FATAL_PHASE1_ERROR;
+ return;
+ }
+ // Start scan by getting exception table address
+ const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(context);
+ if (lsda == 0)
+ {
+ // There is no exception table
+ results.reason = _URC_CONTINUE_UNWIND;
+ return;
+ }
+ results.languageSpecificData = lsda;
+ // Get the current instruction pointer and offset it before next
+ // instruction in the current frame which threw the exception.
+ uintptr_t ip = _Unwind_GetIP(context) - 1;
+ // Get beginning current frame's code (as defined by the
+ // emitted dwarf code)
+ uintptr_t funcStart = _Unwind_GetRegionStart(context);
+ uintptr_t ipOffset = ip - funcStart;
+ const uint8_t* classInfo = NULL;
+ // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding
+ // dwarf emission
+ // Parse LSDA header.
+ uint8_t lpStartEncoding = *lsda++;
+ const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
+ if (lpStart == 0)
+ lpStart = (const uint8_t*)funcStart;
+ uint8_t ttypeEncoding = *lsda++;
+ if (ttypeEncoding != DW_EH_PE_omit)
+ {
+ // Calculate type info locations in emitted dwarf code which
+ // were flagged by type info arguments to llvm.eh.selector
+ // intrinsic
+ uintptr_t classInfoOffset = readULEB128(&lsda);
+ classInfo = lsda + classInfoOffset;
+ }
+ // Walk call-site table looking for range that
+ // includes current PC.
+ uint8_t callSiteEncoding = *lsda++;
+ uint32_t callSiteTableLength = readULEB128(&lsda);
+ const uint8_t* callSiteTableStart = lsda;
+ const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
+ const uint8_t* actionTableStart = callSiteTableEnd;
+ const uint8_t* callSitePtr = callSiteTableStart;
+ while (true)
+ {
+ // There is one entry per call site.
+ // The call sites are non-overlapping in [start, start+length)
+ // The call sites are ordered in increasing value of start
+ uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding);
+ uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding);
+ uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding);
+ uintptr_t actionEntry = readULEB128(&callSitePtr);
+ if ((start <= ipOffset) && (ipOffset < (start + length)))
+ {
+ // Found the call site containing ip.
+ if (landingPad == 0)
+ {
+ // No handler here
+ results.reason = _URC_CONTINUE_UNWIND;
+ return;
+ }
+ landingPad = (uintptr_t)lpStart + landingPad;
+ if (actionEntry == 0)
+ {
+ // Found a cleanup
+ // If this is a type 1 or type 2 search, there are no handlers
+ // If this is a type 3 search, you want to install the cleanup.
+ if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
+ {
+ results.ttypeIndex = 0; // Redundant but clarifying
+ results.landingPad = landingPad;
+ results.reason = _URC_HANDLER_FOUND;
+ return;
+ }
+ // No handler here
+ results.reason = _URC_CONTINUE_UNWIND;
+ return;
+ }
+ // Convert 1-based byte offset into
+ const uint8_t* action = actionTableStart + (actionEntry - 1);
+ // Scan action entries until you find a matching handler, cleanup, or the end of action list
+ while (true)
+ {
+ const uint8_t* actionRecord = action;
+ int64_t ttypeIndex = readSLEB128(&action);
+ if (ttypeIndex > 0)
+ {
+ // Found a catch, does it actually catch?
+ // First check for catch (...)
+ const __shim_type_info* catchType =
+ get_shim_type_info(ttypeIndex, classInfo,
+ ttypeEncoding, native_exception,
+ unwind_exception);
+ if (catchType == 0)
+ {
+ // Found catch (...) catches everything, including foreign exceptions
+ // If this is a type 1 search save state and return _URC_HANDLER_FOUND
+ // If this is a type 2 search save state and return _URC_HANDLER_FOUND
+ // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
+ // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
+ if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
+ {
+ // Save state and return _URC_HANDLER_FOUND
+ results.ttypeIndex = ttypeIndex;
+ results.actionRecord = actionRecord;
+ results.landingPad = landingPad;
+ results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
+ results.reason = _URC_HANDLER_FOUND;
+ return;
+ }
+ else if (!(actions & _UA_FORCE_UNWIND))
+ {
+ // It looks like the exception table has changed
+ // on us. Likely stack corruption!
+ call_terminate(native_exception, unwind_exception);
+ }
+ }
+ // Else this is a catch (T) clause and will never
+ // catch a foreign exception
+ else if (native_exception)
+ {
+ __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+ void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
+ const __shim_type_info* excpType =
+ static_cast<const __shim_type_info*>(exception_header->exceptionType);
+ if (adjustedPtr == 0 || excpType == 0)
+ {
+ // Something very bad happened
+ call_terminate(native_exception, unwind_exception);
+ }
+ if (catchType->can_catch(excpType, adjustedPtr))
+ {
+ // Found a matching handler
+ // If this is a type 1 search save state and return _URC_HANDLER_FOUND
+ // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1!
+ // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan
+ if (actions & _UA_SEARCH_PHASE)
+ {
+ // Save state and return _URC_HANDLER_FOUND
+ results.ttypeIndex = ttypeIndex;
+ results.actionRecord = actionRecord;
+ results.landingPad = landingPad;
+ results.adjustedPtr = adjustedPtr;
+ results.reason = _URC_HANDLER_FOUND;
+ return;
+ }
+ else if (!(actions & _UA_FORCE_UNWIND))
+ {
+ // It looks like the exception table has changed
+ // on us. Likely stack corruption!
+ call_terminate(native_exception, unwind_exception);
+ }
+ }
+ }
+ // Scan next action ...
+ }
+ else if (ttypeIndex < 0)
+ {
+ // Found an exception spec. If this is a foreign exception,
+ // it is always caught.
+ if (native_exception)
+ {
+ // Does the exception spec catch this native exception?
+ __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+ void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
+ const __shim_type_info* excpType =
+ static_cast<const __shim_type_info*>(exception_header->exceptionType);
+ if (adjustedPtr == 0 || excpType == 0)
+ {
+ // Something very bad happened
+ call_terminate(native_exception, unwind_exception);
+ }
+ if (exception_spec_can_catch(ttypeIndex, classInfo,
+ ttypeEncoding, excpType,
+ adjustedPtr, unwind_exception))
+ {
+ // native exception caught by exception spec
+ // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
+ // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
+ // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
+ if (actions & _UA_SEARCH_PHASE)
+ {
+ // Save state and return _URC_HANDLER_FOUND
+ results.ttypeIndex = ttypeIndex;
+ results.actionRecord = actionRecord;
+ results.landingPad = landingPad;
+ results.adjustedPtr = adjustedPtr;
+ results.reason = _URC_HANDLER_FOUND;
+ return;
+ }
+ else if (!(actions & _UA_FORCE_UNWIND))
+ {
+ // It looks like the exception table has changed
+ // on us. Likely stack corruption!
+ call_terminate(native_exception, unwind_exception);
+ }
+ }
+ }
+ else
+ {
+ // foreign exception caught by exception spec
+ // If this is a type 1 search, save state and return _URC_HANDLER_FOUND
+ // If this is a type 2 search, save state and return _URC_HANDLER_FOUND
+ // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
+ // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
+ if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
+ {
+ // Save state and return _URC_HANDLER_FOUND
+ results.ttypeIndex = ttypeIndex;
+ results.actionRecord = actionRecord;
+ results.landingPad = landingPad;
+ results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
+ results.reason = _URC_HANDLER_FOUND;
+ return;
+ }
+ else if (!(actions & _UA_FORCE_UNWIND))
+ {
+ // It looks like the exception table has changed
+ // on us. Likely stack corruption!
+ call_terminate(native_exception, unwind_exception);
+ }
+ }
+ // Scan next action ...
+ }
+ else // ttypeIndex == 0
+ {
+ // Found a cleanup
+ // If this is a type 1 search, ignore it and continue scan
+ // If this is a type 2 search, ignore it and continue scan
+ // If this is a type 3 search, save state and return _URC_HANDLER_FOUND
+ if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
+ {
+ // Save state and return _URC_HANDLER_FOUND
+ results.ttypeIndex = ttypeIndex;
+ results.actionRecord = actionRecord;
+ results.landingPad = landingPad;
+ results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
+ results.reason = _URC_HANDLER_FOUND;
+ return;
+ }
+ }
+ const uint8_t* temp = action;
+ int64_t actionOffset = readSLEB128(&temp);
+ if (actionOffset == 0)
+ {
+ // End of action list, no matching handler or cleanup found
+ results.reason = _URC_CONTINUE_UNWIND;
+ return;
+ }
+ // Go to next action
+ action += actionOffset;
+ } // there is no break out of this loop, only return
+ }
+ else if (ipOffset < start)
+ {
+ // There is no call site for this ip
+ // Something bad has happened. We should never get here.
+ // Possible stack corruption.
+ call_terminate(native_exception, unwind_exception);
+ }
+ } // there is no break out of this loop, only return
+}
+
+// public API
+
+/*
+The personality function branches on actions like so:
+
+_UA_SEARCH_PHASE
+
+ If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's
+ an error from above, return _URC_FATAL_PHASE1_ERROR.
+
+ Scan for anything that could stop unwinding:
+
+ 1. A catch clause that will catch this exception
+ (will never catch foreign).
+ 2. A catch (...) (will always catch foreign).
+ 3. An exception spec that will catch this exception
+ (will always catch foreign).
+ If a handler is found
+ If not foreign
+ Save state in header
+ return _URC_HANDLER_FOUND
+ Else a handler not found
+ return _URC_CONTINUE_UNWIND
+
+_UA_CLEANUP_PHASE
+
+ If _UA_HANDLER_FRAME
+ If _UA_FORCE_UNWIND
+ How did this happen? return _URC_FATAL_PHASE2_ERROR
+ If foreign
+ Do _UA_SEARCH_PHASE to recover state
+ else
+ Recover state from header
+ Transfer control to landing pad. return _URC_INSTALL_CONTEXT
+
+ Else
+
+ This branch handles both normal C++ non-catching handlers (cleanups)
+ and forced unwinding.
+ Scan for anything that can not stop unwinding:
+
+ 1. A cleanup.
+
+ If a cleanup is found
+ transfer control to it. return _URC_INSTALL_CONTEXT
+ Else a cleanup is not found: return _URC_CONTINUE_UNWIND
+*/
+
+_Unwind_Reason_Code
+__gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass,
+ _Unwind_Exception* unwind_exception, _Unwind_Context* context)
+{
+ if (version != 1 || unwind_exception == 0 || context == 0)
+ return _URC_FATAL_PHASE1_ERROR;
+ bool native_exception = (exceptionClass & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ scan_results results;
+ if (actions & _UA_SEARCH_PHASE)
+ {
+ // Phase 1 search: All we're looking for in phase 1 is a handler that
+ // halts unwinding
+ scan_eh_tab(results, actions, native_exception, unwind_exception, context);
+ if (results.reason == _URC_HANDLER_FOUND)
+ {
+ // Found one. Can we cache the results somewhere to optimize phase 2?
+ if (native_exception)
+ {
+ __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+ exception_header->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
+ exception_header->actionRecord = results.actionRecord;
+ exception_header->languageSpecificData = results.languageSpecificData;
+ exception_header->catchTemp = reinterpret_cast<void*>(results.landingPad);
+ exception_header->adjustedPtr = results.adjustedPtr;
+ }
+ return _URC_HANDLER_FOUND;
+ }
+ // Did not find a catching-handler. Return the results of the scan
+ // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE1_ERROR
+ // if we were called improperly).
+ return results.reason;
+ }
+ if (actions & _UA_CLEANUP_PHASE)
+ {
+ // Phase 2 search:
+ // Did we find a catching handler in phase 1?
+ if (actions & _UA_HANDLER_FRAME)
+ {
+ // Yes, phase 1 said we have a catching handler here.
+ // Did we cache the results of the scan?
+ if (native_exception)
+ {
+ // Yes, reload the results from the cache.
+ __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+ results.ttypeIndex = exception_header->handlerSwitchValue;
+ results.actionRecord = exception_header->actionRecord;
+ results.languageSpecificData = exception_header->languageSpecificData;
+ results.landingPad = reinterpret_cast<uintptr_t>(exception_header->catchTemp);
+ results.adjustedPtr = exception_header->adjustedPtr;
+ }
+ else
+ {
+ // No, do the scan again to reload the results.
+ scan_eh_tab(results, actions, native_exception, unwind_exception, context);
+ // Phase 1 told us we would find a handler. Now in Phase 2 we
+ // didn't find a handler. The eh table should not be changing!
+ if (results.reason != _URC_HANDLER_FOUND)
+ call_terminate(native_exception, unwind_exception);
+ }
+ // Jump to the handler
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), results.ttypeIndex);
+ _Unwind_SetIP(context, results.landingPad);
+ return _URC_INSTALL_CONTEXT;
+ }
+ // Either we didn't do a phase 1 search (due to forced unwinding), or
+ // phase 1 reported no catching-handlers.
+ // Search for a (non-catching) cleanup
+ scan_eh_tab(results, actions, native_exception, unwind_exception, context);
+ if (results.reason == _URC_HANDLER_FOUND)
+ {
+ // Found a non-catching handler. Jump to it:
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception);
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), results.ttypeIndex);
+ _Unwind_SetIP(context, results.landingPad);
+ return _URC_INSTALL_CONTEXT;
+ }
+ // Did not find a cleanup. Return the results of the scan
+ // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR
+ // if we were called improperly).
+ return results.reason;
+ }
+ // We were called improperly: neither a phase 1 or phase 2 search
+ return _URC_FATAL_PHASE1_ERROR;
+}
+
+__attribute__((noreturn))
+void
+__cxa_call_unexpected(void* arg)
+{
+ _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg);
+ if (unwind_exception == 0)
+ call_terminate(false, unwind_exception);
+ __cxa_begin_catch(unwind_exception);
+ bool native_old_exception =
+ (unwind_exception->exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ std::unexpected_handler u_handler;
+ std::terminate_handler t_handler;
+ __cxa_exception* old_exception_header = 0;
+ int64_t ttypeIndex;
+ const uint8_t* lsda;
+ if (native_old_exception)
+ {
+ old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
+ t_handler = old_exception_header->terminateHandler;
+ u_handler = old_exception_header->unexpectedHandler;
+ // If std::__unexpected(u_handler) rethrows the same exception,
+ // these values get overwritten by the rethrow. So save them now:
+ ttypeIndex = old_exception_header->handlerSwitchValue;
+ lsda = old_exception_header->languageSpecificData;
+ }
+ else
+ {
+ t_handler = std::get_terminate();
+ u_handler = std::get_unexpected();
+ }
+ try
+ {
+ std::__unexpected(u_handler);
+ }
+ catch (...)
+ {
+ // If the old exception is foreign, then all we can do is terminate.
+ // We have no way to recover the needed old exception spec. There's
+ // no way to pass that information here. And the personality routine
+ // can't call us directly and do anything but terminate() if we throw
+ // from here.
+ if (native_old_exception)
+ {
+ // Have:
+ // old_exception_header->languageSpecificData
+ // old_exception_header->actionRecord
+ // Need
+ // const uint8_t* classInfo
+ // uint8_t ttypeEncoding
+ uint8_t lpStartEncoding = *lsda++;
+ const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding);
+ uint8_t ttypeEncoding = *lsda++;
+ if (ttypeEncoding == DW_EH_PE_omit)
+ std::__terminate(t_handler);
+ uintptr_t classInfoOffset = readULEB128(&lsda);
+ const uint8_t* classInfo = lsda + classInfoOffset;
+ // Is this new exception catchable by the exception spec at ttypeIndex?
+ // The answer is obviously yes if the new and old exceptions are the same exception
+ // If no
+ // throw;
+ __cxa_eh_globals* globals = __cxa_get_globals_fast();
+ __cxa_exception* new_exception_header = globals->caughtExceptions;
+ if (new_exception_header == 0)
+ // This shouldn't be able to happen!
+ std::__terminate(t_handler);
+ bool native_new_exception =
+ (new_exception_header->unwindHeader.exception_class & get_vendor_and_language) ==
+ (kOurExceptionClass & get_vendor_and_language);
+ void* adjustedPtr;
+ if (native_new_exception && (new_exception_header != old_exception_header))
+ {
+ const __shim_type_info* excpType =
+ static_cast<const __shim_type_info*>(new_exception_header->exceptionType);
+ adjustedPtr =
+ new_exception_header->unwindHeader.exception_class == kOurDependentExceptionClass ?
+ ((__cxa_dependent_exception*)new_exception_header)->primaryException :
+ new_exception_header + 1;
+ if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
+ excpType, adjustedPtr, unwind_exception))
+ {
+ // We need to __cxa_end_catch, but for the old exception,
+ // not the new one. This is a little tricky ...
+ // Disguise new_exception_header as a rethrown exception, but
+ // don't actually rethrow it. This means you can temporarily
+ // end the catch clause enclosing new_exception_header without
+ // __cxa_end_catch destroying new_exception_header.
+ new_exception_header->handlerCount = -new_exception_header->handlerCount;
+ globals->uncaughtExceptions += 1;
+ // Call __cxa_end_catch for new_exception_header
+ __cxa_end_catch();
+ // Call __cxa_end_catch for old_exception_header
+ __cxa_end_catch();
+ // Renter this catch clause with new_exception_header
+ __cxa_begin_catch(&new_exception_header->unwindHeader);
+ // Rethrow new_exception_header
+ throw;
+ }
+ }
+ // Will a std::bad_exception be catchable by the exception spec at
+ // ttypeIndex?
+ // If no
+ // throw std::bad_exception();
+ const __shim_type_info* excpType =
+ static_cast<const __shim_type_info*>(&typeid(std::bad_exception));
+ std::bad_exception be;
+ adjustedPtr = &be;
+ if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding,
+ excpType, adjustedPtr, unwind_exception))
+ {
+ // We need to __cxa_end_catch for both the old exception and the
+ // new exception. Technically we should do it in that order.
+ // But it is expedent to do it in the opposite order:
+ // Call __cxa_end_catch for new_exception_header
+ __cxa_end_catch();
+ // Throw std::bad_exception will __cxa_end_catch for
+ // old_exception_header
+ throw be;
+ }
+ }
+ }
+ std::__terminate(t_handler);
+}
+
+} // extern "C"
+
+} // __cxxabiv1
diff --git a/system/lib/libcxxabi/src/cxa_unexpected.cpp b/system/lib/libcxxabi/src/cxa_unexpected.cpp
new file mode 100644
index 00000000..f6e6b6ab
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_unexpected.cpp
@@ -0,0 +1,27 @@
+//===------------------------- cxa_unexpected.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+#include <cxxabi.h>
+#include "cxa_exception.hpp"
+
+namespace __cxxabiv1
+{
+
+#pragma GCC visibility push(default)
+
+extern "C"
+{
+
+}
+
+#pragma GCC visibility pop
+
+} // namespace __cxxabiv1
+
diff --git a/system/lib/libcxxabi/src/cxa_vector.cpp b/system/lib/libcxxabi/src/cxa_vector.cpp
new file mode 100644
index 00000000..926c01dd
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_vector.cpp
@@ -0,0 +1,367 @@
+//===-------------------------- cxa_vector.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// This file implements the "Array Construction and Destruction APIs"
+// http://www.codesourcery.com/public/cxx-abi/abi.html#array-ctor
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxxabi.h"
+
+#include <exception> // for std::terminate
+
+namespace __cxxabiv1 {
+
+#pragma mark --Helper routines and classes --
+
+namespace {
+ inline static size_t __get_element_count ( void *p ) {
+ return static_cast <size_t *> (p)[-1];
+ }
+
+ inline static void __set_element_count ( void *p, size_t element_count ) {
+ static_cast <size_t *> (p)[-1] = element_count;
+ }
+
+
+// A pair of classes to simplify exception handling and control flow.
+// They get passed a block of memory in the constructor, and unless the
+// 'release' method is called, they deallocate the memory in the destructor.
+// Prefered usage is to allocate some memory, attach it to one of these objects,
+// and then, when all the operations to set up the memory block have succeeded,
+// call 'release'. If any of the setup operations fail, or an exception is
+// thrown, then the block is automatically deallocated.
+//
+// The only difference between these two classes is the signature for the
+// deallocation function (to match new2/new3 and delete2/delete3.
+ class st_heap_block2 {
+ public:
+ typedef void (*dealloc_f)(void *);
+
+ st_heap_block2 ( dealloc_f dealloc, void *ptr )
+ : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {}
+ ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; }
+ void release () { enabled_ = false; }
+
+ private:
+ dealloc_f dealloc_;
+ void *ptr_;
+ bool enabled_;
+ };
+
+ class st_heap_block3 {
+ public:
+ typedef void (*dealloc_f)(void *, size_t);
+
+ st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size )
+ : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {}
+ ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; }
+ void release () { enabled_ = false; }
+
+ private:
+ dealloc_f dealloc_;
+ void *ptr_;
+ size_t size_;
+ bool enabled_;
+ };
+
+ class st_cxa_cleanup {
+ public:
+ typedef void (*destruct_f)(void *);
+
+ st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor )
+ : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ),
+ destructor_ ( destructor ), enabled_ ( true ) {}
+ ~st_cxa_cleanup () {
+ if ( enabled_ )
+ __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ );
+ }
+
+ void release () { enabled_ = false; }
+
+ private:
+ void *ptr_;
+ size_t &idx_;
+ size_t element_size_;
+ destruct_f destructor_;
+ bool enabled_;
+ };
+
+ class st_terminate {
+ public:
+ st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {}
+ ~st_terminate () { if ( enabled_ ) std::terminate (); }
+ void release () { enabled_ = false; }
+ private:
+ bool enabled_ ;
+ };
+}
+
+#pragma mark --Externally visible routines--
+
+extern "C" {
+
+// Equivalent to
+//
+// __cxa_vec_new2(element_count, element_size, padding_size, constructor,
+// destructor, &::operator new[], &::operator delete[])
+void* __cxa_vec_new(
+ size_t element_count, size_t element_size, size_t padding_size,
+ void (*constructor)(void*), void (*destructor)(void*) ) {
+
+ return __cxa_vec_new2 ( element_count, element_size, padding_size,
+ constructor, destructor, &::operator new [], &::operator delete [] );
+}
+
+
+
+// Given the number and size of elements for an array and the non-negative
+// size of prefix padding for a cookie, allocate space (using alloc) for
+// the array preceded by the specified padding, initialize the cookie if
+// the padding is non-zero, and call the given constructor on each element.
+// Return the address of the array proper, after the padding.
+//
+// If alloc throws an exception, rethrow the exception. If alloc returns
+// NULL, return NULL. If the constructor throws an exception, call
+// destructor for any already constructed elements, and rethrow the
+// exception. If the destructor throws an exception, call std::terminate.
+//
+// The constructor may be NULL, in which case it must not be called. If the
+// padding_size is zero, the destructor may be NULL; in that case it must
+// not be called.
+//
+// Neither alloc nor dealloc may be NULL.
+void* __cxa_vec_new2(
+ size_t element_count, size_t element_size, size_t padding_size,
+ void (*constructor)(void*), void (*destructor)(void*),
+ void* (*alloc)(size_t), void (*dealloc)(void*) ) {
+
+ const size_t heap_size = element_count * element_size + padding_size;
+ char * const heap_block = static_cast<char *> ( alloc ( heap_size ));
+ char *vec_base = heap_block;
+
+ if ( NULL != vec_base ) {
+ st_heap_block2 heap ( dealloc, heap_block );
+
+ // put the padding before the array elements
+ if ( 0 != padding_size ) {
+ vec_base += padding_size;
+ __set_element_count ( vec_base, element_count );
+ }
+
+ // Construct the elements
+ __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
+ heap.release (); // We're good!
+ }
+
+ return vec_base;
+}
+
+
+// Same as __cxa_vec_new2 except that the deallocation function takes both
+// the object address and its size.
+void* __cxa_vec_new3(
+ size_t element_count, size_t element_size, size_t padding_size,
+ void (*constructor)(void*), void (*destructor)(void*),
+ void* (*alloc)(size_t), void (*dealloc)(void*, size_t) ) {
+
+ const size_t heap_size = element_count * element_size + padding_size;
+ char * const heap_block = static_cast<char *> ( alloc ( heap_size ));
+ char *vec_base = heap_block;
+
+ if ( NULL != vec_base ) {
+ st_heap_block3 heap ( dealloc, heap_block, heap_size );
+
+ // put the padding before the array elements
+ if ( 0 != padding_size ) {
+ vec_base += padding_size;
+ __set_element_count ( vec_base, element_count );
+ }
+
+ // Construct the elements
+ __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor );
+ heap.release (); // We're good!
+ }
+
+ return vec_base;
+}
+
+
+// Given the (data) addresses of a destination and a source array, an
+// element count and an element size, call the given copy constructor to
+// copy each element from the source array to the destination array. The
+// copy constructor's arguments are the destination address and source
+// address, respectively. If an exception occurs, call the given destructor
+// (if non-NULL) on each copied element and rethrow. If the destructor
+// throws an exception, call terminate(). The constructor and or destructor
+// pointers may be NULL. If either is NULL, no action is taken when it
+// would have been called.
+
+void __cxa_vec_cctor( void* dest_array, void* src_array,
+ size_t element_count, size_t element_size,
+ void (*constructor) (void*, void*), void (*destructor)(void*) ) {
+
+ if ( NULL != constructor ) {
+ size_t idx = 0;
+ char *src_ptr = static_cast<char *>(src_array);
+ char *dest_ptr = static_cast<char *>(dest_array);
+ st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor );
+
+ for ( idx = 0; idx < element_count;
+ ++idx, src_ptr += element_size, dest_ptr += element_size )
+ constructor ( dest_ptr, src_ptr );
+ cleanup.release (); // We're good!
+ }
+}
+
+
+// Given the (data) address of an array, not including any cookie padding,
+// and the number and size of its elements, call the given constructor on
+// each element. If the constructor throws an exception, call the given
+// destructor for any already-constructed elements, and rethrow the
+// exception. If the destructor throws an exception, call terminate(). The
+// constructor and/or destructor pointers may be NULL. If either is NULL,
+// no action is taken when it would have been called.
+void __cxa_vec_ctor(
+ void* array_address, size_t element_count, size_t element_size,
+ void (*constructor)(void*), void (*destructor)(void*) ) {
+
+ if ( NULL != constructor ) {
+ size_t idx;
+ char *ptr = static_cast <char *> ( array_address );
+ st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
+
+ // Construct the elements
+ for ( idx = 0; idx < element_count; ++idx, ptr += element_size )
+ constructor ( ptr );
+ cleanup.release (); // We're good!
+ }
+}
+
+// Given the (data) address of an array, the number of elements, and the
+// size of its elements, call the given destructor on each element. If the
+// destructor throws an exception, rethrow after destroying the remaining
+// elements if possible. If the destructor throws a second exception, call
+// terminate(). The destructor pointer may be NULL, in which case this
+// routine does nothing.
+void __cxa_vec_dtor(
+ void* array_address, size_t element_count, size_t element_size,
+ void (*destructor)(void*) ) {
+
+ if ( NULL != destructor ) {
+ char *ptr = static_cast <char *> (array_address);
+ size_t idx = element_count;
+ st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor );
+ {
+ st_terminate exception_guard (__cxa_uncaught_exception ());
+ ptr += element_count * element_size; // one past the last element
+
+ while ( idx-- > 0 ) {
+ ptr -= element_size;
+ destructor ( ptr );
+ }
+ exception_guard.release (); // We're good !
+ }
+ cleanup.release (); // We're still good!
+ }
+}
+
+// Given the (data) address of an array, the number of elements, and the
+// size of its elements, call the given destructor on each element. If the
+// destructor throws an exception, call terminate(). The destructor pointer
+// may be NULL, in which case this routine does nothing.
+void __cxa_vec_cleanup( void* array_address, size_t element_count,
+ size_t element_size, void (*destructor)(void*) ) {
+
+ if ( NULL != destructor ) {
+ char *ptr = static_cast <char *> (array_address);
+ size_t idx = element_count;
+ st_terminate exception_guard;
+
+ ptr += element_count * element_size; // one past the last element
+ while ( idx-- > 0 ) {
+ ptr -= element_size;
+ destructor ( ptr );
+ }
+ exception_guard.release (); // We're done!
+ }
+}
+
+
+// If the array_address is NULL, return immediately. Otherwise, given the
+// (data) address of an array, the non-negative size of prefix padding for
+// the cookie, and the size of its elements, call the given destructor on
+// each element, using the cookie to determine the number of elements, and
+// then delete the space by calling ::operator delete[](void *). If the
+// destructor throws an exception, rethrow after (a) destroying the
+// remaining elements, and (b) deallocating the storage. If the destructor
+// throws a second exception, call terminate(). If padding_size is 0, the
+// destructor pointer must be NULL. If the destructor pointer is NULL, no
+// destructor call is to be made.
+//
+// The intent of this function is to permit an implementation to call this
+// function when confronted with an expression of the form delete[] p in
+// the source code, provided that the default deallocation function can be
+// used. Therefore, the semantics of this function are consistent with
+// those required by the standard. The requirement that the deallocation
+// function be called even if the destructor throws an exception derives
+// from the resolution to DR 353 to the C++ standard, which was adopted in
+// April, 2003.
+void __cxa_vec_delete( void* array_address,
+ size_t element_size, size_t padding_size, void (*destructor)(void*) ) {
+
+ __cxa_vec_delete2 ( array_address, element_size, padding_size,
+ destructor, &::operator delete [] );
+}
+
+
+// Same as __cxa_vec_delete, except that the given function is used for
+// deallocation instead of the default delete function. If dealloc throws
+// an exception, the result is undefined. The dealloc pointer may not be
+// NULL.
+void __cxa_vec_delete2( void* array_address,
+ size_t element_size, size_t padding_size,
+ void (*destructor)(void*), void (*dealloc)(void*) ) {
+
+ if ( NULL != array_address ) {
+ char *vec_base = static_cast <char *> (array_address);
+ char *heap_block = vec_base - padding_size;
+ st_heap_block2 heap ( dealloc, heap_block );
+
+ if ( 0 != padding_size && NULL != destructor ) // call the destructors
+ __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ),
+ element_size, destructor );
+ }
+}
+
+
+// Same as __cxa_vec_delete, except that the given function is used for
+// deallocation instead of the default delete function. The deallocation
+// function takes both the object address and its size. If dealloc throws
+// an exception, the result is undefined. The dealloc pointer may not be
+// NULL.
+void __cxa_vec_delete3( void* array_address,
+ size_t element_size, size_t padding_size,
+ void (*destructor)(void*), void (*dealloc) (void*, size_t)) {
+
+ if ( NULL != array_address ) {
+ char *vec_base = static_cast <char *> (array_address);
+ char *heap_block = vec_base - padding_size;
+ const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0;
+ const size_t heap_block_size = element_size * element_count + padding_size;
+ st_heap_block3 heap ( dealloc, heap_block, heap_block_size );
+
+ if ( 0 != padding_size && NULL != destructor ) // call the destructors
+ __cxa_vec_dtor ( array_address, element_count, element_size, destructor );
+ }
+}
+
+
+} // extern "C"
+
+} // abi
diff --git a/system/lib/libcxxabi/src/cxa_virtual.cpp b/system/lib/libcxxabi/src/cxa_virtual.cpp
new file mode 100644
index 00000000..437b6016
--- /dev/null
+++ b/system/lib/libcxxabi/src/cxa_virtual.cpp
@@ -0,0 +1,31 @@
+//===-------------------------- cxa_virtual.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "cxxabi.h"
+#include "abort_message.h"
+
+namespace __cxxabiv1
+{
+
+extern "C"
+{
+
+LIBCXXABI_NORETURN
+void __cxa_pure_virtual(void) {
+ abort_message("Pure virtual function called!");
+}
+
+LIBCXXABI_NORETURN
+void __cxa_deleted_virtual(void) {
+ abort_message("Deleted virtual function called!");
+}
+
+} // extern "C"
+
+} // abi
diff --git a/system/lib/libcxxabi/src/exception.cpp b/system/lib/libcxxabi/src/exception.cpp
new file mode 100644
index 00000000..c47a9b76
--- /dev/null
+++ b/system/lib/libcxxabi/src/exception.cpp
@@ -0,0 +1,41 @@
+//===---------------------------- exception.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+
+#pragma GCC visibility push(default)
+
+namespace std
+{
+
+// exception
+
+exception::~exception() _NOEXCEPT
+{
+}
+
+const char* exception::what() const _NOEXCEPT
+{
+ return "std::exception";
+}
+
+// bad_exception
+
+bad_exception::~bad_exception() _NOEXCEPT
+{
+}
+
+const char* bad_exception::what() const _NOEXCEPT
+{
+ return "std::bad_exception";
+}
+
+} // std
+
+#pragma GCC visibility pop
diff --git a/system/lib/libcxxabi/src/fallback_malloc.ipp b/system/lib/libcxxabi/src/fallback_malloc.ipp
new file mode 100644
index 00000000..979f0bbd
--- /dev/null
+++ b/system/lib/libcxxabi/src/fallback_malloc.ipp
@@ -0,0 +1,174 @@
+//===------------------------ fallback_malloc.ipp -------------------------===//
+//
+// 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.
+//
+//
+// This file implements the "Exception Handling APIs"
+// http://www.codesourcery.com/public/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+// A small, simple heap manager based (loosely) on
+// the startup heap manager from FreeBSD, optimized for space.
+//
+// Manages a fixed-size memory pool, supports malloc and free only.
+// No support for realloc.
+//
+// Allocates chunks in multiples of four bytes, with a four byte header
+// for each chunk. The overhead of each chunk is kept low by keeping pointers
+// as two byte offsets within the heap, rather than (4 or 8 byte) pointers.
+
+namespace {
+
+static pthread_mutex_t heap_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+class mutexor {
+public:
+ mutexor ( pthread_mutex_t *m ) : mtx_(m) { pthread_mutex_lock ( mtx_ ); }
+ ~mutexor () { pthread_mutex_unlock ( mtx_ ); }
+private:
+ mutexor ( const mutexor &rhs );
+ mutexor & operator = ( const mutexor &rhs );
+ pthread_mutex_t *mtx_;
+ };
+
+
+#define HEAP_SIZE 512
+char heap [ HEAP_SIZE ];
+
+typedef unsigned short heap_offset;
+typedef unsigned short heap_size;
+
+struct heap_node {
+ heap_offset next_node; // offset into heap
+ heap_size len; // size in units of "sizeof(heap_node)"
+};
+
+static const heap_node *list_end = (heap_node *) ( &heap [ HEAP_SIZE ] ); // one past the end of the heap
+static heap_node *freelist = NULL;
+
+heap_node *node_from_offset ( const heap_offset offset )
+ { return (heap_node *) ( heap + ( offset * sizeof (heap_node))); }
+
+heap_offset offset_from_node ( const heap_node *ptr )
+ { return (((char *) ptr ) - heap) / sizeof (heap_node); }
+
+void init_heap () {
+ freelist = (heap_node *) heap;
+ freelist->next_node = offset_from_node ( list_end );
+ freelist->len = HEAP_SIZE / sizeof (heap_node);
+ }
+
+// How big a chunk we allocate
+size_t alloc_size (size_t len)
+ { return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1; }
+
+bool is_fallback_ptr ( void *ptr )
+ { return ptr >= heap && ptr < ( heap + HEAP_SIZE ); }
+
+void *fallback_malloc(size_t len) {
+ heap_node *p, *prev;
+ const size_t nelems = alloc_size ( len );
+ mutexor mtx ( &heap_mutex );
+
+ if ( NULL == freelist )
+ init_heap ();
+
+// Walk the free list, looking for a "big enough" chunk
+ for (p = freelist, prev = 0;
+ p && p != list_end; prev = p, p = node_from_offset ( p->next_node)) {
+
+ if (p->len > nelems) { // chunk is larger, shorten, and return the tail
+ heap_node *q;
+
+ p->len -= nelems;
+ q = p + p->len;
+ q->next_node = 0;
+ q->len = nelems;
+ return (void *) (q + 1);
+ }
+
+ if (p->len == nelems) { // exact size match
+ if (prev == 0)
+ freelist = node_from_offset(p->next_node);
+ else
+ prev->next_node = p->next_node;
+ p->next_node = 0;
+ return (void *) (p + 1);
+ }
+ }
+ return NULL; // couldn't find a spot big enough
+}
+
+// Return the start of the next block
+heap_node *after ( struct heap_node *p ) { return p + p->len; }
+
+void fallback_free (void *ptr) {
+ struct heap_node *cp = ((struct heap_node *) ptr) - 1; // retrieve the chunk
+ struct heap_node *p, *prev;
+
+ mutexor mtx ( &heap_mutex );
+
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << "Freeing item at " << offset_from_node ( cp ) << " of size " << cp->len << std::endl;
+#endif
+
+ for (p = freelist, prev = 0;
+ p && p != list_end; prev = p, p = node_from_offset (p->next_node)) {
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " p, cp, after (p), after(cp) "
+ << offset_from_node ( p ) << ' '
+ << offset_from_node ( cp ) << ' '
+ << offset_from_node ( after ( p )) << ' '
+ << offset_from_node ( after ( cp )) << std::endl;
+#endif
+ if ( after ( p ) == cp ) {
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " Appending onto chunk at " << offset_from_node ( p ) << std::endl;
+#endif
+ p->len += cp->len; // make the free heap_node larger
+ return;
+ }
+ else if ( after ( cp ) == p ) { // there's a free heap_node right after
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " Appending free chunk at " << offset_from_node ( p ) << std::endl;
+#endif
+ cp->len += p->len;
+ if ( prev == 0 ) {
+ freelist = cp;
+ cp->next_node = p->next_node;
+ }
+ else
+ prev->next_node = offset_from_node(cp);
+ return;
+ }
+ }
+// Nothing to merge with, add it to the start of the free list
+#ifdef DEBUG_FALLBACK_MALLOC
+ std::cout << " Making new free list entry " << offset_from_node ( cp ) << std::endl;
+#endif
+ cp->next_node = offset_from_node ( freelist );
+ freelist = cp;
+}
+
+#ifdef INSTRUMENT_FALLBACK_MALLOC
+size_t print_free_list () {
+ struct heap_node *p, *prev;
+ heap_size total_free = 0;
+ if ( NULL == freelist )
+ init_heap ();
+
+ for (p = freelist, prev = 0;
+ p && p != list_end; prev = p, p = node_from_offset (p->next_node)) {
+ std::cout << ( prev == 0 ? "" : " ") << "Offset: " << offset_from_node ( p )
+ << "\tsize: " << p->len << " Next: " << p->next_node << std::endl;
+ total_free += p->len;
+ }
+ std::cout << "Total Free space: " << total_free << std::endl;
+ return total_free;
+ }
+#endif
+} // end unnamed namespace
diff --git a/system/lib/libcxxabi/src/private_typeinfo.cpp b/system/lib/libcxxabi/src/private_typeinfo.cpp
new file mode 100644
index 00000000..269116b6
--- /dev/null
+++ b/system/lib/libcxxabi/src/private_typeinfo.cpp
@@ -0,0 +1,1036 @@
+//===----------------------- private_typeinfo.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "private_typeinfo.h"
+
+namespace __cxxabiv1
+{
+
+#pragma GCC visibility push(hidden)
+
+// __shim_type_info
+
+__shim_type_info::~__shim_type_info()
+{
+}
+
+// __fundamental_type_info
+
+// This miraculously (compiler magic) emits the type_info's for:
+// 1. all of the fundamental types
+// 2. pointers to all of the fundamental types
+// 3. pointers to all of the const fundamental types
+__fundamental_type_info::~__fundamental_type_info()
+{
+}
+
+// __array_type_info
+
+__array_type_info::~__array_type_info()
+{
+}
+
+// __function_type_info
+
+__function_type_info::~__function_type_info()
+{
+}
+
+// __enum_type_info
+
+__enum_type_info::~__enum_type_info()
+{
+}
+
+// __class_type_info
+
+__class_type_info::~__class_type_info()
+{
+}
+
+// __si_class_type_info
+
+__si_class_type_info::~__si_class_type_info()
+{
+}
+
+// __vmi_class_type_info
+
+__vmi_class_type_info::~__vmi_class_type_info()
+{
+}
+
+// __pbase_type_info
+
+__pbase_type_info::~__pbase_type_info()
+{
+}
+
+// __pointer_type_info
+
+__pointer_type_info::~__pointer_type_info()
+{
+}
+
+// __pointer_to_member_type_info
+
+__pointer_to_member_type_info::~__pointer_to_member_type_info()
+{
+}
+
+// can_catch
+
+// A handler is a match for an exception object of type E if
+// 1. The handler is of type cv T or cv T& and E and T are the same type
+// (ignoring the top-level cv-qualifiers), or
+// 2. the handler is of type cv T or cv T& and T is an unambiguous public
+// base class of E, or
+// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be
+// converted to the type of the handler by either or both of
+// A. a standard pointer conversion (4.10) not involving conversions to
+// pointers to private or protected or ambiguous classes
+// B. a qualification conversion
+// 4. the handler is a pointer or pointer to member type and E is
+// std::nullptr_t.
+
+// adjustedPtr:
+//
+// catch (A& a) : adjustedPtr == &a
+// catch (A* a) : adjustedPtr == a
+// catch (A** a) : adjustedPtr == a
+//
+// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object)
+// catch (D2* d2) : adjustedPtr == d2
+// catch (D2*& d2) : adjustedPtr == d2
+//
+// catch (...) : adjustedPtr == & of the exception
+
+// Handles bullet 1
+bool
+__fundamental_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ return this == thrown_type;
+}
+
+bool
+__array_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ // We can get here if someone tries to catch an array by reference.
+ // However if someone tries to throw an array, it immediately gets
+ // converted to a pointer, which will not convert back to an array
+ // at the catch clause. So this can never catch anything.
+ return false;
+}
+
+bool
+__function_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ // We can get here if someone tries to catch a function by reference.
+ // However if someone tries to throw a function, it immediately gets
+ // converted to a pointer, which will not convert back to a function
+ // at the catch clause. So this can never catch anything.
+ return false;
+}
+
+// Handles bullet 1
+bool
+__enum_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ return this == thrown_type;
+}
+
+// Handles bullets 1 and 2
+bool
+__class_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*& adjustedPtr) const
+{
+ // bullet 1
+ if (this == thrown_type)
+ return true;
+ const __class_type_info* thrown_class_type =
+ dynamic_cast<const __class_type_info*>(thrown_type);
+ if (thrown_class_type == 0)
+ return false;
+ // bullet 2
+ __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0};
+ info.number_of_dst_type = 1;
+ thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
+ if (info.path_dst_ptr_to_static_ptr == public_path)
+ {
+ adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
+ return true;
+ }
+ return false;
+}
+
+void
+__class_type_info::process_found_base_class(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (info->dst_ptr_leading_to_static_ptr == 0)
+ {
+ // First time here
+ info->dst_ptr_leading_to_static_ptr = adjustedPtr;
+ info->path_dst_ptr_to_static_ptr = path_below;
+ info->number_to_static_ptr = 1;
+ }
+ else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr)
+ {
+ // We've been here before. Update path to "most public"
+ if (info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->path_dst_ptr_to_static_ptr = path_below;
+ }
+ else
+ {
+ // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr)
+ // to a static_type
+ info->number_to_static_ptr += 1;
+ info->path_dst_ptr_to_static_ptr = not_public_path;
+ info->search_done = true;
+ }
+}
+
+void
+__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (this == info->static_type)
+ process_found_base_class(info, adjustedPtr, path_below);
+}
+
+void
+__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (this == info->static_type)
+ process_found_base_class(info, adjustedPtr, path_below);
+ else
+ __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below);
+}
+
+void
+__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+ if (__offset_flags & __virtual_mask)
+ {
+ const char* vtable = *static_cast<const char*const*>(adjustedPtr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
+ }
+ __base_type->has_unambiguous_public_base(info,
+ static_cast<char*>(adjustedPtr) + offset_to_base,
+ (__offset_flags & __public_mask) ?
+ path_below :
+ not_public_path);
+}
+
+void
+__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info,
+ void* adjustedPtr,
+ int path_below) const
+{
+ if (this == info->static_type)
+ process_found_base_class(info, adjustedPtr, path_below);
+ else
+ {
+ typedef const __base_class_type_info* Iter;
+ const Iter e = __base_info + __base_count;
+ Iter p = __base_info;
+ p->has_unambiguous_public_base(info, adjustedPtr, path_below);
+ if (++p < e)
+ {
+ do
+ {
+ p->has_unambiguous_public_base(info, adjustedPtr, path_below);
+ if (info->search_done)
+ break;
+ } while (++p < e);
+ }
+ }
+}
+
+// Handles bullets 1 and 4 for both pointers and member pointers
+bool
+__pbase_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*&) const
+{
+ if (this == thrown_type)
+ return true;
+ return thrown_type == &typeid(std::nullptr_t);
+}
+
+// Handles bullets 1, 3 and 4
+bool
+__pointer_type_info::can_catch(const __shim_type_info* thrown_type,
+ void*& adjustedPtr) const
+{
+ // Do the dereference adjustment
+ adjustedPtr = *static_cast<void**>(adjustedPtr);
+ // bullets 1 and 4
+ if (__pbase_type_info::can_catch(thrown_type, adjustedPtr))
+ return true;
+ // bullet 3
+ const __pointer_type_info* thrown_pointer_type =
+ dynamic_cast<const __pointer_type_info*>(thrown_type);
+ if (thrown_pointer_type == 0)
+ return false;
+ // bullet 3B
+ if (thrown_pointer_type->__flags & ~__flags)
+ return false;
+ if (__pointee == thrown_pointer_type->__pointee)
+ return true;
+ // bullet 3A
+ if (__pointee == &typeid(void))
+ return true;
+ const __class_type_info* catch_class_type =
+ dynamic_cast<const __class_type_info*>(__pointee);
+ if (catch_class_type == 0)
+ return false;
+ const __class_type_info* thrown_class_type =
+ dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee);
+ if (thrown_class_type == 0)
+ return false;
+ __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0};
+ info.number_of_dst_type = 1;
+ thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path);
+ if (info.path_dst_ptr_to_static_ptr == public_path)
+ {
+ adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr);
+ return true;
+ }
+ return false;
+}
+
+#pragma GCC visibility pop
+#pragma GCC visibility push(default)
+
+// __dynamic_cast
+
+// static_ptr: pointer to an object of type static_type; nonnull, and since the
+// object is polymorphic, *(void**)static_ptr is a virtual table pointer.
+// static_ptr is &v in the expression dynamic_cast<T>(v).
+// static_type: static type of the object pointed to by static_ptr.
+// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)").
+// src2dst_offset: a static hint about the location of the
+// source subobject with respect to the complete object;
+// special negative values are:
+// -1: no hint
+// -2: static_type is not a public base of dst_type
+// -3: static_type is a multiple public base type but never a
+// virtual base type
+// otherwise, the static_type type is a unique public nonvirtual
+// base type of dst_type at offset src2dst_offset from the
+// origin of dst_type.
+//
+// (dynamic_ptr, dynamic_type) are the run time type of the complete object
+// referred to by static_ptr and a pointer to it. These can be found from
+// static_ptr for polymorphic types.
+// static_type is guaranteed to be a polymorphic type.
+//
+// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each
+// node of the tree represents a base class/object of its parent (or parents) below.
+// Each node is uniquely represented by a pointer to the object, and a pointer
+// to a type_info - its type. Different nodes may have the same pointer and
+// different nodes may have the same type. But only one node has a specific
+// (pointer-value, type) pair. In C++ two objects of the same type can not
+// share the same address.
+//
+// There are two flavors of nodes which have the type dst_type:
+// 1. Those that are derived from (below) (static_ptr, static_type).
+// 2. Those that are not derived from (below) (static_ptr, static_type).
+//
+// Invariants of the DAG:
+//
+// There is at least one path from the root (dynamic_ptr, dynamic_type) to
+// the node (static_ptr, static_type). This path may or may not be public.
+// There may be more than one such path (some public some not). Such a path may
+// or may not go through a node having type dst_type.
+//
+// No node of type T appears above a node of the same type. That means that
+// there is only one node with dynamic_type. And if dynamic_type == dst_type,
+// then there is only one dst_type in the DAG.
+//
+// No node of type dst_type appears above a node of type static_type. Such
+// DAG's are possible in C++, but the compiler computes those dynamic_casts at
+// compile time, and only calls __dynamic_cast when dst_type lies below
+// static_type in the DAG.
+//
+// dst_type != static_type: The compiler computes the dynamic_cast in this case too.
+// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too.
+//
+// Returns:
+//
+// If there is exactly one dst_type of flavor 1, and
+// If there is a public path from that dst_type to (static_ptr, static_type), or
+// If there are 0 dst_types of flavor 2, and there is a public path from
+// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public
+// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return
+// a pointer to that dst_type.
+// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and
+// if there is a public path from (dynamic_ptr, dynamic_type) to
+// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type)
+// to the one dst_type, then return a pointer to that one dst_type.
+// Else return nullptr.
+//
+// If dynamic_type == dst_type, then the above algorithm collapses to the
+// following cheaper algorithm:
+//
+// If there is a public path from (dynamic_ptr, dynamic_type) to
+// (static_ptr, static_type), then return dynamic_ptr.
+// Else return nullptr.
+extern "C"
+void*
+__dynamic_cast(const void* static_ptr,
+ const __class_type_info* static_type,
+ const __class_type_info* dst_type,
+ std::ptrdiff_t src2dst_offset)
+{
+ // Possible future optimization: Take advantage of src2dst_offset
+ // Currently clang always sets src2dst_offset to -1 (no hint).
+
+ // Get (dynamic_ptr, dynamic_type) from static_ptr
+ void** vtable = *(void***)static_ptr;
+ ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]);
+ const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived;
+ const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]);
+
+ // Initialize answer to nullptr. This will be changed from the search
+ // results if a non-null answer is found. Regardless, this is what will
+ // be returned.
+ const void* dst_ptr = 0;
+ // Initialize info struct for this search.
+ __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0};
+
+ // Find out if we can use a giant short cut in the search
+ if (dynamic_type == dst_type)
+ {
+ // Using giant short cut. Add that information to info.
+ info.number_of_dst_type = 1;
+ // Do the search
+ dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path);
+ // Query the search.
+ if (info.path_dst_ptr_to_static_ptr == public_path)
+ dst_ptr = dynamic_ptr;
+ }
+ else
+ {
+ // Not using giant short cut. Do the search
+ dynamic_type->search_below_dst(&info, dynamic_ptr, public_path);
+ // Query the search.
+ switch (info.number_to_static_ptr)
+ {
+ case 0:
+ if (info.number_to_dst_ptr == 1 &&
+ info.path_dynamic_ptr_to_static_ptr == public_path &&
+ info.path_dynamic_ptr_to_dst_ptr == public_path)
+ dst_ptr = info.dst_ptr_not_leading_to_static_ptr;
+ break;
+ case 1:
+ if (info.path_dst_ptr_to_static_ptr == public_path ||
+ (
+ info.number_to_dst_ptr == 0 &&
+ info.path_dynamic_ptr_to_static_ptr == public_path &&
+ info.path_dynamic_ptr_to_dst_ptr == public_path
+ )
+ )
+ dst_ptr = info.dst_ptr_leading_to_static_ptr;
+ break;
+ }
+ }
+ return const_cast<void*>(dst_ptr);
+}
+
+#pragma GCC visibility pop
+#pragma GCC visibility push(hidden)
+
+// Call this function when you hit a static_type which is a base (above) a dst_type.
+// Let caller know you hit a static_type. But only start recording details if
+// this is (static_ptr, static_type) -- the node we are casting from.
+// If this is (static_ptr, static_type)
+// Record the path (public or not) from the dst_type to here. There may be
+// multiple paths from the same dst_type to here, record the "most public" one.
+// Record the dst_ptr as pointing to (static_ptr, static_type).
+// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type),
+// then mark this dyanmic_cast as ambiguous and stop the search.
+void
+__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below) const
+{
+ // Record that we found a static_type
+ info->found_any_static_type = true;
+ if (current_ptr == info->static_ptr)
+ {
+ // Record that we found (static_ptr, static_type)
+ info->found_our_static_ptr = true;
+ if (info->dst_ptr_leading_to_static_ptr == 0)
+ {
+ // First time here
+ info->dst_ptr_leading_to_static_ptr = dst_ptr;
+ info->path_dst_ptr_to_static_ptr = path_below;
+ info->number_to_static_ptr = 1;
+ // If there is only one dst_type in the entire tree and the path from
+ // there to here is public then we are done!
+ if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
+ info->search_done = true;
+ }
+ else if (info->dst_ptr_leading_to_static_ptr == dst_ptr)
+ {
+ // We've been here before. Update path to "most public"
+ if (info->path_dst_ptr_to_static_ptr == not_public_path)
+ info->path_dst_ptr_to_static_ptr = path_below;
+ // If there is only one dst_type in the entire tree and the path from
+ // there to here is public then we are done!
+ if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path)
+ info->search_done = true;
+ }
+ else
+ {
+ // We've detected an ambiguous cast from (static_ptr, static_type)
+ // to a dst_type
+ info->number_to_static_ptr += 1;
+ info->search_done = true;
+ }
+ }
+}
+
+// Call this function when you hit a static_type which is not a base (above) a dst_type.
+// If this is (static_ptr, static_type)
+// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be
+// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one.
+void
+__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below) const
+{
+ if (current_ptr == info->static_ptr)
+ {
+ // Record the most public path from (dynamic_ptr, dynamic_type) to
+ // (static_ptr, static_type)
+ if (info->path_dynamic_ptr_to_static_ptr != public_path)
+ info->path_dynamic_ptr_to_static_ptr = path_below;
+ }
+}
+
+// Call this function when searching below a dst_type node. This function searches
+// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes.
+// If it finds a static_type node, there is no need to further search base classes
+// above.
+// If it finds a dst_type node it should search base classes using search_above_dst
+// to find out if this dst_type points to (static_ptr, static_type) or not.
+// Either way, the dst_type is recorded as one of two "flavors": one that does
+// or does not point to (static_ptr, static_type).
+// If this is neither a static_type nor a dst_type node, continue searching
+// base classes above.
+// All the hoopla surrounding the search code is doing nothing but looking for
+// excuses to stop the search prematurely (break out of the for-loop). That is,
+// the algorithm below is simply an optimization of this:
+// void
+// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
+// const void* current_ptr,
+// int path_below) const
+// {
+// typedef const __base_class_type_info* Iter;
+// if (this == info->static_type)
+// process_static_type_below_dst(info, current_ptr, path_below);
+// else if (this == info->dst_type)
+// {
+// // Record the most public access path that got us here
+// if (info->path_dynamic_ptr_to_dst_ptr != public_path)
+// info->path_dynamic_ptr_to_dst_ptr = path_below;
+// bool does_dst_type_point_to_our_static_type = false;
+// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p)
+// {
+// p->search_above_dst(info, current_ptr, current_ptr, public_path);
+// if (info->found_our_static_ptr)
+// does_dst_type_point_to_our_static_type = true;
+// // break out early here if you can detect it doesn't matter if you do
+// }
+// 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;
+// }
+// }
+// else
+// {
+// // This is not a static_type and not a dst_type.
+// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
+// {
+// p->search_below_dst(info, current_ptr, public_path);
+// // break out early here if you can detect it doesn't matter if you do
+// }
+// }
+// }
+void
+__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below) const
+{
+ typedef const __base_class_type_info* Iter;
+ if (this == info->static_type)
+ process_static_type_below_dst(info, current_ptr, path_below);
+ else if (this == info->dst_type)
+ {
+ // We've been here before if we've recorded current_ptr in one of these
+ // two places:
+ if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
+ current_ptr == info->dst_ptr_not_leading_to_static_ptr)
+ {
+ // We've seen this node before, and therefore have already searched
+ // its base classes above.
+ // Update path to here that is "most public".
+ if (path_below == public_path)
+ info->path_dynamic_ptr_to_dst_ptr = public_path;
+ }
+ else // We have haven't been here before
+ {
+ // 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;
+ // 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).
+ // We can stop looking above if:
+ // 1. We've found a public path to (static_ptr, static_type).
+ // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
+ // This is detected at the (static_ptr, static_type).
+ // 3. We can prove that there is no public path to (static_ptr, static_type)
+ // above here.
+ const Iter e = __base_info + __base_count;
+ for (Iter p = __base_info; p < e; ++p)
+ {
+ // Zero out found flags
+ info->found_our_static_ptr = false;
+ info->found_any_static_type = false;
+ p->search_above_dst(info, current_ptr, current_ptr, public_path);
+ if (info->search_done)
+ break;
+ if (info->found_any_static_type)
+ {
+ is_dst_type_derived_from_static_type = true;
+ if (info->found_our_static_ptr)
+ {
+ does_dst_type_point_to_our_static_type = true;
+ // If we found what we're looking for, stop looking above.
+ if (info->path_dst_ptr_to_static_ptr == public_path)
+ break;
+ // We found a private path to (static_ptr, static_type)
+ // If there is no diamond then there is only one path
+ // to (static_ptr, static_type) and we just found it.
+ if (!(__flags & __diamond_shaped_mask))
+ break;
+ }
+ else
+ {
+ // If we found a static_type that isn't the one we're looking
+ // for, and if there are no repeated types above here,
+ // then stop looking.
+ if (!(__flags & __non_diamond_repeat_mask))
+ break;
+ }
+ }
+ }
+ 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
+ // it if it doesn't derive from static_type.
+ if (is_dst_type_derived_from_static_type)
+ info->is_dst_type_derived_from_static_type = yes;
+ else
+ info->is_dst_type_derived_from_static_type = no;
+ }
+ }
+ }
+ else
+ {
+ // This is not a static_type and not a dst_type.
+ const Iter e = __base_info + __base_count;
+ Iter p = __base_info;
+ p->search_below_dst(info, current_ptr, path_below);
+ if (++p < e)
+ {
+ if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1)
+ {
+ // If there are multiple paths to a base above from here, or if
+ // a dst_type pointing to (static_ptr, static_type) has been found,
+ // then there is no way to break out of this loop early unless
+ // something below detects the search is done.
+ do
+ {
+ if (info->search_done)
+ break;
+ p->search_below_dst(info, current_ptr, path_below);
+ } while (++p < e);
+ }
+ else if (__flags & __non_diamond_repeat_mask)
+ {
+ // There are not multiple paths to any base class from here and a
+ // dst_type pointing to (static_ptr, static_type) has not yet been
+ // found.
+ do
+ {
+ if (info->search_done)
+ break;
+ // If we just found a dst_type with a public path to (static_ptr, static_type),
+ // then the only reason to continue the search is to make sure
+ // no other dst_type points to (static_ptr, static_type).
+ // If !diamond, then we don't need to search here.
+ if (info->number_to_static_ptr == 1 &&
+ info->path_dst_ptr_to_static_ptr == public_path)
+ break;
+ p->search_below_dst(info, current_ptr, path_below);
+ } while (++p < e);
+ }
+ else
+ {
+ // There are no repeated types above this node.
+ // There are no nodes with multiple parents above this node.
+ // no dst_type has been found to (static_ptr, static_type)
+ do
+ {
+ if (info->search_done)
+ break;
+ // If we just found a dst_type with a public path to (static_ptr, static_type),
+ // then the only reason to continue the search is to make sure sure
+ // no other dst_type points to (static_ptr, static_type).
+ // If !diamond, then we don't need to search here.
+ // if we just found a dst_type with a private path to (static_ptr, static_type),
+ // then we're only looking for a public path to (static_ptr, static_type)
+ // and to check for other dst_types.
+ // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type)
+ // and not a dst_type under here.
+ if (info->number_to_static_ptr == 1)
+ break;
+ p->search_below_dst(info, current_ptr, path_below);
+ } while (++p < e);
+ }
+ }
+ }
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_below_dst but
+// simplified to the case that there is only a single base class.
+void
+__si_class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below) const
+{
+ if (this == info->static_type)
+ process_static_type_below_dst(info, current_ptr, path_below);
+ else if (this == info->dst_type)
+ {
+ // We've been here before if we've recorded current_ptr in one of these
+ // two places:
+ if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
+ current_ptr == info->dst_ptr_not_leading_to_static_ptr)
+ {
+ // We've seen this node before, and therefore have already searched
+ // its base classes above.
+ // Update path to here that is "most public".
+ if (path_below == public_path)
+ info->path_dynamic_ptr_to_dst_ptr = public_path;
+ }
+ else // We have haven't been here before
+ {
+ // 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;
+ // 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;
+ __base_type->search_above_dst(info, current_ptr, current_ptr, public_path);
+ if (info->found_any_static_type)
+ {
+ is_dst_type_derived_from_static_type = true;
+ 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
+ // it if it doesn't derive from static_type.
+ if (is_dst_type_derived_from_static_type)
+ info->is_dst_type_derived_from_static_type = yes;
+ else
+ info->is_dst_type_derived_from_static_type = no;
+ }
+ }
+ }
+ else
+ {
+ // This is not a static_type and not a dst_type
+ __base_type->search_below_dst(info, current_ptr, path_below);
+ }
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_below_dst but
+// simplified to the case that there is no base class.
+void
+__class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below) const
+{
+ typedef const __base_class_type_info* Iter;
+ if (this == info->static_type)
+ process_static_type_below_dst(info, current_ptr, path_below);
+ else if (this == info->dst_type)
+ {
+ // We've been here before if we've recorded current_ptr in one of these
+ // two places:
+ if (current_ptr == info->dst_ptr_leading_to_static_ptr ||
+ current_ptr == info->dst_ptr_not_leading_to_static_ptr)
+ {
+ // We've seen this node before, and therefore have already searched
+ // its base classes above.
+ // Update path to here that is "most public".
+ if (path_below == public_path)
+ info->path_dynamic_ptr_to_dst_ptr = public_path;
+ }
+ else // We have haven't been here before
+ {
+ // 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;
+ // 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;
+ // We found that dst_type does not derive from static_type
+ info->is_dst_type_derived_from_static_type = no;
+ }
+ }
+}
+
+// Call this function when searching above a dst_type node. This function searches
+// for a public path to (static_ptr, static_type).
+// This function is guaranteed not to find a node of type dst_type.
+// Theoretically this is a very simple function which just stops if it finds a
+// static_type node: All the hoopla surrounding the search code is doing
+// nothing but looking for excuses to stop the search prematurely (break out of
+// the for-loop). That is, the algorithm below is simply an optimization of this:
+// void
+// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
+// const void* dst_ptr,
+// const void* current_ptr,
+// int path_below) const
+// {
+// if (this == info->static_type)
+// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+// else
+// {
+// typedef const __base_class_type_info* Iter;
+// // This is not a static_type and not a dst_type
+// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p)
+// {
+// p->search_above_dst(info, dst_ptr, current_ptr, public_path);
+// // break out early here if you can detect it doesn't matter if you do
+// }
+// }
+// }
+void
+__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below) const
+{
+ if (this == info->static_type)
+ process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+ else
+ {
+ typedef const __base_class_type_info* Iter;
+ // This is not a static_type and not a dst_type
+ // Save flags so they can be restored when returning to nodes below.
+ bool found_our_static_ptr = info->found_our_static_ptr;
+ bool found_any_static_type = info->found_any_static_type;
+ // We've found a dst_type below with a path to here. If the path
+ // to here is not public, there may be another path to here that
+ // is public. So we have to assume that the path to here is public.
+ // We can stop looking above if:
+ // 1. We've found a public path to (static_ptr, static_type).
+ // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type.
+ // This is detected at the (static_ptr, static_type).
+ // 3. We can prove that there is no public path to (static_ptr, static_type)
+ // above here.
+ const Iter e = __base_info + __base_count;
+ Iter p = __base_info;
+ // Zero out found flags
+ info->found_our_static_ptr = false;
+ info->found_any_static_type = false;
+ p->search_above_dst(info, dst_ptr, current_ptr, path_below);
+ if (++p < e)
+ {
+ do
+ {
+ if (info->search_done)
+ break;
+ if (info->found_our_static_ptr)
+ {
+ // If we found what we're looking for, stop looking above.
+ if (info->path_dst_ptr_to_static_ptr == public_path)
+ break;
+ // We found a private path to (static_ptr, static_type)
+ // If there is no diamond then there is only one path
+ // to (static_ptr, static_type) from here and we just found it.
+ if (!(__flags & __diamond_shaped_mask))
+ break;
+ }
+ else if (info->found_any_static_type)
+ {
+ // If we found a static_type that isn't the one we're looking
+ // for, and if there are no repeated types above here,
+ // then stop looking.
+ if (!(__flags & __non_diamond_repeat_mask))
+ break;
+ }
+ // Zero out found flags
+ info->found_our_static_ptr = false;
+ info->found_any_static_type = false;
+ p->search_above_dst(info, dst_ptr, current_ptr, path_below);
+ } while (++p < e);
+ }
+ // Restore flags
+ info->found_our_static_ptr = found_our_static_ptr;
+ info->found_any_static_type = found_any_static_type;
+ }
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_above_dst but
+// simplified to the case that there is only a single base class.
+void
+__si_class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below) const
+{
+ if (this == info->static_type)
+ process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+ else
+ __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below);
+}
+
+// This is the same algorithm as __vmi_class_type_info::search_above_dst but
+// simplified to the case that there is no base class.
+void
+__class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below) const
+{
+ if (this == info->static_type)
+ process_static_type_above_dst(info, dst_ptr, current_ptr, path_below);
+}
+
+// The search functions for __base_class_type_info are simply convenience
+// functions for adjusting the current_ptr and path_below as the search is
+// passed up to the base class node.
+
+void
+__base_class_type_info::search_above_dst(__dynamic_cast_info* info,
+ const void* dst_ptr,
+ const void* current_ptr,
+ int path_below) const
+{
+ ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+ if (__offset_flags & __virtual_mask)
+ {
+ const char* vtable = *static_cast<const char*const*>(current_ptr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
+ }
+ __base_type->search_above_dst(info, dst_ptr,
+ static_cast<const char*>(current_ptr) + offset_to_base,
+ (__offset_flags & __public_mask) ?
+ path_below :
+ not_public_path);
+}
+
+void
+__base_class_type_info::search_below_dst(__dynamic_cast_info* info,
+ const void* current_ptr,
+ int path_below) const
+{
+ ptrdiff_t offset_to_base = __offset_flags >> __offset_shift;
+ if (__offset_flags & __virtual_mask)
+ {
+ const char* vtable = *static_cast<const char*const*>(current_ptr);
+ offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base);
+ }
+ __base_type->search_below_dst(info,
+ static_cast<const char*>(current_ptr) + offset_to_base,
+ (__offset_flags & __public_mask) ?
+ path_below :
+ not_public_path);
+}
+
+#pragma GCC visibility pop
+
+} // __cxxabiv1
diff --git a/system/lib/libcxxabi/src/private_typeinfo.h b/system/lib/libcxxabi/src/private_typeinfo.h
new file mode 100644
index 00000000..fec081ab
--- /dev/null
+++ b/system/lib/libcxxabi/src/private_typeinfo.h
@@ -0,0 +1,246 @@
+//===------------------------ private_typeinfo.h --------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __PRIVATE_TYPEINFO_H_
+#define __PRIVATE_TYPEINFO_H_
+
+#include <typeinfo>
+#include <cstddef>
+
+namespace __cxxabiv1
+{
+
+#pragma GCC visibility push(hidden)
+
+class __attribute__ ((__visibility__("hidden"))) __shim_type_info
+ : public std::type_info
+{
+public:
+ virtual ~__shim_type_info();
+
+ virtual bool can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const = 0;
+};
+
+class __attribute__ ((__visibility__("default"))) __fundamental_type_info
+ : public __shim_type_info
+{
+public:
+ __attribute__ ((__visibility__("hidden"))) virtual ~__fundamental_type_info();
+ __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const;
+};
+
+class __attribute__ ((__visibility__("default"))) __array_type_info
+ : public __shim_type_info
+{
+public:
+ __attribute__ ((__visibility__("hidden"))) virtual ~__array_type_info();
+ __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const;
+};
+
+class __attribute__ ((__visibility__("default"))) __function_type_info
+ : public __shim_type_info
+{
+public:
+ __attribute__ ((__visibility__("hidden"))) virtual ~__function_type_info();
+ __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const;
+};
+
+class __attribute__ ((__visibility__("default"))) __enum_type_info
+ : public __shim_type_info
+{
+public:
+ __attribute__ ((__visibility__("hidden"))) virtual ~__enum_type_info();
+ __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const;
+};
+
+enum
+{
+ unknown = 0,
+ public_path,
+ not_public_path,
+ yes,
+ no
+};
+
+class __class_type_info;
+
+struct __dynamic_cast_info
+{
+// const data supplied to the search:
+
+ const __class_type_info* const dst_type;
+ const void* const static_ptr;
+ const __class_type_info* const static_type;
+ const std::ptrdiff_t src2dst_offset;
+
+// Data that represents the answer:
+
+ // pointer to a dst_type which has (static_ptr, static_type) above it
+ const void* dst_ptr_leading_to_static_ptr;
+ // pointer to a dst_type which does not have (static_ptr, static_type) above it
+ const void* dst_ptr_not_leading_to_static_ptr;
+
+ // The following three paths are either unknown, public_path or not_public_path.
+ // access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type)
+ int path_dst_ptr_to_static_ptr;
+ // access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type)
+ // when there is no dst_type along the path
+ int path_dynamic_ptr_to_static_ptr;
+ // access of path from (dynamic_ptr, dynamic_type) to dst_type
+ // (not used if there is a (static_ptr, static_type) above a dst_type).
+ int path_dynamic_ptr_to_dst_ptr;
+
+ // Number of dst_types below (static_ptr, static_type)
+ int number_to_static_ptr;
+ // Number of dst_types not below (static_ptr, static_type)
+ int number_to_dst_ptr;
+
+// Data that helps stop the search before the entire tree is searched:
+
+ // is_dst_type_derived_from_static_type is either unknown, yes or no.
+ int is_dst_type_derived_from_static_type;
+ // Number of dst_type in tree. If 0, then that means unknown.
+ int number_of_dst_type;
+ // communicates to a dst_type node that (static_ptr, static_type) was found
+ // above it.
+ bool found_our_static_ptr;
+ // communicates to a dst_type node that a static_type was found
+ // above it, but it wasn't (static_ptr, static_type)
+ bool found_any_static_type;
+ // Set whenever a search can be stopped
+ bool search_done;
+};
+
+// Has no base class
+class __attribute__ ((__visibility__("default"))) __class_type_info
+ : public __shim_type_info
+{
+public:
+ __attribute__ ((__visibility__("hidden"))) virtual ~__class_type_info();
+
+ __attribute__ ((__visibility__("hidden")))
+ void process_static_type_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ void process_static_type_below_dst(__dynamic_cast_info*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ void process_found_base_class(__dynamic_cast_info*, void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual bool can_catch(const __shim_type_info*, void*&) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
+};
+
+// Has one non-virtual public base class at offset zero
+class __attribute__ ((__visibility__("default"))) __si_class_type_info
+ : public __class_type_info
+{
+public:
+ const __class_type_info* __base_type;
+
+ __attribute__ ((__visibility__("hidden"))) virtual ~__si_class_type_info();
+
+ __attribute__ ((__visibility__("hidden")))
+ virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
+};
+
+struct __base_class_type_info
+{
+public:
+ const __class_type_info* __base_type;
+ long __offset_flags;
+
+ enum __offset_flags_masks
+ {
+ __virtual_mask = 0x1,
+ __public_mask = 0x2, // base is public
+ __offset_shift = 8
+ };
+
+ void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+ void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+ void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
+};
+
+// Has one or more base classes
+class __attribute__ ((__visibility__("default"))) __vmi_class_type_info
+ : public __class_type_info
+{
+public:
+ unsigned int __flags;
+ unsigned int __base_count;
+ __base_class_type_info __base_info[1];
+
+ enum __flags_masks
+ {
+ __non_diamond_repeat_mask = 0x1, // has two or more distinct base class
+ // objects of the same type
+ __diamond_shaped_mask = 0x2 // has base class object with two or
+ // more derived objects
+ };
+
+ __attribute__ ((__visibility__("hidden"))) virtual ~__vmi_class_type_info();
+
+ __attribute__ ((__visibility__("hidden")))
+ virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const;
+ __attribute__ ((__visibility__("hidden")))
+ virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const;
+};
+
+class __attribute__ ((__visibility__("default"))) __pbase_type_info
+ : public __shim_type_info
+{
+public:
+ unsigned int __flags;
+ const __shim_type_info* __pointee;
+
+ enum __masks
+ {
+ __const_mask = 0x1,
+ __volatile_mask = 0x2,
+ __restrict_mask = 0x4,
+ __incomplete_mask = 0x8,
+ __incomplete_class_mask = 0x10
+ };
+
+ __attribute__ ((__visibility__("hidden"))) virtual ~__pbase_type_info();
+ __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const;
+};
+
+class __attribute__ ((__visibility__("default"))) __pointer_type_info
+ : public __pbase_type_info
+{
+public:
+ __attribute__ ((__visibility__("hidden"))) virtual ~__pointer_type_info();
+ __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const;
+};
+
+class __attribute__ ((__visibility__("default"))) __pointer_to_member_type_info
+ : public __pbase_type_info
+{
+public:
+ const __class_type_info* __context;
+
+ __attribute__ ((__visibility__("hidden"))) virtual ~__pointer_to_member_type_info();
+};
+
+#pragma GCC visibility pop
+
+} // __cxxabiv1
+
+#endif // __PRIVATE_TYPEINFO_H_
diff --git a/system/lib/libcxxabi/src/stdexcept.cpp b/system/lib/libcxxabi/src/stdexcept.cpp
new file mode 100644
index 00000000..4aa962d0
--- /dev/null
+++ b/system/lib/libcxxabi/src/stdexcept.cpp
@@ -0,0 +1,122 @@
+//===------------------------ stdexcept.cpp -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "stdexcept"
+#include "new"
+#include <cstdlib>
+#include <cstring>
+#include <cstdint>
+#include <cstddef>
+
+// Note: optimize for size
+
+#pragma GCC visibility push(hidden)
+
+namespace
+{
+
+class __libcpp_nmstr
+{
+private:
+ const char* str_;
+
+ typedef std::size_t unused_t;
+ typedef std::int32_t count_t;
+
+ static const std::ptrdiff_t offset = static_cast<std::ptrdiff_t>(2*sizeof(unused_t) +
+ sizeof(count_t));
+
+ count_t& count() const _NOEXCEPT {return (count_t&)(*(str_ - sizeof(count_t)));}
+public:
+ explicit __libcpp_nmstr(const char* msg);
+ __libcpp_nmstr(const __libcpp_nmstr& s) _LIBCPP_CANTTHROW;
+ __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _LIBCPP_CANTTHROW;
+ ~__libcpp_nmstr() _LIBCPP_CANTTHROW;
+ const char* c_str() const _NOEXCEPT {return str_;}
+};
+
+__libcpp_nmstr::__libcpp_nmstr(const char* msg)
+{
+ std::size_t len = strlen(msg);
+ str_ = new char[len + 1 + offset];
+ unused_t* c = (unused_t*)str_;
+ c[0] = c[1] = len;
+ str_ += offset;
+ count() = 0;
+ std::strcpy(const_cast<char*>(c_str()), msg);
+}
+
+inline
+__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s)
+ : str_(s.str_)
+{
+ __sync_add_and_fetch(&count(), 1);
+}
+
+__libcpp_nmstr&
+__libcpp_nmstr::operator=(const __libcpp_nmstr& s)
+{
+ const char* p = str_;
+ str_ = s.str_;
+ __sync_add_and_fetch(&count(), 1);
+ if (__sync_add_and_fetch((count_t*)(p-sizeof(count_t)), -1) < 0)
+ delete [] (p-offset);
+ return *this;
+}
+
+inline
+__libcpp_nmstr::~__libcpp_nmstr()
+{
+ if (__sync_add_and_fetch(&count(), -1) < 0)
+ delete [] (str_ - offset);
+}
+
+}
+
+#pragma GCC visibility pop
+
+namespace std // purposefully not using versioning namespace
+{
+
+logic_error::~logic_error() _NOEXCEPT
+{
+ __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
+ s.~__libcpp_nmstr();
+}
+
+const char*
+logic_error::what() const _NOEXCEPT
+{
+ __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
+ return s.c_str();
+}
+
+runtime_error::~runtime_error() _NOEXCEPT
+{
+ __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
+ s.~__libcpp_nmstr();
+}
+
+const char*
+runtime_error::what() const _NOEXCEPT
+{
+ __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_;
+ return s.c_str();
+}
+
+domain_error::~domain_error() _NOEXCEPT {}
+invalid_argument::~invalid_argument() _NOEXCEPT {}
+length_error::~length_error() _NOEXCEPT {}
+out_of_range::~out_of_range() _NOEXCEPT {}
+
+range_error::~range_error() _NOEXCEPT {}
+overflow_error::~overflow_error() _NOEXCEPT {}
+underflow_error::~underflow_error() _NOEXCEPT {}
+
+} // std
diff --git a/system/lib/libcxxabi/src/temporary.cpp b/system/lib/libcxxabi/src/temporary.cpp
new file mode 100644
index 00000000..5facf39d
--- /dev/null
+++ b/system/lib/libcxxabi/src/temporary.cpp
@@ -0,0 +1,41 @@
+//===---------------------------- temporary.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "abort_message.h"
+
+#pragma GCC visibility push(default)
+
+extern "C"
+{
+
+static
+void f1()
+{
+ abort_message("__cxa_new_handler shouldn't be called");
+}
+
+static
+void f2()
+{
+ abort_message("__cxa_terminate_handler shouldn't be called");
+}
+
+static
+void f3()
+{
+ abort_message("__cxa_unexpected_handler shouldn't be called");
+}
+
+void (*__cxa_new_handler)() = f1;
+void (*__cxa_terminate_handler)() = f2;
+void (*__cxa_unexpected_handler)() = f3;
+
+}
+
+#pragma GCC visibility pop
diff --git a/system/lib/libcxxabi/src/typeinfo.cpp b/system/lib/libcxxabi/src/typeinfo.cpp
new file mode 100644
index 00000000..9313be04
--- /dev/null
+++ b/system/lib/libcxxabi/src/typeinfo.cpp
@@ -0,0 +1,53 @@
+//===----------------------------- typeinfo.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <typeinfo>
+
+namespace std
+{
+
+// type_info
+
+type_info::~type_info()
+{
+}
+
+// bad_cast
+
+bad_cast::bad_cast() _NOEXCEPT
+{
+}
+
+bad_cast::~bad_cast() _NOEXCEPT
+{
+}
+
+const char*
+bad_cast::what() const _NOEXCEPT
+{
+ return "std::bad_cast";
+}
+
+// bad_typeid
+
+bad_typeid::bad_typeid() _NOEXCEPT
+{
+}
+
+bad_typeid::~bad_typeid() _NOEXCEPT
+{
+}
+
+const char*
+bad_typeid::what() const _NOEXCEPT
+{
+ return "std::bad_typeid";
+}
+
+} // std