]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c: Fix sizeof error recovery [PR117745]
authorJakub Jelinek <jakub@redhat.com>
Wed, 27 Nov 2024 16:29:28 +0000 (17:29 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 13 Jun 2025 09:25:58 +0000 (11:25 +0200)
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  <jakub@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)

gcc/c/c-parser.cc
gcc/testsuite/gcc.dg/pr117745.c [new file with mode: 0644]

index 78a313fe31ef26c7e753761dea8e8656dffd1a21..9264581da558a31cae9625b3982daf45b3a0fc92 100644 (file)
@@ -8311,13 +8311,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 (file)
index 0000000..3485f7c
--- /dev/null
@@ -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 ()])); }