aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2005-01-26 07:20:53 -0800
committerRichard Henderson <rth@gcc.gnu.org>2005-01-26 07:20:53 -0800
commit6f642f985272e36ec5bac248a65e912605727337 (patch)
tree2bf5d70375fa0bc54fd1069c76adcd376923ad97 /gcc/expr.c
parentead553a1d9f9206c1f5a3b1a6799ea877fc9a845 (diff)
downloadgcc-6f642f985272e36ec5bac248a65e912605727337.zip
gcc-6f642f985272e36ec5bac248a65e912605727337.tar.gz
gcc-6f642f985272e36ec5bac248a65e912605727337.tar.bz2
re PR middle-end/19515 (Violation of C99 6.7.8 ยง21 for unions)
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
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c56
1 files changed, 48 insertions, 8 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index ea6f15a..ed693a3 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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;