aboutsummaryrefslogtreecommitdiff
path: root/gdb/cp-name-parser.y
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/cp-name-parser.y')
-rw-r--r--gdb/cp-name-parser.y74
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);