OSDN Git Service

Make CONSTRUCTOR use VEC to store initializers.
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index 34f94d1..d9c9949 100644 (file)
@@ -1259,103 +1259,116 @@ decl_constant_value_for_broken_optimization (tree decl)
   return ret;
 }
 
-
-/* Perform the default conversion of arrays and functions to pointers.
-   Return the result of converting EXP.  For any other expression, just
-   return EXP after removing NOPs.  */
-
-tree
-default_function_array_conversion (tree exp)
+/* Convert the array expression EXP to a pointer.  */
+static tree
+array_to_pointer_conversion (tree exp)
 {
-  tree orig_exp;
+  tree orig_exp = exp;
   tree type = TREE_TYPE (exp);
-  enum tree_code code = TREE_CODE (type);
-  int not_lvalue = 0;
+  tree adr;
+  tree restype = TREE_TYPE (type);
+  tree ptrtype;
 
-  /* Strip NON_LVALUE_EXPRs and no-op conversions, since we aren't using as
-     an lvalue.
+  gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
 
-     Do not use STRIP_NOPS here!  It will remove conversions from pointer
-     to integer and cause infinite recursion.  */
-  orig_exp = exp;
-  while (TREE_CODE (exp) == NON_LVALUE_EXPR
-        || (TREE_CODE (exp) == NOP_EXPR
-            && TREE_TYPE (TREE_OPERAND (exp, 0)) == TREE_TYPE (exp)))
-    {
-      if (TREE_CODE (exp) == NON_LVALUE_EXPR)
-       not_lvalue = 1;
-      exp = TREE_OPERAND (exp, 0);
-    }
+  STRIP_TYPE_NOPS (exp);
 
   if (TREE_NO_WARNING (orig_exp))
     TREE_NO_WARNING (exp) = 1;
 
-  if (code == FUNCTION_TYPE)
+  ptrtype = build_pointer_type (restype);
+
+  if (TREE_CODE (exp) == INDIRECT_REF)
+    return convert (ptrtype, TREE_OPERAND (exp, 0));
+
+  if (TREE_CODE (exp) == VAR_DECL)
     {
-      return build_unary_op (ADDR_EXPR, exp, 0);
+      /* We are making an ADDR_EXPR of ptrtype.  This is a valid
+        ADDR_EXPR because it's the best way of representing what
+        happens in C when we take the address of an array and place
+        it in a pointer to the element type.  */
+      adr = build1 (ADDR_EXPR, ptrtype, exp);
+      if (!c_mark_addressable (exp))
+       return error_mark_node;
+      TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
+      return adr;
     }
-  if (code == ARRAY_TYPE)
-    {
-      tree adr;
-      tree restype = TREE_TYPE (type);
-      tree ptrtype;
-      int constp = 0;
-      int volatilep = 0;
-      int lvalue_array_p;
 
-      if (REFERENCE_CLASS_P (exp) || DECL_P (exp))
-       {
-         constp = TREE_READONLY (exp);
-         volatilep = TREE_THIS_VOLATILE (exp);
-       }
+  /* This way is better for a COMPONENT_REF since it can
+     simplify the offset for a component.  */
+  adr = build_unary_op (ADDR_EXPR, exp, 1);
+  return convert (ptrtype, adr);
+}
 
-      if (TYPE_QUALS (type) || constp || volatilep)
-       restype
-         = c_build_qualified_type (restype,
-                                   TYPE_QUALS (type)
-                                   | (constp * TYPE_QUAL_CONST)
-                                   | (volatilep * TYPE_QUAL_VOLATILE));
+/* Convert the function expression EXP to a pointer.  */
+static tree
+function_to_pointer_conversion (tree exp)
+{
+  tree orig_exp = exp;
 
-      if (TREE_CODE (exp) == INDIRECT_REF)
-       return convert (build_pointer_type (restype),
-                       TREE_OPERAND (exp, 0));
+  gcc_assert (TREE_CODE (TREE_TYPE (exp)) == FUNCTION_TYPE);
 
-      if (TREE_CODE (exp) == COMPOUND_EXPR)
-       {
-         tree op1 = default_conversion (TREE_OPERAND (exp, 1));
-         return build2 (COMPOUND_EXPR, TREE_TYPE (op1),
-                        TREE_OPERAND (exp, 0), op1);
-       }
+  STRIP_TYPE_NOPS (exp);
 
-      lvalue_array_p = !not_lvalue && lvalue_p (exp);
-      if (!flag_isoc99 && !lvalue_array_p)
-       {
-         /* Before C99, non-lvalue arrays do not decay to pointers.
-            Normally, using such an array would be invalid; but it can
-            be used correctly inside sizeof or as a statement expression.
-            Thus, do not give an error here; an error will result later.  */
-         return exp;
-       }
+  if (TREE_NO_WARNING (orig_exp))
+    TREE_NO_WARNING (exp) = 1;
 
-      ptrtype = build_pointer_type (restype);
+  return build_unary_op (ADDR_EXPR, exp, 0);
+}
 
-      if (TREE_CODE (exp) == VAR_DECL)
-       {
-         /* We are making an ADDR_EXPR of ptrtype.  This is a valid
-            ADDR_EXPR because it's the best way of representing what
-            happens in C when we take the address of an array and place
-            it in a pointer to the element type.  */
-         adr = build1 (ADDR_EXPR, ptrtype, exp);
-         if (!c_mark_addressable (exp))
-           return error_mark_node;
-         TREE_SIDE_EFFECTS (adr) = 0;   /* Default would be, same as EXP.  */
-         return adr;
-       }
-      /* This way is better for a COMPONENT_REF since it can
-        simplify the offset for a component.  */
-      adr = build_unary_op (ADDR_EXPR, exp, 1);
-      return convert (ptrtype, adr);
+/* Perform the default conversion of arrays and functions to pointers.
+   Return the result of converting EXP.  For any other expression, just
+   return EXP after removing NOPs.  */
+
+struct c_expr
+default_function_array_conversion (struct c_expr exp)
+{
+  tree orig_exp = exp.value;
+  tree type = TREE_TYPE (exp.value);
+  enum tree_code code = TREE_CODE (type);
+
+  switch (code)
+    {
+    case ARRAY_TYPE:
+      {
+       bool not_lvalue = false;
+       bool lvalue_array_p;
+
+       while ((TREE_CODE (exp.value) == NON_LVALUE_EXPR
+               || TREE_CODE (exp.value) == NOP_EXPR)
+              && TREE_TYPE (TREE_OPERAND (exp.value, 0)) == type)
+         {
+           if (TREE_CODE (exp.value) == NON_LVALUE_EXPR)
+             not_lvalue = true;
+           exp.value = TREE_OPERAND (exp.value, 0);
+         }
+
+       if (TREE_NO_WARNING (orig_exp))
+         TREE_NO_WARNING (exp.value) = 1;
+
+       lvalue_array_p = !not_lvalue && lvalue_p (exp.value);
+       if (!flag_isoc99 && !lvalue_array_p)
+         {
+           /* Before C99, non-lvalue arrays do not decay to pointers.
+              Normally, using such an array would be invalid; but it can
+              be used correctly inside sizeof or as a statement expression.
+              Thus, do not give an error here; an error will result later.  */
+           return exp;
+         }
+
+       exp.value = array_to_pointer_conversion (exp.value);
+      }
+      break;
+    case FUNCTION_TYPE:
+      exp.value = function_to_pointer_conversion (exp.value);
+      break;
+    default:
+      STRIP_TYPE_NOPS (exp.value);
+      if (TREE_NO_WARNING (orig_exp))
+       TREE_NO_WARNING (exp.value) = 1;
+      break;
     }
+
   return exp;
 }
 
@@ -1992,7 +2005,8 @@ build_function_call (tree function, tree params)
       name = DECL_NAME (function);
       fundecl = function;
     }
