This patch solves another ICE-after-error problem in the C family front-ends. Upon a conflicting type redeclaration, the ambiguous type is poisoned with an error_mark_node to indicate to the middle-end that the type is suspect, but care has to be taken by the front-end to avoid passing these malformed trees into the middle-end during error recovery. In this case, a var_decl with a poisoned type appears within a sizeof() expression (wrapped in NOP_EXPR) which causes problems.
This revision of the patch tests seen_error() to avoid tree traversal (STRIP_NOPs) in the most common case that an error hasn't occurred. Both this version (and an earlier revision that didn't test seen_error) have survived bootstrap and regression testing on x86_64-pc-linux-gnu. As a consolation, this code also contains a minor performance improvement, by avoiding trying to create (and folding away) a CEIL_DIV_EXPR in the common case that "char" is a single-byte. The current code relies on the middle-end's tree folding to recognize that CEIL_DIV_EXPR of integer_one_node is a no-op, that can be optimized away. Ok for mainline? 2024-04-30 Roger Sayle <ro...@nextmovesoftware.com> gcc/c-family/ChangeLog PR c/109618 * c-common.cc (c_sizeof_or_alignof_type): If seen_error() check whether value is (a VAR_DECL) of type error_mark_node, or a NOP_EXPR thereof. Avoid folding CEIL_DIV_EXPR for the common case where char_type is a single byte. gcc/testsuite/ChangeLog PR c/109618 * gcc.dg/pr109618.c: New test case. Thanks in advance, Roger --
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 6fa8243..be8ff09 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -3993,10 +3993,31 @@ c_sizeof_or_alignof_type (location_t loc, else { if (is_sizeof) - /* Convert in case a char is more than one unit. */ - value = size_binop_loc (loc, CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type), - size_int (TYPE_PRECISION (char_type_node) - / BITS_PER_UNIT)); + { + value = TYPE_SIZE_UNIT (type); + + /* PR 109618: Check for erroneous types, stripping NOPs. */ + if (seen_error ()) + { + tree tmp = value; + while (CONVERT_EXPR_P (tmp) + || TREE_CODE (tmp) == NON_LVALUE_EXPR) + { + if (TREE_TYPE (tmp) == error_mark_node) + return error_mark_node; + tmp = TREE_OPERAND (tmp, 0); + } + if (tmp == error_mark_node + || TREE_TYPE (tmp) == error_mark_node) + return error_mark_node; + } + + /* Convert in case a char is more than one unit. */ + if (TYPE_PRECISION (char_type_node) != BITS_PER_UNIT) + value = size_binop_loc (loc, CEIL_DIV_EXPR, value, + size_int (TYPE_PRECISION (char_type_node) + / BITS_PER_UNIT)); + } else if (min_alignof) value = size_int (min_align_of_type (type)); else diff --git a/gcc/testsuite/gcc.dg/pr109618.c b/gcc/testsuite/gcc.dg/pr109618.c new file mode 100644 index 0000000..f240907 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr109618.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ +int foo() +{ + const unsigned int var_1 = 2; + + char var_5[var_1]; + + int var_1[10]; /* { dg-error "conflicting type" } */ + + return sizeof(var_5); +} +