re PR middle-end/19515 (Violation of C99 6.7.8 ยง21 for unions)
authorRichard Henderson <rth@redhat.com>
Wed, 26 Jan 2005 15:20:53 +0000 (07:20 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Wed, 26 Jan 2005 15:20:53 +0000 (07:20 -0800)
        PR middle-end/19515
        * expr.c (categorize_ctor_elements): New argument p_must_clear.
        (categorize_ctor_elements_1): Likewise.  Detect a union that isn't
        fully initialized.
        (mostly_zeros_p): Update for new categorize_ctor_elements argument.
        * gimplify.c (gimplify_init_constructor): Likewise.  Only shove
        objects into static storage if they have more than one non-zero value.
        * tree.h (categorize_ctor_elements): Update decl.

From-SVN: r94266

gcc/ChangeLog
gcc/expr.c
gcc/gimplify.c
gcc/testsuite/gcc.c-torture/execute/pr19515.c [new file with mode: 0644]
gcc/tree.h

index ef8f274bc90493197a655ed2a8ea2f820d9ce1bd..a7b83b8d4fe85b447080a8e1a8d545b40bfd5e83 100644 (file)
@@ -1,3 +1,14 @@
+2005-01-26  Richard Henderson  <rth@redhat.com>
+
+       PR middle-end/19515
+       * expr.c (categorize_ctor_elements): New argument p_must_clear.
+       (categorize_ctor_elements_1): Likewise.  Detect a union that isn't
+       fully initialized.
+       (mostly_zeros_p): Update for new categorize_ctor_elements argument.
+       * gimplify.c (gimplify_init_constructor): Likewise.  Only shove
+       objects into static storage if they have more than one non-zero value.
+       * tree.h (categorize_ctor_elements): Update decl.
+
 2005-01-26  Steven Bosscher  <stevenb@suse.de>
 
        PR middle-end/19616     
index ea6f15a10b83a36e0de638e2bc96f212f4d18f2c..ed693a3166f6163371194766c2eee9af5627f7b8 100644 (file)
@@ -4272,12 +4272,15 @@ store_expr (tree exp, rtx target, int call_param_p)
    * how many scalar fields are set to non-constant values,
      and place it in  *P_NC_ELTS; and
    * how many scalar fields in total are in CTOR,
-     and place it in *P_ELT_COUNT.  */
+     and place it in *P_ELT_COUNT.
+   * if a type is a union, and the initializer from the constructor
+     is not the largest element in the union, then set *p_must_clear.  */
 
 static void
 categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
                            HOST_WIDE_INT *p_nc_elts,
-                           HOST_WIDE_INT *p_elt_count)
+                           HOST_WIDE_INT *p_elt_count,
+                           bool *p_must_clear)
 {
   HOST_WIDE_INT nz_elts, nc_elts, elt_count;
   tree list;
@@ -4307,11 +4310,11 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        {
        case CONSTRUCTOR:
          {
-           HOST_WIDE_INT nz = 0, nc = 0, count = 0;
-           categorize_ctor_elements_1 (value, &nz, &nc, &count);
+           HOST_WIDE_INT nz = 0, nc = 0, ic = 0;
+           categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear);
            nz_elts += mult * nz;
            nc_elts += mult * nc;
-           elt_count += mult * count;
+           elt_count += mult * ic;
          }
          break;
 
@@ -4356,6 +4359,36 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        }
     }
 
+  if (!*p_must_clear
+      && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
+         || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE))
+    {
+      tree init_sub_type;
+
+      /* We don't expect more than one element of the union to be
+        initialized.  Not sure what we should do otherwise... */
+      list = CONSTRUCTOR_ELTS (ctor);
+      gcc_assert (TREE_CHAIN (list) == NULL);
+
+      init_sub_type = TREE_TYPE (TREE_VALUE (list));
+
+      /* ??? We could look at each element of the union, and find the
+        largest element.  Which would avoid comparing the size of the
+        initialized element against any tail padding in the union.
+        Doesn't seem worth the effort...  */
+      if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)), 
+                           TYPE_SIZE (init_sub_type)) == 1)
+       {
+         /* And now we have to find out if the element itself is fully
+            constructed.  E.g. for union { struct { int a, b; } s; } u
+            = { .s = { .a = 1 } }.  */
+         if (elt_count != count_type_elements (init_sub_type))
+           *p_must_clear = true;
+       }
+      else
+       *p_must_clear = true;
+    }
+
   *p_nz_elts += nz_elts;
   *p_nc_elts += nc_elts;
   *p_elt_count += elt_count;
@@ -4364,12 +4397,15 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
 void
 categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
                          HOST_WIDE_INT *p_nc_elts,
-                         HOST_WIDE_INT *p_elt_count)
+                         HOST_WIDE_INT *p_elt_count,
+                         bool *p_must_clear)
 {
   *p_nz_elts = 0;
   *p_nc_elts = 0;
   *p_elt_count = 0;
-  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count);
+  *p_must_clear = false;
+  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count,
+                             p_must_clear);
 }
 
 /* Count the number of scalars in TYPE.  Return -1 on overflow or
@@ -4459,8 +4495,12 @@ mostly_zeros_p (tree exp)
 
     {
       HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+      bool must_clear;
+
+      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+      if (must_clear)
+       return 1;
 
-      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count);
       elts = count_type_elements (TREE_TYPE (exp));
 
       return nz_elts < elts / 4;
index d77a3b36adeea2c45dc0477e045c103b37b3a1e8..ac9ae14a74a7d4b1f21064a9738aedfd9b387beb 100644 (file)
@@ -2599,11 +2599,12 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 
        categorize_ctor_elements (ctor, &num_nonzero_elements,
                                  &num_nonconstant_elements,
-                                 &num_ctor_elements);
+                                 &num_ctor_elements, &cleared);
 
        /* If a const aggregate variable is being initialized, then it
           should never be a lose to promote the variable to be static.  */
        if (num_nonconstant_elements == 0
+           && num_nonzero_elements > 1
            && TREE_READONLY (object)
            && TREE_CODE (object) == VAR_DECL)
          {
@@ -2685,7 +2686,6 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
        num_type_elements = count_type_elements (TREE_TYPE (ctor));
 
        /* If there are "lots" of zeros, then block clear the object first.  */
-       cleared = false;
        if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
            && num_nonzero_elements < num_type_elements/4)
          cleared = true;
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr19515.c b/gcc/testsuite/gcc.c-torture/execute/pr19515.c
new file mode 100644 (file)
index 0000000..df0e107
--- /dev/null
@@ -0,0 +1,17 @@
+/* PR 19515 */
+
+typedef union {
+      char a2[8];
+}aun;
+
+void abort (void);
+
+int main(void)
+{
+  aun a = {{0}};
+
+  if (a.a2[2] != 0)
+    abort ();
+  return 0;
+}
+
index 884f2c43d45d8d515d398cf7a7abccad35d3fe36..65e660fecc4faa8a09d0c728e619f1c233b216af 100644 (file)
@@ -3235,8 +3235,8 @@ extern int fields_length (tree);
 
 extern bool initializer_zerop (tree);
 
-extern void categorize_ctor_elements (tree, HOST_WIDE_INT *,
-                                     HOST_WIDE_INT *, HOST_WIDE_INT *);
+extern void categorize_ctor_elements (tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
+                                     HOST_WIDE_INT *, bool *);
 extern HOST_WIDE_INT count_type_elements (tree);
 
 /* add_var_to_bind_expr (bind_expr, var) binds var to bind_expr.  */