-  function = default_function_array_conversion (function);
+  if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
+    function = function_to_pointer_conversion (function);
 
   /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
      expressions, like those used for ObjC messenger dispatches.  */
@@ -2047,8 +2061,7 @@ build_function_call (tree function, tree params)
 
          if (AGGREGATE_TYPE_P (return_type))
            rhs = build_compound_literal (return_type,
-                                         build_constructor (return_type,
-                                                            NULL_TREE));
+                                         build_constructor (return_type, 0));
          else
            rhs = fold_build1 (NOP_EXPR, return_type, integer_zero_node);
 
@@ -2730,11 +2743,13 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
       /* For &x[y], return x+y */
       if (TREE_CODE (arg) == ARRAY_REF)
        {
-         if (!c_mark_addressable (TREE_OPERAND (arg, 0)))
+         tree op0 = TREE_OPERAND (arg, 0);
+         if (!c_mark_addressable (op0))
            return error_mark_node;
          return build_binary_op (PLUS_EXPR,
-                                 default_function_array_conversion
-                                   (TREE_OPERAND (arg, 0)),
+                                 (TREE_CODE (TREE_TYPE (op0)) == ARRAY_TYPE
+                                  ? array_to_pointer_conversion (op0)
+                                  : op0),
                                  TREE_OPERAND (arg, 1), 1);
        }
 
