static struct demangle_component **
d_cv_qualifiers (struct d_info *, struct demangle_component **, int);
+static struct demangle_component *
+d_ref_qualifier (struct d_info *, struct demangle_component *);
+
static struct demangle_component *
d_function_type (struct d_info *);
case DEMANGLE_COMPONENT_NAME:
printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s);
return;
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ printf ("tagged name\n");
+ d_dump (dc->u.s_binary.left, indent + 2);
+ d_dump (dc->u.s_binary.right, indent + 2);
+ return;
case DEMANGLE_COMPONENT_TEMPLATE_PARAM:
printf ("template parameter %ld\n", dc->u.s_number.number);
return;
case DEMANGLE_COMPONENT_CONST_THIS:
printf ("const this\n");
break;
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ printf ("reference this\n");
+ break;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ printf ("rvalue reference this\n");
+ break;
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
printf ("vendor type qualifier\n");
break;
case DEMANGLE_COMPONENT_PACK_EXPANSION:
printf ("pack expansion\n");
break;
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ printf ("tls init function\n");
+ break;
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ printf ("tls wrapper function\n");
+ break;
+ case DEMANGLE_COMPONENT_DEFAULT_ARG:
+ printf ("default argument %d\n", dc->u.s_unary_num.num);
+ d_dump (dc->u.s_unary_num.sub, indent+2);
+ return;
+ case DEMANGLE_COMPONENT_LAMBDA:
+ printf ("lambda %d\n", dc->u.s_unary_num.num);
+ d_dump (dc->u.s_unary_num.sub, indent+2);
+ return;
}
d_dump (d_left (dc), indent + 2);
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
case DEMANGLE_COMPONENT_TYPED_NAME:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
case DEMANGLE_COMPONENT_TEMPLATE:
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_COVARIANT_THUNK:
case DEMANGLE_COMPONENT_JAVA_CLASS:
case DEMANGLE_COMPONENT_GUARD:
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
case DEMANGLE_COMPONENT_REFTEMP:
case DEMANGLE_COMPONENT_HIDDEN_ALIAS:
case DEMANGLE_COMPONENT_TRANSACTION_CLONE:
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_ARGLIST:
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
break;
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
return has_return_type (d_left (dc));
}
}
v2 demangler without DMGL_PARAMS. */
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
+ || dc->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dc = d_left (dc);
/* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
dcr = d_right (dc);
while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dcr->type == DEMANGLE_COMPONENT_CONST_THIS)
+ || dcr->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dcr = d_left (dcr);
dc->u.s_binary.right = dcr;
}
}
}
+/* <tagged-name> ::= <name> B <source-name> */
+
+static struct demangle_component *
+d_abi_tags (struct d_info *di, struct demangle_component *dc)
+{
+ char peek;
+ while (peek = d_peek_char (di),
+ peek == 'B')
+ {
+ struct demangle_component *tag;
+ d_advance (di, 1);
+ tag = d_source_name (di);
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag);
+ }
+ return dc;
+}
+
/* <name> ::= <nested-name>
::= <unscoped-name>
::= <unscoped-template-name> <template-args>
}
}
-/* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
- ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+/* <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
*/
static struct demangle_component *
{
struct demangle_component *ret;
struct demangle_component **pret;
+ struct demangle_component *rqual;
if (! d_check_char (di, 'N'))
return NULL;
if (pret == NULL)
return NULL;
+ /* Parse the ref-qualifier now and then attach it
+ once we have something to attach it to. */
+ rqual = d_ref_qualifier (di, NULL);
+
*pret = d_prefix (di);
if (*pret == NULL)
return NULL;
+ if (rqual)
+ {
+ d_left (rqual) = ret;
+ ret = rqual;
+ }
+
if (! d_check_char (di, 'E'))
return NULL;
static struct demangle_component *
d_unqualified_name (struct d_info *di)
{
+ struct demangle_component *ret;
char peek;
peek = d_peek_char (di);
if (IS_DIGIT (peek))
- return d_source_name (di);
+ ret = d_source_name (di);
else if (IS_LOWER (peek))
{
- struct demangle_component *ret;
-
ret = d_operator_name (di);
if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR)
{
ret = d_make_comp (di, DEMANGLE_COMPONENT_UNARY, ret,
d_source_name (di));
}
- return ret;
}
else if (peek == 'C' || peek == 'D')
- return d_ctor_dtor_name (di);
+ ret = d_ctor_dtor_name (di);
else if (peek == 'L')
{
- struct demangle_component * ret;
-
d_advance (di, 1);
ret = d_source_name (di);
return NULL;
if (! d_discriminator (di))
return NULL;
- return ret;
}
else if (peek == 'U')
{
switch (d_peek_next_char (di))
{
case 'l':
- return d_lambda (di);
+ ret = d_lambda (di);
+ break;
case 't':
- return d_unnamed_type (di);
+ ret = d_unnamed_type (di);
+ break;
default:
return NULL;
}
}
else
return NULL;
+
+ if (d_peek_char (di) == 'B')
+ ret = d_abi_tags (di, ret);
+ return ret;
}
/* <source-name> ::= <(positive length) number> <identifier> */
{ "an", NL ("&"), 2 },
{ "at", NL ("alignof "), 1 },
{ "az", NL ("alignof "), 1 },
+ { "cc", NL ("const_cast"), 2 },
{ "cl", NL ("()"), 2 },
{ "cm", NL (","), 2 },
{ "co", NL ("~"), 1 },
{ "dV", NL ("/="), 2 },
{ "da", NL ("delete[] "), 1 },
+ { "dc", NL ("dynamic_cast"), 2 },
{ "de", NL ("*"), 1 },
{ "dl", NL ("delete "), 1 },
{ "ds", NL (".*"), 2 },
{ "qu", NL ("?"), 3 },
{ "rM", NL ("%="), 2 },
{ "rS", NL (">>="), 2 },
+ { "rc", NL ("reinterpret_cast"), 2 },
{ "rm", NL ("%"), 2 },
{ "rs", NL (">>"), 2 },
+ { "sc", NL ("static_cast"), 2 },
{ "st", NL ("sizeof "), 1 },
{ "sz", NL ("sizeof "), 1 },
{ "tr", NL ("throw"), 0 },
return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS,
cplus_demangle_type (di), NULL);
+ case 'H':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT,
+ d_name (di), NULL);
+
+ case 'W':
+ return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
+ d_name (di), NULL);
+
default:
return NULL;
}
pret = d_cv_qualifiers (di, &ret, 0);
if (pret == NULL)
return NULL;
- *pret = cplus_demangle_type (di);
- if (! *pret || ! d_add_substitution (di, ret))
+ if (d_peek_char (di) == 'F')
+ {
+ /* cv-qualifiers before a function type apply to 'this',
+ so avoid adding the unqualified function type to
+ the substitution list. */
+ *pret = d_function_type (di);
+ }
+ else
+ *pret = cplus_demangle_type (di);
+ if (!*pret)
+ return NULL;
+ if ((*pret)->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ || (*pret)->type == DEMANGLE_COMPONENT_REFERENCE_THIS)
+ {
+ /* Move the ref-qualifier outside the cv-qualifiers so that
+ they are printed in the right order. */
+ struct demangle_component *fn = d_left (*pret);
+ d_left (*pret) = ret;
+ ret = *pret;
+ *pret = fn;
+ }
+ if (! d_add_substitution (di, ret))
return NULL;
return ret;
}
return pret;
}
-/* <function-type> ::= F [Y] <bare-function-type> E */
+/* <ref-qualifier> ::= R
+ ::= O */
+
+static struct demangle_component *
+d_ref_qualifier (struct d_info *di, struct demangle_component *sub)
+{
+ struct demangle_component *ret = sub;
+ char peek;
+
+ peek = d_peek_char (di);
+ if (peek == 'R' || peek == 'O')
+ {
+ enum demangle_component_type t;
+ if (peek == 'R')
+ {
+ t = DEMANGLE_COMPONENT_REFERENCE_THIS;
+ di->expansion += sizeof "&";
+ }
+ else
+ {
+ t = DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS;
+ di->expansion += sizeof "&&";
+ }
+ d_advance (di, 1);
+
+ ret = d_make_comp (di, t, ret, NULL);
+ }
+
+ return ret;
+}
+
+/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */
static struct demangle_component *
d_function_type (struct d_info *di)
d_advance (di, 1);
}
ret = d_bare_function_type (di, 1);
+ ret = d_ref_qualifier (di, ret);
+
if (! d_check_char (di, 'E'))
return NULL;
return ret;
char peek = d_peek_char (di);
if (peek == '\0' || peek == 'E' || peek == '.')
break;
+ if ((peek == 'R' || peek == 'O')
+ && d_peek_next_char (di) == 'E')
+ /* Function ref-qualifier, not a ref prefix for a parameter type. */
+ break;
type = cplus_demangle_type (di);
if (type == NULL)
return NULL;
{
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)
+ if (cl == NULL)
return NULL;
- if (pmem != &mem && (*pmem)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
- {
- if (! d_add_substitution (di, mem))
- return NULL;
- }
+ /* The ABI says, "The type of a non-static member function is considered
+ to be different, for the purposes of substitution, from the type of a
+ namespace-scope or static member function whose type appears
+ similar. The types of two non-static member functions are considered
+ to be different, for the purposes of substitution, if the functions
+ are members of different classes. In other words, for the purposes of
+ substitution, the class of which the function is a member is
+ considered part of the type of function."
+
+ For a pointer to member function, this call to cplus_demangle_type
+ will end up adding a (possibly qualified) non-member function type to
+ the substitution table, which is not correct; however, the member
+ function type will never be used in a substitution, so putting the
+ wrong type in the substitution table is harmless. */
+
+ mem = cplus_demangle_type (di);
+ if (mem == NULL)
+ return NULL;
return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem);
}
return list;
}
+/* Returns nonzero iff OP is an operator for a C++ cast: const_cast,
+ dynamic_cast, static_cast or reinterpret_cast. */
+
+static int
+op_is_new_cast (struct demangle_component *op)
+{
+ const char *code = op->u.s_operator.op->code;
+ return (code[1] == 'c'
+ && (code[0] == 's' || code[0] == 'd'
+ || code[0] == 'c' || code[0] == 'r'));
+}
+
/* <expression> ::= <(unary) operator-name> <expression>
::= <(binary) operator-name> <expression> <expression>
::= <(trinary) operator-name> <expression> <expression> <expression>
struct demangle_component *left;
struct demangle_component *right;
- left = d_expression (di);
+ if (op_is_new_cast (op))
+ left = cplus_demangle_type (di);
+ else
+ left = d_expression (di);
if (!strcmp (code, "cl"))
right = d_exprlist (di, 'E');
else if (!strcmp (code, "dt") || !strcmp (code, "pt"))
/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>]
::= Z <(function) encoding> E s [<discriminator>]
+ ::= Z <(function) encoding> E d [<parameter> number>] _ <entity name>
*/
static struct demangle_component *
case DEMANGLE_COMPONENT_LAMBDA:
case DEMANGLE_COMPONENT_NAME:
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
case DEMANGLE_COMPONENT_OPERATOR:
case DEMANGLE_COMPONENT_BUILTIN_TYPE:
case DEMANGLE_COMPONENT_SUB_STD:
case DEMANGLE_COMPONENT_CHARACTER:
case DEMANGLE_COMPONENT_FUNCTION_PARAM:
+ case DEMANGLE_COMPONENT_UNNAMED_TYPE:
return NULL;
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR:
d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len);
return;
+ case DEMANGLE_COMPONENT_TAGGED_NAME:
+ d_print_comp (dpi, options, d_left (dc));
+ d_append_string (dpi, "[abi:");
+ d_print_comp (dpi, options, d_right (dc));
+ d_append_char (dpi, ']');
+ return;
+
case DEMANGLE_COMPONENT_QUAL_NAME:
case DEMANGLE_COMPONENT_LOCAL_NAME:
d_print_comp (dpi, options, d_left (dc));
d_append_string (dpi, "::");
else
d_append_char (dpi, '.');
- d_print_comp (dpi, options, d_right (dc));
+ {
+ struct demangle_component *local_name = d_right (dc);
+ if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+ {
+ d_append_string (dpi, "{default arg#");
+ d_append_num (dpi, local_name->u.s_unary_num.num + 1);
+ d_append_string (dpi, "}::");
+ local_name = local_name->u.s_unary_num.sub;
+ }
+ d_print_comp (dpi, options, local_name);
+ }
return;
case DEMANGLE_COMPONENT_TYPED_NAME:
if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS
&& typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS
- && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS)
+ && typed_name->type != DEMANGLE_COMPONENT_CONST_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS
+ && typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS)
break;
typed_name = d_left (typed_name);
local_name = local_name->u.s_unary_num.sub;
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || local_name->type == DEMANGLE_COMPONENT_CONST_THIS)
+ || local_name->type == DEMANGLE_COMPONENT_CONST_THIS
+ || local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || (local_name->type
+ == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))
{
if (i >= sizeof adpm / sizeof adpm[0])
{
d_print_comp (dpi, options, d_left (dc));
return;
+ case DEMANGLE_COMPONENT_TLS_INIT:
+ d_append_string (dpi, "TLS init function for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
+ case DEMANGLE_COMPONENT_TLS_WRAPPER:
+ d_append_string (dpi, "TLS wrapper function for ");
+ d_print_comp (dpi, options, d_left (dc));
+ return;
+
case DEMANGLE_COMPONENT_REFTEMP:
d_append_string (dpi, "reference temporary #");
d_print_comp (dpi, options, d_right (dc));
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL:
case DEMANGLE_COMPONENT_POINTER:
case DEMANGLE_COMPONENT_COMPLEX:
return;
}
+ if (op_is_new_cast (d_left (dc)))
+ {
+ d_print_expr_op (dpi, options, d_left (dc));
+ d_append_char (dpi, '<');
+ d_print_comp (dpi, options, d_left (d_right (dc)));
+ d_append_string (dpi, ">(");
+ d_print_comp (dpi, options, d_right (d_right (dc)));
+ d_append_char (dpi, ')');
+ return;
+ }
+
/* We wrap an expression which uses the greater-than operator in
an extra layer of parens so that it does not get confused
with the '>' which ends the template parameters. */
|| (! suffix
&& (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS)))
+ || mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS
+ || mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || (mods->mod->type
+ == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS))))
{
d_print_mod_list (dpi, options, mods->next, suffix);
return;
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dc->type == DEMANGLE_COMPONENT_CONST_THIS)
+ || dc->type == DEMANGLE_COMPONENT_CONST_THIS
+ || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
+ || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
dc = d_left (dc);
d_print_comp (dpi, options, dc);
if ((options & DMGL_JAVA) == 0)
d_append_char (dpi, '*');
return;
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ /* For the ref-qualifier, put a space before the &. */
+ d_append_char (dpi, ' ');
case DEMANGLE_COMPONENT_REFERENCE:
d_append_char (dpi, '&');
return;
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+ d_append_char (dpi, ' ');
case DEMANGLE_COMPONENT_RVALUE_REFERENCE:
d_append_string (dpi, "&&");
return;
case DEMANGLE_COMPONENT_RESTRICT_THIS:
case DEMANGLE_COMPONENT_VOLATILE_THIS:
case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
break;
default:
break;
{
switch (dc->type)
{
+ /* These cannot appear on a constructor or destructor. */
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_REFERENCE_THIS:
+ case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
default:
dc = NULL;
break;
case DEMANGLE_COMPONENT_TYPED_NAME:
case DEMANGLE_COMPONENT_TEMPLATE:
- case DEMANGLE_COMPONENT_RESTRICT_THIS:
- case DEMANGLE_COMPONENT_VOLATILE_THIS:
- case DEMANGLE_COMPONENT_CONST_THIS:
dc = d_left (dc);
break;
case DEMANGLE_COMPONENT_QUAL_NAME: