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);
+}
+

Reply via email to