@@ -2774,9 +2789,6 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
 
       val = build1 (ADDR_EXPR, argtype, arg);
 
-      if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
-       TREE_INVARIANT (val) = TREE_CONSTANT (val) = 1;
-
       return val;
 
     default:
@@ -3197,8 +3209,7 @@ build_c_cast (tree type, tree expr)
          if (pedantic)
            pedwarn ("ISO C forbids casts to union type");
          t = digest_init (type,
-                          build_constructor (type,
-                                             build_tree_list (field, value)),
+                          build_constructor_single (type, field, value),
                           true, 0);
          TREE_CONSTANT (t) = TREE_CONSTANT (value);
          TREE_INVARIANT (t) = TREE_INVARIANT (value);
@@ -3780,6 +3791,55 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
         warning (OPT_Wc___compat, "request for implicit conversion from "
                  "%qT to %qT not permitted in C++", rhstype, type);
 
+      /* Check if the right-hand side has a format attribute but the
+        left-hand side doesn't.  */
+      if (warn_missing_format_attribute)
+        {
+         tree rattrs = TYPE_ATTRIBUTES (ttr), ra;
+         for (ra = rattrs; ra; ra = TREE_CHAIN (ra))
+           {
+             if (is_attribute_p ("format", TREE_PURPOSE (ra)))
+               break;
+           }
+         if (ra)
+           {
+             tree lattrs = TYPE_ATTRIBUTES (ttl), la;
+             for (la = lattrs; la; la = TREE_CHAIN (la))
+             {
+               if (is_attribute_p ("format", TREE_PURPOSE (la)))
+                 break;
+             }
+             if (!la)
+               switch (errtype)
+                 {
+                 case ic_argpass:
+                 case ic_argpass_nonproto:
+                   warning (OPT_Wmissing_format_attribute,
+                            "argument %d of %qE might be "
+                            "a candidate for a format attribute",
+                            parmnum, rname);
+                   break;
+                 case ic_assign:
+                   warning (OPT_Wmissing_format_attribute,
+                            "assignment left-hand side might be "
+                            "a candidate for a format attribute");
+                   break;
+                 case ic_init:
+                   warning (OPT_Wmissing_format_attribute,
+                            "initialization left-hand side might be "
+                            "a candidate for a format attribute");
+                   break;
+                 case ic_return:
+                   warning (OPT_Wmissing_format_attribute,
+                            "return type might be "
+                            "a candidate for a format attribute");
+                   break;
+                 default:
+                   gcc_unreachable ();
+                 }
+           }
+       }
+      
       /* Any non-function converts to a [const][volatile] void *
         and vice versa; otherwise, targets must be the same.
         Meanwhile, the lhs target must have all the qualifiers of the rhs.  */
@@ -4335,18 +4395,22 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
 
       if (TREE_CODE (inside_init) == CONSTRUCTOR)
        {
-         tree link;
+         unsigned HOST_WIDE_INT ix;
+         tree value;
+         bool constant_p = true;
 
          /* Iterate through elements and check if all constructor
             elements are *_CSTs.  */
-         for (link = CONSTRUCTOR_ELTS (inside_init);
-              link;
-              link = TREE_CHAIN (link))
-           if (! CONSTANT_CLASS_P (TREE_VALUE (link)))
-             break;
+         FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (inside_init), ix, value)
+           if (!CONSTANT_CLASS_P (value))
+             {
+               constant_p = false;
+               break;
+             }
 
