diff options
author | Jason Merrill <jason@redhat.com> | 2020-12-21 17:36:25 -0500 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2020-12-21 21:13:41 -0500 |
commit | 58fb912c15175f4444144b8a4ab52a4880b84994 (patch) | |
tree | 30eb36cd8436ac5f9d9dc3d0b4f4e56018450252 /libiberty/cp-demangle.c | |
parent | 93ac0c05ffc84acba8e73ed5238fc325044378e0 (diff) | |
download | gcc-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/cp-demangle.c')
-rw-r--r-- | libiberty/cp-demangle.c | 87 |
1 files changed, 65 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 |