From 58fb912c15175f4444144b8a4ab52a4880b84994 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 21 Dec 2020 17:36:25 -0500 Subject: [PATCH] c++: Fix demangling of The ABI for unresolved scoped names on the RHS of . and -> used to be sr 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. --- libiberty/cp-demangle.c | 87 ++++++++++++++++++++------- libiberty/cp-demangle.h | 4 ++ libiberty/testsuite/demangle-expected | 3 + 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 98ab47a3460..52427275f44 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) unqualified-name> ::= ::= -*/ + + 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')); } +/* ::= [gs] # x or (with "gs") ::x + ::= sr # T::x / decltype(p)::x + # T::N::x /decltype(p)::N::x + ::= srN + E + # A::x, N::y, A::z; "gs" means leading "::" + ::= [gs] sr + E + + "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 ; 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); +} + /* ::= <(unary) operator-name> ::= <(binary) operator-name> ::= <(trinary) operator-name> ::= cl + E ::= st ::= - ::= sr - ::= sr + ::= ::= ::= @@ -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 943a3ef478e..27014cde258 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 6789d0d1d9d..e6b5b64b9a9 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -1485,3 +1485,6 @@ decltype (({parm#1}.(operator A*))()) j(A) _Z1fI1AEDtdtfp_srT_1xES1_ decltype ({parm#1}.A::x) f(A) + +_Z2f6IP1AEDtptfp_gssr1A1BE1xET_ +decltype ({parm#1}->(::A::B::x)) f6(A*) -- 2.30.2