-         if (link == NULL)
-           return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
+         if (constant_p)
+           return build_vector_from_ctor (type,
+                                          CONSTRUCTOR_ELTS (inside_init));
        }
     }
 
@@ -4367,16 +4431,18 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
     {
       if (code == POINTER_TYPE)
        {
-         if (TREE_CODE (inside_init) == STRING_CST
-             || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
-           inside_init = default_function_array_conversion (inside_init);
-
          if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE)
            {
-             error_init ("invalid use of non-lvalue array");
-             return error_mark_node;
+             if (TREE_CODE (inside_init) == STRING_CST
+                 || TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
+               inside_init = array_to_pointer_conversion (inside_init);
+             else
+               {
+                 error_init ("invalid use of non-lvalue array");
+                 return error_mark_node;
+               }
            }
-        }
+       }
 
       if (code == VECTOR_TYPE)
        /* Although the types are compatible, we may require a
@@ -4427,6 +4493,10 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
          inside_init = error_mark_node;
        }
 
+      /* Added to enable additional -Wmissing-format-attribute warnings.  */
+      if (TREE_CODE (TREE_TYPE (inside_init)) == POINTER_TYPE)
+       inside_init = convert_for_assignment (type, inside_init, ic_init, NULL_TREE,
+                                             NULL_TREE, 0);
       return inside_init;
     }
 
