OSDN Git Service

* gimplify.c (gimplify_init_ctor_eval): Don't discard a zero-sized
[pf3gnuchains/gcc-fork.git] / gcc / gimplify.c
index d207e7c..cdb8a33 100644 (file)
@@ -2533,6 +2533,17 @@ zero_sized_field_decl (tree fdecl)
   return false;
 }
 
+/* Return true if TYPE is zero sized.  */
+   
+static bool
+zero_sized_type (tree type)
+{
+  if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type)
+      && integer_zerop (TYPE_SIZE (type)))
+    return true;
+  return false;
+}
+
 /* A subroutine of gimplify_init_constructor.  Generate individual
    MODIFY_EXPRs for a CONSTRUCTOR.  OBJECT is the LHS against which the
    assignments should happen.  ELTS is the CONSTRUCTOR_ELTS of the
@@ -2565,7 +2576,12 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
         so we don't have to figure out what's missing ourselves.  */
       gcc_assert (purpose);
 
-      if (zero_sized_field_decl (purpose))
+      /* Skip zero-sized fields, unless value has side-effects.  This can
+        happen with calls to functions returning a zero-sized type, which
+        we shouldn't discard.  As a number of downstream passes don't
+        expect sets of zero-sized fields, we rely on the gimplification of
+        the MODIFY_EXPR we make below to drop the assignment statement.  */
+      if (! TREE_SIDE_EFFECTS (value) && zero_sized_field_decl (purpose))
        continue;
 
       /* If we have a RANGE_EXPR, we have to build a loop to assign the
@@ -2593,10 +2609,14 @@ gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
                        purpose, NULL_TREE, NULL_TREE);
        }
       else
-       cref = build (COMPONENT_REF, TREE_TYPE (purpose),
-                     unshare_expr (object), purpose, NULL_TREE);
+       {
+         gcc_assert (TREE_CODE (purpose) == FIELD_DECL);
+         cref = build (COMPONENT_REF, TREE_TYPE (purpose),
+                       unshare_expr (object), purpose, NULL_TREE);
+       }
 
-      if (TREE_CODE (value) == CONSTRUCTOR)
+      if (TREE_CODE (value) == CONSTRUCTOR
+         && TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE)
        gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
                                 pre_p, cleared);
       else
@@ -2691,13 +2711,18 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
           parts in, then generate code for the non-constant parts.  */
        /* TODO.  There's code in cp/typeck.c to do this.  */
 
-       num_type_elements = count_type_elements (TREE_TYPE (ctor));
+       num_type_elements = count_type_elements (type, true);
 
+       /* If count_type_elements could not determine number of type elements
+          for a constant-sized object, assume clearing is needed.
+          Don't do this for variable-sized objects, as store_constructor
+          will ignore the clearing of variable-sized objects.  */
+       if (num_type_elements < 0 && int_size_in_bytes (type) >= 0)
+         cleared = true;
        /* If there are "lots" of zeros, then block clear the object first.  */
-       if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
-           && num_nonzero_elements < num_type_elements/4)
+       else if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
+                && num_nonzero_elements < num_type_elements/4)
          cleared = true;
-
        /* ??? This bit ought not be needed.  For any element not present
           in the initializer, we should simply set them to zero.  Except
           we'd need to *find* the elements that are not present, and that
@@ -3138,6 +3163,18 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful.  */
   if (TREE_CODE (*expr_p) == INIT_EXPR)
     TREE_SET_CODE (*expr_p, MODIFY_EXPR);
+  
+  /* For zero sized types only gimplify the left hand side and right hand side
+     as statements and throw away the assignment.  */
+  if (zero_sized_type (TREE_TYPE (*from_p)))
+    {
+      gimplify_stmt (from_p);
+      gimplify_stmt (to_p);
+      append_to_statement_list (*from_p, pre_p);
+      append_to_statement_list (*to_p, pre_p);
+      *expr_p = NULL_TREE;
+      return GS_ALL_DONE;
+    }
 
   /* See if any simplifications can be done based on what the RHS is.  */
   ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
@@ -4422,7 +4459,15 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
          /* Historically, the compiler has treated a bare
             reference to a volatile lvalue as forcing a load.  */
          tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p));
-         tree tmp = create_tmp_var (type, "vol");
+         /* Normally, we do want to create a temporary for a
+            TREE_ADDRESSABLE type because such a type should not be
+            copied by bitwise-assignment.  However, we make an
+            exception here, as all we are doing here is ensuring that
+            we read the bytes that make up the type.  We use
+            create_tmp_var_raw because create_tmp_var will abort when
+            given a TREE_ADDRESSABLE type.  */
+         tree tmp = create_tmp_var_raw (type, "vol");
+         gimple_add_tmp_var (tmp);
          *expr_p = build (MODIFY_EXPR, type, tmp, *expr_p);
        }
       else
@@ -4634,7 +4679,9 @@ gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
      type-stripping code with this knowledge because it doesn't matter
      for the bulk of GENERIC/GIMPLE.  It only matters that TYPE_SIZE_UNIT
      and friends retain their "sizetype-ness".  */
-  if (TREE_TYPE (expr) != type && TYPE_IS_SIZETYPE (type))
+  if (TREE_TYPE (expr) != type
+      && TREE_CODE (type) == INTEGER_TYPE
+      && TYPE_IS_SIZETYPE (type))
     {
       tree tmp;