https://gcc.gnu.org/g:0183fb1cef5e382af2a5c0dc3c59efbcd32db6ab
commit r14-11146-g0183fb1cef5e382af2a5c0dc3c59efbcd32db6ab Author: Jakub Jelinek <ja...@redhat.com> Date: Wed Nov 27 17:29:28 2024 +0100 c: Fix sizeof error recovery [PR117745] Compilation of the following testcase hangs forever after emitting first error. The problem is that in one place we just return error_mark_node directly rather than going through c_expr_sizeof_expr or c_expr_sizeof_type. The parsing of the expression could have called record_maybe_used_decl though, but nothing calls pop_maybe_used which needs to be called after parsing of every sizeof/typeof, successful or not. At the end of the toplevel declaration we free the parser_obstack and in another function record_maybe_used_decl is called again and due to the missing pop_maybe_unused we end up with a cycle in the chain. The following patch fixes it by just setting error and goto to the sizeof_expr: c_inhibit_evaluation_warnings--; in_sizeof--; mark_exp_read (expr.value); if (TREE_CODE (expr.value) == COMPONENT_REF && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1))) error_at (expr_loc, "%<sizeof%> applied to a bit-field"); result = c_expr_sizeof_expr (expr_loc, expr); where c_expr_sizeof_expr will do: struct c_expr ret; if (expr.value == error_mark_node) { ret.value = error_mark_node; ret.original_code = ERROR_MARK; ret.original_type = NULL; ret.m_decimal = 0; pop_maybe_used (false); } ... return ret; which is exactly what the old code did manually except for the missing pop_maybe_used call. mark_exp_read does nothing on error_mark_node and error_mark_node doesn't have COMPONENT_REF tree_code. 2024-11-27 Jakub Jelinek <ja...@redhat.com> PR c/117745 * c-parser.cc (c_parser_sizeof_expression): If type_name is NULL, just expr.set_error () and goto sizeof_expr instead of doing error recovery manually. * gcc.dg/pr117745.c: New test. (cherry picked from commit 958f0025f41d8bd9812e4da91a72b1ad79496e5b) Diff: --- gcc/c/c-parser.cc | 12 +++++------- gcc/testsuite/gcc.dg/pr117745.c | 8 ++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 5fcfff7134a8..cd2e089fe38d 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -9891,13 +9891,11 @@ c_parser_sizeof_expression (c_parser *parser) finish = parser->tokens_buf[0].location; if (type_name == NULL) { - struct c_expr ret; - c_inhibit_evaluation_warnings--; - in_sizeof--; - ret.set_error (); - ret.original_code = ERROR_MARK; - ret.original_type = NULL; - return ret; + /* Let c_expr_sizeof_expr call pop_maybe_used and fill in c_expr + for parsing error; the parsing of the expression could have + called record_maybe_used_decl. */ + expr.set_error (); + goto sizeof_expr; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) { diff --git a/gcc/testsuite/gcc.dg/pr117745.c b/gcc/testsuite/gcc.dg/pr117745.c new file mode 100644 index 000000000000..3485f7c9b1ab --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr117745.c @@ -0,0 +1,8 @@ +/* PR c/117745 */ +/* { dg-do compile } */ +/* { dg-options "" } */ + +static int foo (void); +void bar (void) { sizeof (int [0 ? foo () : 1); } /* { dg-error "expected" } */ +static int baz (void); +void qux (void) { sizeof (sizeof (int[baz ()])); }