@@ -4436,9 +4506,10 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
       || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
       || code == VECTOR_TYPE)
     {
-      if (TREE_CODE (init) == STRING_CST
-         || TREE_CODE (init) == COMPOUND_LITERAL_EXPR)
-       init = default_function_array_conversion (init);
+      if (TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE
+         && (TREE_CODE (init) == STRING_CST
+             || TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
+       init = array_to_pointer_conversion (init);
       inside_init
        = convert_for_assignment (type, init, ic_init,
                                  NULL_TREE, NULL_TREE, 0);
@@ -4505,7 +4576,7 @@ static tree constructor_bit_index;
 /* If we are saving up the elements rather than allocating them,
    this is the list of elements so far (in reverse order,
    most recent first).  */
-static tree constructor_elements;
+static VEC(constructor_elt,gc) *constructor_elements;
 
 /* 1 if constructor should be incrementally stored into a constructor chain,
    0 if all the elements should be kept in AVL tree.  */
@@ -4576,7 +4647,7 @@ struct constructor_stack
   tree unfilled_index;
   tree unfilled_fields;
   tree bit_index;
-  tree elements;
+  VEC(constructor_elt,gc) *elements;
   struct init_node *pending_elts;
   int offset;
   int depth;
@@ -4620,7 +4691,7 @@ struct initializer_stack
   tree decl;
   struct constructor_stack *constructor_stack;
   struct constructor_range_stack *constructor_range_stack;
-  tree elements;
+  VEC(constructor_elt,gc) *elements;
   struct spelling *spelling;
   struct spelling *spelling_base;
   int spelling_size;
@@ -4955,7 +5026,7 @@ push_init_level (int implicit)
       constructor_constant = TREE_CONSTANT (value);
       constructor_simple = TREE_STATIC (value);
       constructor_elements = CONSTRUCTOR_ELTS (value);
-      if (constructor_elements
+      if (!VEC_empty (constructor_elt, constructor_elements)
          && (TREE_CODE (constructor_type) == RECORD_TYPE
              || TREE_CODE (constructor_type) == ARRAY_TYPE))
        set_nonincremental_init ();
@@ -5130,19 +5201,19 @@ pop_init_level (int implicit)
     {
       /* A nonincremental scalar initializer--just return
         the element, after verifying there is just one.  */
-      if (constructor_elements == 0)
+      if (VEC_empty (constructor_elt,constructor_elements))
        {
          if (!constructor_erroneous)
            error_init ("empty scalar initializer");
          ret.value = error_mark_node;
        }
-      else if (TREE_CHAIN (constructor_elements) != 0)
+      else if (VEC_length (constructor_elt,constructor_elements) != 1)
        {
          error_init ("extra elements in scalar initializer");
-         ret.value = TREE_VALUE (constructor_elements);
+         ret.value = VEC_index (constructor_elt,constructor_elements,0)->value;
        }
       else
-       ret.value = TREE_VALUE (constructor_elements);
+       ret.value = VEC_index (constructor_elt,constructor_elements,0)->value;
     }
   else
     {
@@ -5151,7 +5222,7 @@ pop_init_level (int implicit)
       else
        {
          ret.value = build_constructor (constructor_type,
-                                        nreverse (constructor_elements));
+                                        constructor_elements);
          if (constructor_constant)
            TREE_CONSTANT (ret.value) = TREE_INVARIANT (ret.value) = 1;
          if (constructor_constant && constructor_simple)
@@ -5600,14 +5671,15 @@ add_pending_init (tree purpose, tree value)
 static void
 set_nonincremental_init (void)
 {
-  tree chain;
+  unsigned HOST_WIDE_INT ix;
+  tree index, value;
 
   if (TREE_CODE (constructor_type) != RECORD_TYPE
       && TREE_CODE (constructor_type) != ARRAY_TYPE)
     return;
 
-  for (chain = constructor_elements; chain; chain = TREE_CHAIN (chain))
-    add_pending_init (TREE_PURPOSE (chain), TREE_VALUE (chain));
+  FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
+    add_pending_init (index, value);
   constructor_elements = 0;
   if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
@@ -5759,9 +5831,10 @@ find_init_member (tree field)
     }
   else if (TREE_CODE (constructor_type) == UNION_TYPE)
     {
-      if (constructor_elements
-         && TREE_PURPOSE (constructor_elements) == field)
-       return TREE_VALUE (constructor_elements);
+      if (!VEC_empty (constructor_elt, constructor_elements)
+         && (VEC_last (constructor_elt, constructor_elements)->index
+             == field))
+       return VEC_last (constructor_elt, constructor_elements)->value;
     }
   return 0;
 }
@@ -5783,6 +5856,8 @@ static void
 output_init_element (tree value, bool strict_string, tree type, tree field,
                     int pending)
 {
+  constructor_elt *celt;
+
   if (type == error_mark_node || value == error_mark_node)
     {
       constructor_erroneous = 1;
@@ -5796,7 +5871,7 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
           && INTEGRAL_TYPE_P (TREE_TYPE (type)))
       && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
                     TYPE_MAIN_VARIANT (type)))
-    value = default_function_array_conversion (value);
+    value = array_to_pointer_conversion (value);
 
   if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
       && require_constant_value && !flag_isoc99 && pending)
@@ -5887,9 +5962,10 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
       return;
     }
   else if (TREE_CODE (constructor_type) == UNION_TYPE
-          && constructor_elements)
+          && !VEC_empty (constructor_elt, constructor_elements))
     {
-      if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
+      if (TREE_SIDE_EFFECTS (VEC_last (constructor_elt,
+                                      constructor_elements)->value))
        warning_init ("initialized field with side-effects overwritten");
 
       /* We can have just one union field set.  */
@@ -5901,8 +5977,9 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
 
   if (field && TREE_CODE (field) == INTEGER_CST)
     field = copy_node (field);
-  constructor_elements
-    = tree_cons (field, value, constructor_elements);
+  celt = VEC_safe_push (constructor_elt, gc, constructor_elements, NULL);
+  celt->index = field;
+  celt->value = value;
 
   /* Advance the variable that indicates sequential elements output.  */
   if (TREE_CODE (constructor_type) == ARRAY_TYPE)
@@ -8123,3 +8200,24 @@ c_objc_common_truthvalue_conversion (tree expr)
      leaving those to give errors later?  */
   return c_common_truthvalue_conversion (expr);
 }
+\f
+
+/* Convert EXPR to a contained DECL, updating *TC, *TI and *SE as
+   required.  */
+
+tree
+c_expr_to_decl (tree expr, bool *tc ATTRIBUTE_UNUSED,
+               bool *ti ATTRIBUTE_UNUSED, bool *se)
+{
+  if (TREE_CODE (expr) == COMPOUND_LITERAL_EXPR)
+    {
+      tree decl = COMPOUND_LITERAL_EXPR_DECL (expr);
+      /* Executing a compound literal inside a function reinitializes
+        it.  */
+      if (!TREE_STATIC (decl))
+       *se = true;
+      return decl;
+    }
+  else
+    return expr;
+}