[gcc r12-11156] c: Fix sizeof error recovery [PR117745]

Jakub Jelinek jakub@gcc.gnu.org
Fri Jun 13 15:40:52 GMT 2025


https://gcc.gnu.org/g:b740a4accf8995ed800f191310180c168e59450f

commit r12-11156-gb740a4accf8995ed800f191310180c168e59450f
Author: Jakub Jelinek <jakub@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  <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)

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 78a313fe31ef..9264581da558 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -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
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 ()])); }


More information about the Gcc-cvs mailing list