+ case 'R':
+ return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, d_name (di),
+ NULL);
+
+ case 'A':
+ return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
+ d_encoding (di, 0), NULL);
+
+ case 'r':
+ return d_java_resource (di);
+
+ default:
+ return NULL;
+ }
+ }
+ else
+ return NULL;
+}
+
+/* <call-offset> ::= h <nv-offset> _
+ ::= v <v-offset> _
+
+ <nv-offset> ::= <(offset) number>
+
+ <v-offset> ::= <(offset) number> _ <(virtual offset) number>
+
+ The C parameter, if not '\0', is a character we just read which is
+ the start of the <call-offset>.
+
+ We don't display the offset information anywhere. FIXME: We should
+ display it in verbose mode. */
+
+static int
+d_call_offset (struct d_info *di, int c)
+{
+ if (c == '\0')
+ c = d_next_char (di);
+
+ if (c == 'h')
+ d_number (di);
+ else if (c == 'v')
+ {
+ d_number (di);
+ if (! d_check_char (di, '_'))
+ return 0;
+ d_number (di);
+ }
+ else
+ return 0;
+
+ if (! d_check_char (di, '_'))
+ return 0;
+
+ return 1;
+}
+
+/* <ctor-dtor-name> ::= C1
+ ::= C2
+ ::= C3
+ ::= D0
+ ::= D1
+ ::= D2
+*/
+
+static struct demangle_component *
+d_ctor_dtor_name (struct d_info *di)
+{
+ if (di->last_name != NULL)
+ {
+ if (di->last_name->type == DEMANGLE_COMPONENT_NAME)
+ di->expansion += di->last_name->u.s_name.len;
+ else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD)
+ di->expansion += di->last_name->u.s_string.len;
+ }
+ switch (d_peek_char (di))
+ {
+ case 'C':
+ {
+ enum gnu_v3_ctor_kinds kind;
+
+ switch (d_peek_next_char (di))
+ {
+ case '1':
+ kind = gnu_v3_complete_object_ctor;
+ break;
+ case '2':
+ kind = gnu_v3_base_object_ctor;
+ break;
+ case '3':
+ kind = gnu_v3_complete_object_allocating_ctor;
+ break;
+ default:
+ return NULL;
+ }
+ d_advance (di, 2);
+ return d_make_ctor (di, kind, di->last_name);
+ }
+
+ case 'D':
+ {
+ enum gnu_v3_dtor_kinds kind;
+
+ switch (d_peek_next_char (di))
+ {
+ case '0':
+ kind = gnu_v3_deleting_dtor;
+ break;
+ case '1':
+ kind = gnu_v3_complete_object_dtor;
+ break;
+ case '2':
+ kind = gnu_v3_base_object_dtor;
+ break;
+ default:
+ return NULL;
+ }
+ d_advance (di, 2);
+ return d_make_dtor (di, kind, di->last_name);
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+/* <type> ::= <builtin-type>
+ ::= <function-type>
+ ::= <class-enum-type>
+ ::= <array-type>
+ ::= <pointer-to-member-type>
+ ::= <template-param>
+ ::= <template-template-param> <template-args>
+ ::= <substitution>
+ ::= <CV-qualifiers> <type>
+ ::= P <type>
+ ::= R <type>
+ ::= O <type> (C++0x)
+ ::= C <type>
+ ::= G <type>
+ ::= U <source-name> <type>
+
+ <builtin-type> ::= various one letter codes
+ ::= u <source-name>
+*/
+
+CP_STATIC_IF_GLIBCPP_V3
+const struct demangle_builtin_type_info
+cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] =
+{
+ /* a */ { NL ("signed char"), NL ("signed char"), D_PRINT_DEFAULT },
+ /* b */ { NL ("bool"), NL ("boolean"), D_PRINT_BOOL },
+ /* c */ { NL ("char"), NL ("byte"), D_PRINT_DEFAULT },
+ /* d */ { NL ("double"), NL ("double"), D_PRINT_FLOAT },
+ /* e */ { NL ("long double"), NL ("long double"), D_PRINT_FLOAT },
+ /* f */ { NL ("float"), NL ("float"), D_PRINT_FLOAT },
+ /* g */ { NL ("__float128"), NL ("__float128"), D_PRINT_FLOAT },
+ /* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT },
+ /* i */ { NL ("int"), NL ("int"), D_PRINT_INT },
+ /* j */ { NL ("unsigned int"), NL ("unsigned"), D_PRINT_UNSIGNED },
+ /* k */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* l */ { NL ("long"), NL ("long"), D_PRINT_LONG },
+ /* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG },
+ /* n */ { NL ("__int128"), NL ("__int128"), D_PRINT_DEFAULT },
+ /* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"),
+ D_PRINT_DEFAULT },
+ /* p */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* q */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* r */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* s */ { NL ("short"), NL ("short"), D_PRINT_DEFAULT },
+ /* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT },
+ /* u */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT },
+ /* v */ { NL ("void"), NL ("void"), D_PRINT_VOID },
+ /* w */ { NL ("wchar_t"), NL ("char"), D_PRINT_DEFAULT },
+ /* x */ { NL ("long long"), NL ("long"), D_PRINT_LONG_LONG },
+ /* y */ { NL ("unsigned long long"), NL ("unsigned long long"),
+ D_PRINT_UNSIGNED_LONG_LONG },
+ /* z */ { NL ("..."), NL ("..."), D_PRINT_DEFAULT },
+ /* 26 */ { NL ("decimal32"), NL ("decimal32"), D_PRINT_DEFAULT },
+ /* 27 */ { NL ("decimal64"), NL ("decimal64"), D_PRINT_DEFAULT },
+ /* 28 */ { NL ("decimal128"), NL ("decimal128"), D_PRINT_DEFAULT },
+ /* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT },
+ /* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT },
+ /* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT },
+ /* 32 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"),
+ D_PRINT_DEFAULT },
+};
+
+CP_STATIC_IF_GLIBCPP_V3
+struct demangle_component *
+cplus_demangle_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *ret;
+ int can_subst;
+
+ /* The ABI specifies that when CV-qualifiers are used, the base type
+ is substitutable, and the fully qualified type is substitutable,
+ but the base type with a strict subset of the CV-qualifiers is
+ not substitutable. The natural recursive implementation of the
+ CV-qualifiers would cause subsets to be substitutable, so instead
+ we pull them all off now.
+
+ FIXME: The ABI says that order-insensitive vendor qualifiers
+ should be handled in the same way, but we have no way to tell
+ which vendor qualifiers are order-insensitive and which are
+ order-sensitive. So we just assume that they are all
+ order-sensitive. g++ 3.4 supports only one vendor qualifier,
+ __vector, and it treats it as order-sensitive when mangling
+ names. */
+
+ peek = d_peek_char (di);
+ if (peek == 'r' || peek == 'V' || peek == 'K')
+ {
+ struct demangle_component **pret;
+
+ pret = d_cv_qualifiers (di, &ret, 0);
+ if (pret == NULL)
+ return NULL;
+ *pret = cplus_demangle_type (di);
+ if (! *pret || ! d_add_substitution (di, ret))
+ return NULL;
+ return ret;
+ }
+
+ can_subst = 1;
+
+ switch (peek)
+ {
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+ case 'h': case 'i': case 'j': case 'l': case 'm': case 'n':
+ case 'o': case 's': case 't':
+ case 'v': case 'w': case 'x': case 'y': case 'z':
+ ret = d_make_builtin_type (di,
+ &cplus_demangle_builtin_types[peek - 'a']);
+ di->expansion += ret->u.s_builtin.type->len;
+ can_subst = 0;
+ d_advance (di, 1);
+ break;
+
+ case 'u':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE,
+ d_source_name (di), NULL);
+ break;
+
+ case 'F':
+ ret = d_function_type (di);
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'N':
+ case 'Z':
+ ret = d_class_enum_type (di);
+ break;
+
+ case 'A':
+ ret = d_array_type (di);
+ break;
+
+ case 'M':
+ ret = d_pointer_to_member_type (di);
+ break;
+
+ case 'T':
+ ret = d_template_param (di);
+ if (d_peek_char (di) == 'I')
+ {
+ /* This is <template-template-param> <template-args>. The
+ <template-template-param> part is a substitution
+ candidate. */
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ }
+ break;
+
+ case 'S':
+ /* If this is a special substitution, then it is the start of
+ <class-enum-type>. */
+ {
+ char peek_next;
+
+ peek_next = d_peek_next_char (di);
+ if (IS_DIGIT (peek_next)
+ || peek_next == '_'
+ || IS_UPPER (peek_next))
+ {
+ ret = d_substitution (di, 0);
+ /* The substituted name may have been a template name and
+ may be followed by tepmlate args. */
+ if (d_peek_char (di) == 'I')
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret,
+ d_template_args (di));
+ else
+ can_subst = 0;
+ }
+ else
+ {
+ ret = d_class_enum_type (di);
+ /* If the substitution was a complete type, then it is not
+ a new substitution candidate. However, if the
+ substitution was followed by template arguments, then
+ the whole thing is a substitution candidate. */
+ if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD)
+ can_subst = 0;
+ }
+ }
+ break;
+
+ case 'O':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'P':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'R':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'C':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'G':
+ d_advance (di, 1);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'U':
+ d_advance (di, 1);
+ ret = d_source_name (di);
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
+ cplus_demangle_type (di), ret);
+ break;
+
+ case 'D':
+ can_subst = 0;
+ d_advance (di, 1);
+ peek = d_next_char (di);
+ switch (peek)
+ {
+ case 'T':
+ case 't':
+ /* decltype (expression) */
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE,
+ d_expression (di), NULL);
+ if (ret && d_next_char (di) != 'E')
+ ret = NULL;
+ break;
+
+ case 'p':
+ /* Pack expansion. */
+ ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
+ cplus_demangle_type (di), NULL);
+ break;
+
+ case 'f':
+ /* 32-bit decimal floating point */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'd':
+ /* 64-bit DFP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'e':
+ /* 128-bit DFP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'h':
+ /* 16-bit half-precision FP */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 's':
+ /* char16_t */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+ case 'i':
+ /* char32_t */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+
+ case 'F':
+ /* Fixed point types. DF<int bits><length><fract bits><sat> */
+ ret = d_make_empty (di);
+ ret->type = DEMANGLE_COMPONENT_FIXED_TYPE;
+ if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di))))
+ /* For demangling we don't care about the bits. */
+ d_number (di);
+ ret->u.s_fixed.length = cplus_demangle_type (di);
+ if (ret->u.s_fixed.length == NULL)
+ return NULL;
+ d_number (di);
+ peek = d_next_char (di);
+ ret->u.s_fixed.sat = (peek == 's');
+ break;
+
+ case 'v':
+ ret = d_vector_type (di);
+ break;
+
+ case 'n':
+ /* decltype(nullptr) */
+ ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]);
+ di->expansion += ret->u.s_builtin.type->len;
+ break;
+
+ default:
+ return NULL;
+ }
+ break;
+
+ default:
+ return NULL;
+ }
+
+ if (can_subst)
+ {
+ if (! d_add_substitution (di, ret))
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* <CV-qualifiers> ::= [r] [V] [K] */
+
+static struct demangle_component **
+d_cv_qualifiers (struct d_info *di,
+ struct demangle_component **pret, int member_fn)
+{
+ char peek;
+
+ peek = d_peek_char (di);
+ while (peek == 'r' || peek == 'V' || peek == 'K')
+ {
+ enum demangle_component_type t;
+
+ d_advance (di, 1);
+ if (peek == 'r')
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_RESTRICT_THIS
+ : DEMANGLE_COMPONENT_RESTRICT);
+ di->expansion += sizeof "restrict";
+ }
+ else if (peek == 'V')
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_VOLATILE_THIS
+ : DEMANGLE_COMPONENT_VOLATILE);
+ di->expansion += sizeof "volatile";
+ }
+ else
+ {
+ t = (member_fn
+ ? DEMANGLE_COMPONENT_CONST_THIS
+ : DEMANGLE_COMPONENT_CONST);
+ di->expansion += sizeof "const";
+ }
+
+ *pret = d_make_comp (di, t, NULL, NULL);
+ if (*pret == NULL)
+ return NULL;
+ pret = &d_left (*pret);
+
+ peek = d_peek_char (di);
+ }
+
+ return pret;
+}
+
+/* <function-type> ::= F [Y] <bare-function-type> E */
+
+static struct demangle_component *
+d_function_type (struct d_info *di)
+{
+ struct demangle_component *ret;
+
+ if (! d_check_char (di, 'F'))
+ return NULL;
+ if (d_peek_char (di) == 'Y')
+ {
+ /* Function has C linkage. We don't print this information.
+ FIXME: We should print it in verbose mode. */
+ d_advance (di, 1);
+ }
+ ret = d_bare_function_type (di, 1);
+ if (! d_check_char (di, 'E'))
+ return NULL;
+ return ret;
+}
+
+/* <type>+ */
+
+static struct demangle_component *
+d_parmlist (struct d_info *di)
+{
+ struct demangle_component *tl;
+ struct demangle_component **ptl;
+
+ tl = NULL;
+ ptl = &tl;
+ while (1)
+ {
+ struct demangle_component *type;
+
+ char peek = d_peek_char (di);
+ if (peek == '\0' || peek == 'E')
+ break;
+ type = cplus_demangle_type (di);
+ if (type == NULL)
+ return NULL;
+ *ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL);
+ if (*ptl == NULL)
+ return NULL;
+ ptl = &d_right (*ptl);
+ }
+
+ /* There should be at least one parameter type besides the optional
+ return type. A function which takes no arguments will have a
+ single parameter type void. */
+ if (tl == NULL)
+ return NULL;
+
+ /* If we have a single parameter type void, omit it. */
+ if (d_right (tl) == NULL
+ && d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE
+ && d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID)
+ {
+ di->expansion -= d_left (tl)->u.s_builtin.type->len;
+ d_left (tl) = NULL;
+ }
+
+ return tl;
+}
+
+/* <bare-function-type> ::= [J]<type>+ */
+
+static struct demangle_component *
+d_bare_function_type (struct d_info *di, int has_return_type)
+{
+ struct demangle_component *return_type;
+ struct demangle_component *tl;
+ char peek;
+
+ /* Detect special qualifier indicating that the first argument
+ is the return type. */
+ peek = d_peek_char (di);
+ if (peek == 'J')
+ {
+ d_advance (di, 1);
+ has_return_type = 1;
+ }
+
+ if (has_return_type)
+ {
+ return_type = cplus_demangle_type (di);
+ if (return_type == NULL)
+ return NULL;
+ }
+ else
+ return_type = NULL;
+
+ tl = d_parmlist (di);
+ if (tl == NULL)
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE,
+ return_type, tl);
+}
+
+/* <class-enum-type> ::= <name> */
+
+static struct demangle_component *
+d_class_enum_type (struct d_info *di)
+{
+ return d_name (di);
+}
+
+/* <array-type> ::= A <(positive dimension) number> _ <(element) type>
+ ::= A [<(dimension) expression>] _ <(element) type>
+*/
+
+static struct demangle_component *
+d_array_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *dim;
+
+ if (! d_check_char (di, 'A'))
+ return NULL;
+
+ peek = d_peek_char (di);
+ if (peek == '_')
+ dim = NULL;
+ else if (IS_DIGIT (peek))
+ {
+ const char *s;
+
+ s = d_str (di);
+ do
+ {
+ d_advance (di, 1);
+ peek = d_peek_char (di);
+ }
+ while (IS_DIGIT (peek));
+ dim = d_make_name (di, s, d_str (di) - s);
+ if (dim == NULL)
+ return NULL;
+ }
+ else
+ {
+ dim = d_expression (di);
+ if (dim == NULL)
+ return NULL;
+ }
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim,
+ cplus_demangle_type (di));
+}
+
+/* <vector-type> ::= Dv <number> _ <type>
+ ::= Dv _ <expression> _ <type> */
+
+static struct demangle_component *
+d_vector_type (struct d_info *di)
+{
+ char peek;
+ struct demangle_component *dim;
+
+ peek = d_peek_char (di);
+ if (peek == '_')
+ {
+ d_advance (di, 1);
+ dim = d_expression (di);
+ }
+ else
+ dim = d_number_component (di);
+
+ if (dim == NULL)
+ return NULL;
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_VECTOR_TYPE, dim,
+ cplus_demangle_type (di));
+}
+
+/* <pointer-to-member-type> ::= M <(class) type> <(member) type> */
+
+static struct demangle_component *
+d_pointer_to_member_type (struct d_info *di)
+{
+ struct demangle_component *cl;
+ struct demangle_component *mem;
+ struct demangle_component **pmem;
+
+ if (! d_check_char (di, 'M'))
+ return NULL;
+
+ cl = cplus_demangle_type (di);
+
+ /* The ABI specifies that any type can be a substitution source, and
+ that M is followed by two types, and that when a CV-qualified
+ type is seen both the base type and the CV-qualified types are
+ substitution sources. The ABI also specifies that for a pointer
+ to a CV-qualified member function, the qualifiers are attached to
+ the second type. Given the grammar, a plain reading of the ABI
+ suggests that both the CV-qualified member function and the
+ non-qualified member function are substitution sources. However,
+ g++ does not work that way. g++ treats only the CV-qualified
+ member function as a substitution source. FIXME. So to work
+ with g++, we need to pull off the CV-qualifiers here, in order to
+ avoid calling add_substitution() in cplus_demangle_type(). But
+ for a CV-qualified member which is not a function, g++ does
+ follow the ABI, so we need to handle that case here by calling
+ d_add_substitution ourselves. */
+
+ pmem = d_cv_qualifiers (di, &mem, 1);
+ if (pmem == NULL)
+ return NULL;
+ *pmem = cplus_demangle_type (di);
+ if (*pmem == NULL)
+ return NULL;
+
+ if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ {
+ if (! d_add_substitution (di, mem))
+ return NULL;
+ }
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
+}
+
+/* <non-negative number> _ */
+
+static long
+d_compact_number (struct d_info *di)
+{
+ long num;
+ if (d_peek_char (di) == '_')
+ num = 0;
+ else if (d_peek_char (di) == 'n')
+ return -1;
+ else
+ num = d_number (di) + 1;
+
+ if (! d_check_char (di, '_'))
+ return -1;
+ return num;