c++: Fix demangling of <unresolved-name>

The ABI for unresolved scoped names on the RHS of . and -> used to be

  sr <type> <unqualified-id>

That changed years ago to something more complex, but G++ was never updated.
This change was particularly incompatible for simple qualified-ids like
A::x, which were previously mangled as sr1A1x, and now sr1AE1x.

This obviously makes life hard for demanglers, which can't know whether to
consume that E or not.  To work around this, we now try demangling with the
newer ABI, and if that fails and we saw an "sr", try again with the older
ABI.

libiberty/ChangeLog:

	PR c++/67343
	* cp-demangle.h (struct d_info): Add unresolved_name_state.
	* cp-demangle.c (d_prefix): Add subst parm.
	(d_nested_name): Pass it.
	(d_unresolved_name): Split out from...
	(d_expression_1): ...here.
	(d_demangle_callback): Maybe retry with old sr mangling.
	* testsuite/demangle-expected: Add test.
This commit is contained in:
Jason Merrill 2020-12-21 17:36:25 -05:00
parent 93ac0c05ff
commit 58fb912c15
3 changed files with 72 additions and 22 deletions

View File

@ -429,7 +429,7 @@ static struct demangle_component *d_name (struct d_info *);
static struct demangle_component *d_nested_name (struct d_info *);
static struct demangle_component *d_prefix (struct d_info *);
static struct demangle_component *d_prefix (struct d_info *, int);
static struct demangle_component *d_unqualified_name (struct d_info *);
@ -1510,7 +1510,7 @@ d_nested_name (struct d_info *di)
once we have something to attach it to. */
rqual = d_ref_qualifier (di, NULL);
*pret = d_prefix (di);
*pret = d_prefix (di, 1);
if (*pret == NULL)
return NULL;
@ -1536,10 +1536,12 @@ d_nested_name (struct d_info *di)
<template-prefix> ::= <prefix> <(template) unqualified-name>
::= <template-param>
::= <substitution>
*/
SUBST is true if we should add substitutions (as normal), false
if not (in an unresolved-name). */
static struct demangle_component *
d_prefix (struct d_info *di)
d_prefix (struct d_info *di, int subst)
{
struct demangle_component *ret = NULL;
@ -1605,7 +1607,7 @@ d_prefix (struct d_info *di)
else
ret = d_make_comp (di, comb_type, ret, dc);
if (peek != 'S' && d_peek_char (di) != 'E')
if (peek != 'S' && d_peek_char (di) != 'E' && subst)
{
if (! d_add_substitution (di, ret))
return NULL;
@ -3291,14 +3293,58 @@ op_is_new_cast (struct demangle_component *op)
|| code[0] == 'c' || code[0] == 'r'));
}
/* <unresolved-name> ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
# T::N::x /decltype(p)::N::x
::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
# A::x, N::y, A<T>::z; "gs" means leading "::"
::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
"gs" is handled elsewhere, as a unary operator. */
static struct demangle_component *
d_unresolved_name (struct d_info *di)
{
struct demangle_component *type;
struct demangle_component *name;
char peek;
/* Consume the "sr". */
d_advance (di, 2);
peek = d_peek_char (di);
if (di->unresolved_name_state
&& (IS_DIGIT (peek)
|| IS_LOWER (peek)
|| peek == 'C'
|| peek == 'U'
|| peek == 'L'))
{
/* The third production is ambiguous with the old unresolved-name syntax
of <type> <base-unresolved-name>; in the old mangling, A::x was mangled
as sr1A1x, now sr1AE1x. So we first try to demangle using the new
mangling, then with the old if that fails. */
di->unresolved_name_state = -1;
type = d_prefix (di, 0);
if (d_peek_char (di) == 'E')
d_advance (di, 1);
}
else
type = cplus_demangle_type (di);
name = d_unqualified_name (di);
if (d_peek_char (di) == 'I')
name = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
d_template_args (di));
return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
}
/* <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>
::= sr <type> <unqualified-name> <template-args>
::= <unresolved-name>
::= <expr-primary>
<braced-expression> ::= <expression>
@ -3308,7 +3354,7 @@ op_is_new_cast (struct demangle_component *op)
# [expr ... expr] = expr
*/
static inline struct demangle_component *
static struct demangle_component *
d_expression_1 (struct d_info *di)
{
char peek;
@ -3319,20 +3365,7 @@ d_expression_1 (struct d_info *di)
else if (peek == 'T')
return d_template_param (di);
else if (peek == 's' && d_peek_next_char (di) == 'r')
{
struct demangle_component *type;
struct demangle_component *name;
d_advance (di, 2);
type = cplus_demangle_type (di);
name = d_unqualified_name (di);
if (d_peek_char (di) != 'I')
return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name);
else
return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type,
d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name,
d_template_args (di)));
}
return d_unresolved_name (di);
else if (peek == 's' && d_peek_next_char (di) == 'p')
{
d_advance (di, 2);
@ -6397,6 +6430,9 @@ d_demangle_callback (const char *mangled, int options,
type = DCT_TYPE;
}
di.unresolved_name_state = 1;
again:
cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
/* PR 87675 - Check for a mangled string that is so long
@ -6455,6 +6491,13 @@ d_demangle_callback (const char *mangled, int options,
if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
dc = NULL;
/* See discussion in d_unresolved_name. */
if (dc == NULL && di.unresolved_name_state == -1)
{
di.unresolved_name_state = 0;
goto again;
}
#ifdef CP_DEMANGLE_DEBUG
d_dump (dc, 0);
#endif

View File

@ -122,6 +122,10 @@ struct d_info
/* Non-zero if we are parsing the type operand of a conversion
operator, but not when in an expression. */
int is_conversion;
/* 1: using new unresolved-name grammar.
-1: using new unresolved-name grammar and saw an unresolved-name.
0: using old unresolved-name grammar. */
int unresolved_name_state;
/* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
the current recursion level. */
unsigned int recursion_level;

View File

@ -1485,3 +1485,6 @@ decltype (({parm#1}.(operator A*))()) j<A>(A)
_Z1fI1AEDtdtfp_srT_1xES1_
decltype ({parm#1}.A::x) f<A>(A)
_Z2f6IP1AEDtptfp_gssr1A1BE1xET_
decltype ({parm#1}->(::A::B::x)) f6<A*>(A*)