diff options
Diffstat (limited to 'gdb/cp-name-parser.y')
-rw-r--r-- | gdb/cp-name-parser.y | 74 |
1 files changed, 61 insertions, 13 deletions
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index 9d0085d..cafd6b2 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -1,6 +1,6 @@ /* YACC parser for C++ names, for GDB. - Copyright (C) 2003-2024 Free Software Foundation, Inc. + Copyright (C) 2003-2025 Free Software Foundation, Inc. Parts of the lexer are based on c-exp.y from GDB. @@ -75,19 +75,35 @@ struct cpname_state { + cpname_state (const char *input, demangle_parse_info *info) + : lexptr (input), + prev_lexptr (input), + demangle_info (info) + { } + + /* Un-push a character into the lexer. This can only un-push the + previous character in the input string. */ + void unpush (char c) + { + gdb_assert (lexptr[-1] == c); + --lexptr; + } + /* LEXPTR is the current pointer into our lex buffer. PREV_LEXPTR is the start of the last token lexed, only used for diagnostics. ERROR_LEXPTR is the first place an error occurred. GLOBAL_ERRMSG is the first error message encountered. */ - const char *lexptr, *prev_lexptr, *error_lexptr, *global_errmsg; + const char *lexptr, *prev_lexptr; + const char *error_lexptr = nullptr; + const char *global_errmsg = nullptr; demangle_parse_info *demangle_info; /* The parse tree created by the parser is stored here after a successful parse. */ - struct demangle_component *global_result; + struct demangle_component *global_result = nullptr; struct demangle_component *d_grab (); @@ -358,6 +374,22 @@ function | colon_ext_only function_arglist start_opt { $$ = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, $2.comp); if ($3) $$ = state->fill_comp (DEMANGLE_COMPONENT_LOCAL_NAME, $$, $3); } + | colon_ext_only + { + /* This production is a hack to handle + something like "name::operator new[]" -- + without arguments, this ordinarily would + not parse, but canonicalizing it is + important. So we infer the "()" and then + remove it when converting back to string. + Note that this works because this + production is terminal. */ + demangle_component *comp + = state->fill_comp (DEMANGLE_COMPONENT_FUNCTION_TYPE, + nullptr, nullptr); + $$ = state->fill_comp (DEMANGLE_COMPONENT_TYPED_NAME, $1, comp); + state->demangle_info->added_parens = true; + } | conversion_op_name start_opt { $$ = $1.comp; @@ -507,6 +539,11 @@ conversion_op_name unqualified_name: oper | oper '<' template_params '>' { $$ = state->fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); } + | oper '<' template_params RSH + { + $$ = state->fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); + state->unpush ('>'); + } | '~' NAME { $$ = state->make_dtor (gnu_v3_complete_object_dtor, $2); } ; @@ -572,6 +609,11 @@ nested_name : NAME COLONCOLON /* DEMANGLE_COMPONENT_TEMPLATE_ARGLIST */ templ : NAME '<' template_params '>' { $$ = state->fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); } + | NAME '<' template_params RSH + { + $$ = state->fill_comp (DEMANGLE_COMPONENT_TEMPLATE, $1, $3.comp); + state->unpush ('>'); + } ; template_params : template_arg @@ -2018,15 +2060,14 @@ struct std::unique_ptr<demangle_parse_info> cp_demangled_name_to_comp (const char *demangled_name, std::string *errmsg) { - cpname_state state; - - state.prev_lexptr = state.lexptr = demangled_name; - state.error_lexptr = NULL; - state.global_errmsg = NULL; - auto result = std::make_unique<demangle_parse_info> (); - state.demangle_info = result.get (); + cpname_state state (demangled_name, result.get ()); + /* Note that we can't set yydebug here, as is done in the other + parsers. Bison implements yydebug as a global, even with a pure + parser, and this parser is run from worker threads. So, changing + yydebug causes TSan reports. If you need to debug this parser, + debug gdb and set the global from the outer gdb. */ if (yyparse (&state)) { if (state.global_errmsg && errmsg) @@ -2083,13 +2124,20 @@ canonicalize_tests () should_be_the_same ("something<void ()>", "something<void (void)>"); should_parse ("void whatever::operator<=><int, int>"); + + should_be_the_same ("Foozle<int>::fogey<Empty<int> > (Empty<int>)", + "Foozle<int>::fogey<Empty<int>> (Empty<int>)"); + + should_be_the_same ("something :: operator new [ ]", + "something::operator new[]"); + should_be_the_same ("something :: operator new", + "something::operator new"); + should_be_the_same ("operator()", "operator ()"); } #endif -void _initialize_cp_name_parser (); -void -_initialize_cp_name_parser () +INIT_GDB_FILE (cp_name_parser) { #if GDB_SELF_TEST selftests::register_test ("canonicalize", canonicalize_tests); |