diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-11-27 17:29:28 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2024-11-27 17:29:28 +0100 |
commit | 958f0025f41d8bd9812e4da91a72b1ad79496e5b (patch) | |
tree | 718822490f3147a37357eb97a4aaacce7ddac932 /gcc/c/c-parser.cc | |
parent | 4a8685911697c237ff8c0589827eb8649f8440f1 (diff) | |
download | gcc-958f0025f41d8bd9812e4da91a72b1ad79496e5b.zip gcc-958f0025f41d8bd9812e4da91a72b1ad79496e5b.tar.gz gcc-958f0025f41d8bd9812e4da91a72b1ad79496e5b.tar.bz2 |
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.
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r-- | gcc/c/c-parser.cc | 12 |
1 files changed, 5 insertions, 7 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 730f70b..0e6f87e 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -10416,13 +10416,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)) { |