aboutsummaryrefslogtreecommitdiff
path: root/libiberty
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-12-21 17:36:25 -0500
committerJason Merrill <jason@redhat.com>2020-12-21 21:13:41 -0500
commit58fb912c15175f4444144b8a4ab52a4880b84994 (patch)
tree30eb36cd8436ac5f9d9dc3d0b4f4e56018450252 /libiberty
parent93ac0c05ffc84acba8e73ed5238fc325044378e0 (diff)
downloadgcc-58fb912c15175f4444144b8a4ab52a4880b84994.zip
gcc-58fb912c15175f4444144b8a4ab52a4880b84994.tar.gz
gcc-58fb912c15175f4444144b8a4ab52a4880b84994.tar.bz2
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.
Diffstat (limited to 'libiberty')
-rw-r--r--libiberty/cp-demangle.c87
-rw-r--r--libiberty/cp-demangle.h4
-rw-r--r--libiberty/testsuite/demangle-expected3
3 files changed, 72 insertions, 22 deletions
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index 98ab47a..5242727 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -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
diff --git a/libiberty/cp-demangle.h b/libiberty/cp-demangle.h
index 943a3ef..27014cd 100644
--- a/libiberty/cp-demangle.h
+++ b/libiberty/cp-demangle.h
@@ -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;
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 6789d0d..e6b5b64 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -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*)