/* Demangler for g++ V3 ABI.
- Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@wasabisystems.com>.
This file is part of the libiberty library, which is part of GCC.
struct d_print_mod *modifiers;
/* Set to 1 if we saw a demangling error. */
int demangle_failure;
+ /* The current index into any template argument packs we are using
+ for printing. */
+ int pack_index;
};
#ifdef CP_DEMANGLE_DEBUG
case DEMANGLE_COMPONENT_PTRMEM_TYPE:
printf ("pointer to member type\n");
break;
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ printf ("fixed-point type\n");
+ break;
case DEMANGLE_COMPONENT_ARGLIST:
printf ("argument list\n");
break;
case DEMANGLE_COMPONENT_LITERAL_NEG:
printf ("negative literal\n");
break;
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ printf ("java resource\n");
+ break;
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ printf ("compound name\n");
+ break;
+ case DEMANGLE_COMPONENT_CHARACTER:
+ printf ("character '%c'\n", dc->u.s_character.character);
+ return;
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ printf ("decltype\n");
+ break;
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ printf ("pack expansion\n");
+ break;
}
d_dump (d_left (dc), indent + 2);
case DEMANGLE_COMPONENT_TRINARY_ARG2:
case DEMANGLE_COMPONENT_LITERAL:
case DEMANGLE_COMPONENT_LITERAL_NEG:
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
if (left == NULL || right == NULL)
return NULL;
break;
case DEMANGLE_COMPONENT_COMPLEX:
case DEMANGLE_COMPONENT_IMAGINARY:
case DEMANGLE_COMPONENT_VENDOR_TYPE:
- case DEMANGLE_COMPONENT_ARGLIST:
- case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
case DEMANGLE_COMPONENT_CAST:
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
if (left == NULL)
return NULL;
break;
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_ARGLIST:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
break;
/* Other types should not be seen here. */
return p;
}
+/* Add a new function parameter. */
+
+static struct demangle_component *
+d_make_function_param (struct d_info *di, long i)
+{
+ struct demangle_component *p;
+
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM;
+ p->u.s_number.number = i;
+ }
+ return p;
+}
+
/* Add a new standard substitution component. */
static struct demangle_component *
struct demangle_component *
cplus_demangle_mangled_name (struct d_info *di, int top_level)
{
- if (! d_check_char (di, '_'))
+ if (! d_check_char (di, '_')
+ /* Allow missing _ if not at toplevel to work around a
+ bug in G++ abi-version=2 mangling; see the comment in
+ write_template_arg. */
+ && top_level)
return NULL;
if (! d_check_char (di, 'Z'))
return NULL;
{ "aa", NL ("&&"), 2 },
{ "ad", NL ("&"), 1 },
{ "an", NL ("&"), 2 },
- { "cl", NL ("()"), 0 },
+ { "cl", NL ("()"), 2 },
{ "cm", NL (","), 2 },
{ "co", NL ("~"), 1 },
{ "dV", NL ("/="), 2 },
{ "da", NL ("delete[]"), 1 },
{ "de", NL ("*"), 1 },
{ "dl", NL ("delete"), 1 },
+ { "dt", NL ("."), 2 },
{ "dv", NL ("/"), 2 },
{ "eO", NL ("^="), 2 },
{ "eo", NL ("^"), 2 },
{ "rs", NL (">>"), 2 },
{ "st", NL ("sizeof "), 1 },
{ "sz", NL ("sizeof "), 1 },
+ { "at", NL ("alignof "), 1 },
+ { "az", NL ("alignof "), 1 },
{ NULL, NULL, 0, 0 }
};
}
}
+static struct demangle_component *
+d_make_character (struct d_info *di, int c)
+{
+ struct demangle_component *p;
+ p = d_make_empty (di);
+ if (p != NULL)
+ {
+ p->type = DEMANGLE_COMPONENT_CHARACTER;
+ p->u.s_character.character = c;
+ }
+ return p;
+}
+
+static struct demangle_component *
+d_java_resource (struct d_info *di)
+{
+ struct demangle_component *p = NULL;
+ struct demangle_component *next = NULL;
+ long len, i;
+ char c;
+ const char *str;
+
+ len = d_number (di);
+ if (len <= 1)
+ return NULL;
+
+ /* Eat the leading '_'. */
+ if (d_next_char (di) != '_')
+ return NULL;
+ len--;
+
+ str = d_str (di);
+ i = 0;
+
+ while (len > 0)
+ {
+ c = str[i];
+ if (!c)
+ return NULL;
+
+ /* Each chunk is either a '$' escape... */
+ if (c == '$')
+ {
+ i++;
+ switch (str[i++])
+ {
+ case 'S':
+ c = '/';
+ break;
+ case '_':
+ c = '.';
+ break;
+ case '$':
+ c = '$';
+ break;
+ default:
+ return NULL;
+ }
+ next = d_make_character (di, c);
+ d_advance (di, i);
+ str = d_str (di);
+ len -= i;
+ i = 0;
+ if (next == NULL)
+ return NULL;
+ }
+ /* ... or a sequence of characters. */
+ else
+ {
+ while (i < len && str[i] && str[i] != '$')
+ i++;
+
+ next = d_make_name (di, str, i);
+ d_advance (di, i);
+ str = d_str (di);
+ len -= i;
+ i = 0;
+ if (next == NULL)
+ return NULL;
+ }
+
+ if (p == NULL)
+ p = next;
+ else
+ {
+ p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next);
+ if (p == NULL)
+ return NULL;
+ }
+ }
+
+ p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL);
+
+ return p;
+}
+
/* <special-name> ::= TV <type>
::= TT <type>
::= TI <type>
::= TJ <type>
::= GR <name>
::= GA <encoding>
+ ::= Gr <resource name>
*/
static struct demangle_component *
return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS,
d_encoding (di, 0), NULL);
+ case 'r':
+ return d_java_resource (di);
+
default:
return NULL;
}
/* 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 },
};
CP_STATIC_IF_GLIBCPP_V3
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);
+ d_number (di);
+ peek = d_next_char (di);
+ ret->u.s_fixed.sat = (peek == 's');
+ break;
+
+ default:
+ return NULL;
+ }
+ break;
+
default:
return NULL;
}
if (! d_check_char (di, 'I'))
return NULL;
+ if (d_peek_char (di) == 'E')
+ {
+ /* An argument pack can be empty. */
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL);
+ }
+
al = NULL;
pal = &al;
while (1)
case 'L':
return d_expr_primary (di);
+ case 'I':
+ /* An argument pack. */
+ return d_template_args (di);
+
default:
return cplus_demangle_type (di);
}
}
+/* Subroutine of <expression> ::= cl <expression>+ E */
+
+static struct demangle_component *
+d_exprlist (struct d_info *di)
+{
+ struct demangle_component *list = NULL;
+ struct demangle_component **p = &list;
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL);
+ }
+
+ while (1)
+ {
+ struct demangle_component *arg = d_expression (di);
+ if (arg == NULL)
+ return NULL;
+
+ *p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL);
+ if (*p == NULL)
+ return NULL;
+ p = &d_right (*p);
+
+ if (d_peek_char (di) == 'E')
+ {
+ d_advance (di, 1);
+ break;
+ }
+ }
+
+ return list;
+}
+
/* <expression> ::= <(unary) operator-name> <expression>
::= <(binary) operator-name> <expression> <expression>
::= <(trinary) operator-name> <expression> <expression> <expression>
+ ::= cl <expression>+ E
::= st <type>
::= <template-param>
::= sr <type> <unqualified-name>
d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
d_template_args (di)));
}
+ else if (peek == 's' && d_peek_next_char (di) == 'p')
+ {
+ d_advance (di, 2);
+ return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION,
+ d_expression (di), NULL);
+ }
+ else if (peek == 'f' && d_peek_next_char (di) == 'p')
+ {
+ /* Function parameter used in a late-specified return type. */
+ int index;
+ d_advance (di, 2);
+ if (d_peek_char (di) == '_')
+ index = 1;
+ else
+ {
+ index = d_number (di);
+ if (index < 0)
+ return NULL;
+ index += 2;
+ }
+
+ if (! d_check_char (di, '_'))
+ return NULL;
+
+ return d_make_function_param (di, index);
+ }
+ else if (IS_DIGIT (peek))
+ {
+ /* We can get an unqualified name as an expression in the case of
+ a dependent member access, i.e. decltype(T().i). */
+ struct demangle_component *name = d_unqualified_name (di);
+ if (name == NULL)
+ return NULL;
+ if (d_peek_char (di) == 'I')
+ return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
+ d_template_args (di));
+ else
+ return name;
+ }
else
{
struct demangle_component *op;
switch (args)
{
case 1:
- return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
- d_expression (di));
+ {
+ struct demangle_component *operand;
+ if (op->type == DEMANGLE_COMPONENT_CAST
+ && d_check_char (di, '_'))
+ operand = d_exprlist (di);
+ else
+ operand = d_expression (di);
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
+ operand);
+ }
case 2:
{
struct demangle_component *left;
+ struct demangle_component *right;
left = d_expression (di);
+ if (!strcmp (op->u.s_operator.op->code, "cl"))
+ right = d_exprlist (di);
+ else
+ right = d_expression (di);
+
return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op,
d_make_comp (di,
DEMANGLE_COMPONENT_BINARY_ARGS,
- left,
- d_expression (di)));
+ left, right));
}
case 3:
{
if (! d_check_char (di, 'L'))
return NULL;
- if (d_peek_char (di) == '_')
+ if (d_peek_char (di) == '_'
+ /* Workaround for G++ bug; see comment in write_template_arg. */
+ || d_peek_char (di) == 'Z')
ret = cplus_demangle_mangled_name (di, 0);
else
{
c = d_next_char (di);
if (c == '_' || IS_DIGIT (c) || IS_UPPER (c))
{
- int id;
+ unsigned int id;
id = 0;
if (c != '_')
{
do
{
+ unsigned int new_id;
+
if (IS_DIGIT (c))
- id = id * 36 + c - '0';
+ new_id = id * 36 + c - '0';
else if (IS_UPPER (c))
- id = id * 36 + c - 'A' + 10;
+ new_id = id * 36 + c - 'A' + 10;
else
return NULL;
- if (id < 0)
+ if (new_id < id)
return NULL;
+ id = new_id;
c = d_next_char (di);
}
while (c != '_');
++id;
}
- if (id >= di->next_sub)
+ if (id >= (unsigned int) di->next_sub)
return NULL;
++di->did_subs;
return dgs.buf;
}
+/* Returns the I'th element of the template arglist ARGS, or NULL on
+ failure. */
+
+static struct demangle_component *
+d_index_template_argument (struct demangle_component *args, int i)
+{
+ struct demangle_component *a;
+
+ for (a = args;
+ a != NULL;
+ a = d_right (a))
+ {
+ if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ return NULL;
+ if (i <= 0)
+ break;
+ --i;
+ }
+ if (i != 0 || a == NULL)
+ return NULL;
+
+ return d_left (a);
+}
+
+/* Returns the template argument from the current context indicated by DC,
+ which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL. */
+
+static struct demangle_component *
+d_lookup_template_argument (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ if (dpi->templates == NULL)
+ {
+ d_print_error (dpi);
+ return NULL;
+ }
+
+ return d_index_template_argument
+ (d_right (dpi->templates->template_decl),
+ dc->u.s_number.number);
+}
+
+/* Returns a template argument pack used in DC (any will do), or NULL. */
+
+static struct demangle_component *
+d_find_pack (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ struct demangle_component *a;
+ if (dc == NULL)
+ return NULL;
+
+ switch (dc->type)
+ {
+ case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
+ a = d_lookup_template_argument (dpi, dc);
+ if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ return a;
+ return NULL;
+
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ return NULL;
+
+ case DEMANGLE_COMPONENT_NAME:
+ case DEMANGLE_COMPONENT_OPERATOR:
+ case DEMANGLE_COMPONENT_BUILTIN_TYPE:
+ case DEMANGLE_COMPONENT_SUB_STD:
+ case DEMANGLE_COMPONENT_CHARACTER:
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ return NULL;
+
+ case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
+ return d_find_pack (dpi, dc->u.s_extended_operator.name);
+ case DEMANGLE_COMPONENT_CTOR:
+ return d_find_pack (dpi, dc->u.s_ctor.name);
+ case DEMANGLE_COMPONENT_DTOR:
+ return d_find_pack (dpi, dc->u.s_dtor.name);
+
+ default:
+ a = d_find_pack (dpi, d_left (dc));
+ if (a)
+ return a;
+ return d_find_pack (dpi, d_right (dc));
+ }
+}
+
+/* Returns the length of the template argument pack DC. */
+
+static int
+d_pack_length (const struct demangle_component *dc)
+{
+ int count = 0;
+ while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST
+ && d_left (dc) != NULL)
+ {
+ ++count;
+ dc = d_right (dc);
+ }
+ return count;
+}
+
+/* DC is a component of a mangled expression. Print it, wrapped in parens
+ if needed. */
+
+static void
+d_print_subexpr (struct d_print_info *dpi,
+ const struct demangle_component *dc)
+{
+ int simple = 0;
+ if (dc->type == DEMANGLE_COMPONENT_NAME
+ || dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM)
+ simple = 1;
+ if (!simple)
+ d_append_char (dpi, '(');
+ d_print_comp (dpi, dc);
+ if (!simple)
+ d_append_char (dpi, ')');
+}
+
/* Subroutine to handle components. */
static void
the right place for the type. We also have to pass down
any CV-qualifiers, which apply to the this parameter. */
hold_modifiers = dpi->modifiers;
+ dpi->modifiers = 0;
i = 0;
typed_name = d_left (dc);
while (typed_name != NULL)
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
{
- long i;
- struct demangle_component *a;
struct d_print_template *hold_dpt;
+ struct demangle_component *a = d_lookup_template_argument (dpi, dc);
- if (dpi->templates == NULL)
- {
- d_print_error (dpi);
- return;
- }
- i = dc->u.s_number.number;
- for (a = d_right (dpi->templates->template_decl);
- a != NULL;
- a = d_right (a))
- {
- if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
- {
- d_print_error (dpi);
- return;
- }
- if (i <= 0)
- break;
- --i;
- }
- if (i != 0 || a == NULL)
+ if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST)
+ a = d_index_template_argument (a, dpi->pack_index);
+
+ if (a == NULL)
{
d_print_error (dpi);
return;
hold_dpt = dpi->templates;
dpi->templates = hold_dpt->next;
- d_print_comp (dpi, d_left (a));
+ d_print_comp (dpi, a);
dpi->templates = hold_dpt;
return;
}
+ case DEMANGLE_COMPONENT_FIXED_TYPE:
+ if (dc->u.s_fixed.sat)
+ d_append_string (dpi, "_Sat ");
+ /* Don't print "int _Accum". */
+ if (dc->u.s_fixed.length->u.s_builtin.type
+ != &cplus_demangle_builtin_types['i'-'a'])
+ {
+ d_print_comp (dpi, dc->u.s_fixed.length);
+ d_append_char (dpi, ' ');
+ }
+ if (dc->u.s_fixed.accum)
+ d_append_string (dpi, "_Accum");
+ else
+ d_append_string (dpi, "_Fract");
+ return;
+
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
- d_print_comp (dpi, d_left (dc));
+ if (d_left (dc) != NULL)
+ d_print_comp (dpi, d_left (dc));
if (d_right (dc) != NULL)
{
+ size_t len;
d_append_string (dpi, ", ");
+ len = dpi->len;
d_print_comp (dpi, d_right (dc));
+ /* If that didn't print anything (which can happen with empty
+ template argument packs), remove the comma and space. */
+ if (dpi->len == len)
+ dpi->len -= 2;
}
return;
d_print_cast (dpi, d_left (dc));
d_append_char (dpi, ')');
}
- d_append_char (dpi, '(');
- d_print_comp (dpi, d_right (dc));
- d_append_char (dpi, ')');
+ d_print_subexpr (dpi, d_right (dc));
return;
case DEMANGLE_COMPONENT_BINARY:
&& d_left (dc)->u.s_operator.op->name[0] == '>')
d_append_char (dpi, '(');
- d_append_char (dpi, '(');
- d_print_comp (dpi, d_left (d_right (dc)));
- d_append_string (dpi, ") ");
- d_print_expr_op (dpi, d_left (dc));
- d_append_string (dpi, " (");
- d_print_comp (dpi, d_right (d_right (dc)));
- d_append_char (dpi, ')');
+ d_print_subexpr (dpi, d_left (d_right (dc)));
+ if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0)
+ d_print_expr_op (dpi, d_left (dc));
+ d_print_subexpr (dpi, d_right (d_right (dc)));
if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR
&& d_left (dc)->u.s_operator.op->len == 1
d_print_error (dpi);
return;
}
- d_append_char (dpi, '(');
- d_print_comp (dpi, d_left (d_right (dc)));
- d_append_string (dpi, ") ");
+ d_print_subexpr (dpi, d_left (d_right (dc)));
d_print_expr_op (dpi, d_left (dc));
- d_append_string (dpi, " (");
- d_print_comp (dpi, d_left (d_right (d_right (dc))));
- d_append_string (dpi, ") : (");
- d_print_comp (dpi, d_right (d_right (d_right (dc))));
- d_append_char (dpi, ')');
+ d_print_subexpr (dpi, d_left (d_right (d_right (dc))));
+ d_append_string (dpi, " : ");
+ d_print_subexpr (dpi, d_right (d_right (d_right (dc))));
return;
case DEMANGLE_COMPONENT_TRINARY_ARG1:
}
return;
+ case DEMANGLE_COMPONENT_JAVA_RESOURCE:
+ d_append_string (dpi, "java resource ");
+ d_print_comp (dpi, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_COMPOUND_NAME:
+ d_print_comp (dpi, d_left (dc));
+ d_print_comp (dpi, d_right (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_CHARACTER:
+ d_append_char (dpi, dc->u.s_character.character);
+ return;
+
+ case DEMANGLE_COMPONENT_DECLTYPE:
+ d_append_string (dpi, "decltype (");
+ d_print_comp (dpi, d_left (dc));
+ d_append_char (dpi, ')');
+ return;
+
+ case DEMANGLE_COMPONENT_PACK_EXPANSION:
+ {
+ int len;
+ int i;
+ struct demangle_component *a = d_find_pack (dpi, d_left (dc));
+ if (a == NULL)
+ {
+ /* d_find_pack won't find anything if the only packs involved
+ in this expansion are function parameter packs; in that
+ case, just print the pattern and "...". */
+ d_print_subexpr (dpi, d_left (dc));
+ d_append_string (dpi, "...");
+ return;
+ }
+
+ len = d_pack_length (a);
+ dc = d_left (dc);
+ for (i = 0; i < len; ++i)
+ {
+ dpi->pack_index = i;
+ d_print_comp (dpi, dc);
+ if (i < len-1)
+ d_append_string (dpi, ", ");
+ }
+ }
+ return;
+
+ case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ {
+ char buf[25];
+ d_append_string (dpi, "parm#");
+ sprintf(buf,"%ld", dc->u.s_number.number);
+ d_append_string (dpi, buf);
+ return;
+ }
+
default:
d_print_error (dpi);
return;