OSDN Git Service

(output_toc): Align DF constants if STRICT_ALIGNMENT.
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index f5ff3a5..75df083 100644 (file)
@@ -1,5 +1,5 @@
 /* Build expressions with type checking for C compiler.
-   Copyright (C) 1987, 88, 91, 92, 93, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file is part of the C front end.
@@ -32,6 +33,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tree.h"
 #include "c-tree.h"
 #include "flags.h"
+#include "output.h"
 
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
@@ -208,14 +210,15 @@ common_type (t1, t2)
          attributes = a2;
        else
        {
-         /* Pick the longest list, and hang on the other
-            list.  */
+         /* Pick the longest list, and hang on the other list.  */
+         /* ??? For the moment we punt on the issue of attrs with args.  */
        
          if (list_length (a1) < list_length (a2))
             attributes = a2, a2 = a1;
 
          for (; a2; a2 = TREE_CHAIN (a2))
-            if (!value_member (attributes, a2))
+           if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+                                 attributes) == NULL_TREE)
              {
                a1 = copy_node (a2);
                TREE_CHAIN (a1) = attributes;
@@ -655,7 +658,8 @@ type_lists_compatible_p (args1, args2)
          /* Allow  wait (union {union wait *u; int *i} *)
             and  wait (union wait *)  to be compatible.  */
          if (TREE_CODE (TREE_VALUE (args1)) == UNION_TYPE
-             && TYPE_NAME (TREE_VALUE (args1)) == 0
+             && (TYPE_NAME (TREE_VALUE (args1)) == 0
+                 || TYPE_TRANSPARENT_UNION (TREE_VALUE (args1)))
              && TREE_CODE (TYPE_SIZE (TREE_VALUE (args1))) == INTEGER_CST
              && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args1)),
                                     TYPE_SIZE (TREE_VALUE (args2))))
@@ -669,7 +673,8 @@ type_lists_compatible_p (args1, args2)
                return 0;
            }
          else if (TREE_CODE (TREE_VALUE (args2)) == UNION_TYPE
-                  && TYPE_NAME (TREE_VALUE (args2)) == 0
+                  && (TYPE_NAME (TREE_VALUE (args2)) == 0
+                      || TYPE_TRANSPARENT_UNION (TREE_VALUE (args2)))
                   && TREE_CODE (TYPE_SIZE (TREE_VALUE (args2))) == INTEGER_CST
                   && tree_int_cst_equal (TYPE_SIZE (TREE_VALUE (args2)),
                                          TYPE_SIZE (TREE_VALUE (args1))))
@@ -754,6 +759,14 @@ unsigned_type (type)
     return long_unsigned_type_node;
   if (type1 == long_long_integer_type_node)
     return long_long_unsigned_type_node;
+  if (type1 == intDI_type_node)
+    return unsigned_intDI_type_node;
+  if (type1 == intSI_type_node)
+    return unsigned_intSI_type_node;
+  if (type1 == intHI_type_node)
+    return unsigned_intHI_type_node;
+  if (type1 == intQI_type_node)
+    return unsigned_intQI_type_node;
   return type;
 }
 
@@ -774,6 +787,14 @@ signed_type (type)
     return long_integer_type_node;
   if (type1 == long_long_unsigned_type_node)
     return long_long_integer_type_node;
+  if (type1 == unsigned_intDI_type_node)
+    return intDI_type_node;
+  if (type1 == unsigned_intSI_type_node)
+    return intSI_type_node;
+  if (type1 == unsigned_intHI_type_node)
+    return intHI_type_node;
+  if (type1 == unsigned_intQI_type_node)
+    return intQI_type_node;
   return type;
 }
 
@@ -990,8 +1011,11 @@ default_conversion (exp)
   /* Constants can be used directly unless they're not loadable.  */
   if (TREE_CODE (exp) == CONST_DECL)
     exp = DECL_INITIAL (exp);
-  /* Replace a nonvolatile const static variable with its value.  */
-  else if (optimize && TREE_CODE (exp) == VAR_DECL)
+
+  /* Replace a nonvolatile const static variable with its value unless
+     it is an array, in which case we must be sure that taking the
+     address of the array produces consistent results.  */
+  else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
     {
       exp = decl_constant_value (exp);
       type = TREE_TYPE (exp);
@@ -1130,8 +1154,6 @@ lookup_field (type, component, indirect)
       top = TYPE_LANG_SPECIFIC (type)->len;
       while (top - bot > 1)
        {
-         HOST_WIDE_INT cmp;
-
          half = (top - bot + 1) >> 1;
          field = field_array[bot+half];
 
@@ -1159,10 +1181,9 @@ lookup_field (type, component, indirect)
              continue;
            }
 
-         cmp = (HOST_WIDE_INT) DECL_NAME (field) - (HOST_WIDE_INT) component;
-         if (cmp == 0)
+         if (DECL_NAME (field) == component)
            break;
-         if (cmp < 0)
+         if (DECL_NAME (field) < component)
            bot += half;
          else
            top = bot + half;
@@ -1630,37 +1651,28 @@ convert_arguments (typelist, values, name, fundecl)
            }
          else
            {
-#if 0 /* This turns out not to win--there's no way to write a prototype
-        for a function whose arg type is a union with no tag.  */
-             /* Nameless union automatically casts the types it contains.  */
-             if (TREE_CODE (type) == UNION_TYPE && TYPE_NAME (type) == 0)
-               {
-                 tree field;
-
-                 for (field = TYPE_FIELDS (type); field;
-                      field = TREE_CHAIN (field))
-                   if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
-                                  TYPE_MAIN_VARIANT (TREE_TYPE (val))))
-                     break;
-
-                 if (field)
-                   val = build1 (CONVERT_EXPR, type, val);
-               }
-#endif
-
              /* Optionally warn about conversions that
                 differ from the default conversions.  */
              if (warn_conversion)
                {
                  int formal_prec = TYPE_PRECISION (type);
 
-                 if (TREE_CODE (type) != REAL_TYPE
+                 if (INTEGRAL_TYPE_P (type)
                      && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
                    warn_for_assignment ("%s as integer rather than floating due to prototype", (char *) 0, name, parmnum + 1);
+                 else if (TREE_CODE (type) == COMPLEX_TYPE
+                          && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+                   warn_for_assignment ("%s as complex rather than floating due to prototype", (char *) 0, name, parmnum + 1);
                  else if (TREE_CODE (type) == REAL_TYPE
-                     && TREE_CODE (TREE_TYPE (val)) != REAL_TYPE)
+                          && INTEGRAL_TYPE_P (TREE_TYPE (val)))
                    warn_for_assignment ("%s as floating rather than integer due to prototype", (char *) 0, name, parmnum + 1);
                  else if (TREE_CODE (type) == REAL_TYPE
+                          && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+                   warn_for_assignment ("%s as floating rather than complex due to prototype", (char *) 0, name, parmnum + 1);
+                 /* ??? At some point, messages should be written about
+                    conversions between complex types, but that's too messy
+                    to do now.  */
+                 else if (TREE_CODE (type) == REAL_TYPE
                           && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
                    {
                      /* Warn if any argument is passed as `float',
@@ -1669,10 +1681,8 @@ convert_arguments (typelist, values, name, fundecl)
                        warn_for_assignment ("%s as `float' rather than `double' due to prototype", (char *) 0, name, parmnum + 1);
                    }
                  /* Detect integer changing in width or signedness.  */
-                 else if ((TREE_CODE (type) == INTEGER_TYPE
-                           || TREE_CODE (type) == ENUMERAL_TYPE)
-                          && (TREE_CODE (TREE_TYPE (val)) == INTEGER_TYPE
-                              || TREE_CODE (TREE_TYPE (val)) == ENUMERAL_TYPE))
+                 else if (INTEGRAL_TYPE_P (type)
+                          && INTEGRAL_TYPE_P (TREE_TYPE (val)))
                    {
                      tree would_have_been = default_conversion (val);
                      tree type1 = TREE_TYPE (would_have_been);
@@ -1902,8 +1912,12 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
      Zero means they need to be converted to RESULT_TYPE.  */
   int converted = 0;
 
+  /* Nonzero means create the expression with this type, rather than
+     RESULT_TYPE.  */
+  tree build_type = 0;
+
   /* Nonzero means after finally constructing the expression
-     give it this type.  Otherwise, give it type RESULT_TYPE.  */
+     convert it to this type.  */
   tree final_type = 0;
 
   /* Nonzero if this is an operation like MIN or MAX which can
@@ -2174,8 +2188,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case NE_EXPR:
       /* Result of comparison is always int,
         but don't convert the args to int!  */
-      result_type = integer_type_node;
-      converted = 1;
+      build_type = integer_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
           || code0 == COMPLEX_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
@@ -2189,7 +2202,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
             Otherwise, the targets must be compatible
             and both must be object or both incomplete.  */
          if (comp_target_types (type0, type1))
-           ;
+           result_type = common_type (type0, type1);
          else if (TYPE_MAIN_VARIANT (tt0) == void_type_node)
            {
              /* op0 != orig_op0 detects the case of something
@@ -2206,29 +2219,28 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
            }
          else
            pedwarn ("comparison of distinct pointer types lacks a cast");
+
+         if (result_type == NULL_TREE)
+           result_type = ptr_type_node;
        }
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
-       op1 = null_pointer_node;
+       result_type = type0;
       else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
               && integer_zerop (op0))
-       op0 = null_pointer_node;
+       result_type = type1;
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
+         result_type = type0;
          if (! flag_traditional)
            pedwarn ("comparison between pointer and integer");
-         op1 = convert (TREE_TYPE (op0), op1);
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
+         result_type = type1;
          if (! flag_traditional)
            pedwarn ("comparison between pointer and integer");
-         op0 = convert (TREE_TYPE (op1), op0);
        }
-      else
-       /* If args are not valid, clear out RESULT_TYPE
-          to cause an error message later.  */
-       result_type = 0;
       break;
 
     case MAX_EXPR:
@@ -2238,12 +2250,18 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        shorten = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
-         if (! comp_target_types (type0, type1))
-           pedwarn ("comparison of distinct pointer types lacks a cast");
-         else if (pedantic 
-                  && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-           pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
-         result_type = common_type (type0, type1);
+         if (comp_target_types (type0, type1))
+           {
+             result_type = common_type (type0, type1);
+             if (pedantic 
+                 && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+               pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
+           }
+         else
+           {
+             result_type = ptr_type_node;
+             pedwarn ("comparison of distinct pointer types lacks a cast");
+           }
        }
       break;
 
@@ -2251,52 +2269,54 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
     case GE_EXPR:
     case LT_EXPR:
     case GT_EXPR:
+      build_type = integer_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
          && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
        short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
-         if (! comp_target_types (type0, type1))
-           pedwarn ("comparison of distinct pointer types lacks a cast");
-         else if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
-                  != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
-           pedwarn ("comparison of complete and incomplete pointers");
-         else if (pedantic 
-                  && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-           pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
-         result_type = integer_type_node;
+         if (comp_target_types (type0, type1))
+           {
+             result_type = common_type (type0, type1);
+             if ((TYPE_SIZE (TREE_TYPE (type0)) != 0)
+                 != (TYPE_SIZE (TREE_TYPE (type1)) != 0))
+               pedwarn ("comparison of complete and incomplete pointers");
+             else if (pedantic 
+                      && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+               pedwarn ("ANSI C forbids ordered comparisons of pointers to functions");
+           }
+         else
+           {
+             result_type = ptr_type_node;
+             pedwarn ("comparison of distinct pointer types lacks a cast");
+           }
        }
       else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
               && integer_zerop (op1))
        {
-         result_type = integer_type_node;
-         op1 = null_pointer_node;
-         if (pedantic)
+         result_type = type0;
+         if (pedantic || extra_warnings)
            pedwarn ("ordered comparison of pointer with integer zero");
        }
       else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
               && integer_zerop (op0))
        {
-         result_type = integer_type_node;
-         op0 = null_pointer_node;
+         result_type = type1;
          if (pedantic)
            pedwarn ("ordered comparison of pointer with integer zero");
        }
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
-         result_type = integer_type_node;
+         result_type = type0;
          if (! flag_traditional)
            pedwarn ("comparison between pointer and integer");
-         op1 = convert (TREE_TYPE (op0), op1);
        }
       else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
-         result_type = integer_type_node;
+         result_type = type1;
          if (! flag_traditional)
            pedwarn ("comparison between pointer and integer");
-         op0 = convert (TREE_TYPE (op1), op0);
        }
-      converted = 1;
       break;
     }
 
@@ -2397,6 +2417,10 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
            unsigned_arg = TREE_UNSIGNED (TREE_TYPE (op0));
 
          if (TYPE_PRECISION (TREE_TYPE (arg0)) < TYPE_PRECISION (result_type)
+             /* We can shorten only if the shift count is less than the
+                number of bits in the smaller type size.  */
+             && TREE_INT_CST_HIGH (op1) == 0
+             && TYPE_PRECISION (TREE_TYPE (arg0)) > TREE_INT_CST_LOW (op1)
              /* If arg is sign-extended and then unsigned-shifted,
                 we can simulate this with a signed shift in arg's type
                 only if the extended result is at least twice as wide
@@ -2434,43 +2458,113 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
            = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
          if (val != 0)
            return val;
-         op0 = xop0, op1 = xop1, result_type = xresult_type;
+         op0 = xop0, op1 = xop1;
+         converted = 1;
          resultcode = xresultcode;
 
          if (extra_warnings)
            {
-             tree op0_type = TREE_TYPE (orig_op0);
-             tree op1_type = TREE_TYPE (orig_op1);
-             int op0_unsigned = TREE_UNSIGNED (op0_type);
-             int op1_unsigned = TREE_UNSIGNED (op1_type);
+             int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
+             int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
+
+             int unsignedp0, unsignedp1;
+             tree primop0 = get_narrower (op0, &unsignedp0);
+             tree primop1 = get_narrower (op1, &unsignedp1);
+
+             /* Avoid spurious warnings for comparison with enumerators.  */
  
+             xop0 = orig_op0;
+             xop1 = orig_op1;
+             STRIP_TYPE_NOPS (xop0);
+             STRIP_TYPE_NOPS (xop1);
+
              /* Give warnings for comparisons between signed and unsigned
-                quantities that will fail.  Do not warn if the signed quantity
-                is an unsuffixed integer literal (or some static constant
-                expression involving such literals) and it is positive.
-                Do not warn if the width of the unsigned quantity is less
-                than that of the signed quantity, since in this case all
-                values of the unsigned quantity fit in the signed quantity.
-                Do not warn if the signed type is the same size as the
-                result_type since sign extension does not cause trouble in
-                this case.  */
+                quantities that may fail.  */
              /* Do the checking based on the original operand trees, so that
                 casts will be considered, but default promotions won't be.  */
-             if (op0_unsigned != op1_unsigned
-                 && ((op0_unsigned
-                      && TYPE_PRECISION (op0_type) >= TYPE_PRECISION (op1_type)
-                      && TYPE_PRECISION (op0_type) < TYPE_PRECISION (result_type)
-                      && (TREE_CODE (op1) != INTEGER_CST
-                          || (TREE_CODE (op1) == INTEGER_CST
-                              && INT_CST_LT (op1, integer_zero_node))))
-                     ||
-                     (op1_unsigned
-                      && TYPE_PRECISION (op1_type) >= TYPE_PRECISION (op0_type)
-                      && TYPE_PRECISION (op1_type) < TYPE_PRECISION (result_type)
-                      && (TREE_CODE (op0) != INTEGER_CST
-                          || (TREE_CODE (op0) == INTEGER_CST
-                              && INT_CST_LT (op0, integer_zero_node))))))
+
+             /* Do not warn if the comparison is being done in a signed type,
+                since the signed type will only be chosen if it can represent
+                all the values of the unsigned type.  */
+             if (! TREE_UNSIGNED (result_type))
+               /* OK */;
+              /* Do not warn if both operands are unsigned.  */
+              else if (op0_signed == op1_signed)
+                /* OK */;
+             /* Do not warn if the signed quantity is an unsuffixed
+                integer literal (or some static constant expression
+                involving such literals) and it is non-negative.  */
+             else if ((op0_signed && TREE_CODE (xop0) == INTEGER_CST
+                       && tree_int_cst_sgn (xop0) >= 0)
+                      || (op1_signed && TREE_CODE (xop1) == INTEGER_CST
+                          && tree_int_cst_sgn (xop1) >= 0))
+               /* OK */;
+             /* Do not warn if the comparison is an equality operation,
+                 the unsigned quantity is an integral constant and it does
+                 not use the most significant bit of result_type.  */
+             else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
+                      && ((op0_signed && TREE_CODE (xop1) == INTEGER_CST
+                           && int_fits_type_p (xop1, signed_type (result_type))
+                          || (op1_signed && TREE_CODE (xop0) == INTEGER_CST
+                              && int_fits_type_p (xop0, signed_type (result_type))))))
+               /* OK */;
+             else
                warning ("comparison between signed and unsigned");
+
+             /* Warn if two unsigned values are being compared in a size
+                larger than their original size, and one (and only one) is the
+                result of a `~' operator.  This comparison will always fail.
+
+                Also warn if one operand is a constant, and the constant
+                does not have all bits set that are set in the ~ operand
+                when it is extended.  */
+
+             if ((TREE_CODE (primop0) == BIT_NOT_EXPR)
+                 != (TREE_CODE (primop1) == BIT_NOT_EXPR))
+               {
+                 if (TREE_CODE (primop0) == BIT_NOT_EXPR)
+                   primop0 = get_narrower (TREE_OPERAND (primop0, 0),
+                                           &unsignedp0);
+                 else
+                   primop1 = get_narrower (TREE_OPERAND (primop1, 0),
+                                           &unsignedp1);
+             
+                 if (TREE_CODE (primop0) == INTEGER_CST
+                     || TREE_CODE (primop1) == INTEGER_CST)
+                   {
+                     tree primop;
+                     long constant, mask;
+                     int unsignedp, bits;
+
+                     if (TREE_CODE (primop0) == INTEGER_CST)
+                       {
+                         primop = primop1;
+                         unsignedp = unsignedp1;
+                         constant = TREE_INT_CST_LOW (primop0);
+                       }
+                     else
+                       {
+                         primop = primop0;
+                         unsignedp = unsignedp0;
+                         constant = TREE_INT_CST_LOW (primop1);
+                       }
+
+                     bits = TYPE_PRECISION (TREE_TYPE (primop));
+                     if (bits < TYPE_PRECISION (result_type)
+                         && bits < HOST_BITS_PER_LONG && unsignedp)
+                       {
+                         mask = (~0L) << bits;
+                         if ((mask & constant) != mask)
+                           warning ("comparison of promoted ~unsigned with constant");
+                       }
+                   }
+                 else if (unsignedp0 && unsignedp1
+                          && (TYPE_PRECISION (TREE_TYPE (primop0))
+                              < TYPE_PRECISION (result_type))
+                          && (TYPE_PRECISION (TREE_TYPE (primop1))
+                              < TYPE_PRECISION (result_type)))
+                   warning ("comparison of promoted ~unsigned with unsigned");
+               }
            }
        }
     }
@@ -2495,8 +2589,11 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
        op1 = convert (result_type, op1); 
     }
 
+  if (build_type == NULL_TREE)
+    build_type = result_type;
+
   {
-    register tree result = build (resultcode, result_type, op0, op1);
+    register tree result = build (resultcode, build_type, op0, op1);
     register tree folded;
 
     folded = fold (result);
@@ -2551,7 +2648,13 @@ pointer_int_sum (resultcode, ptrop, intop)
       && TREE_CONSTANT (size_exp)
       /* If the constant comes from pointer subtraction,
         skip this optimization--it would cause an error.  */
-      && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE)
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE
+      /* If the constant is unsigned, and smaller than the pointer size,
+        then we must skip this optimization.  This is because it could cause
+        an overflow error if the constant is negative but INTOP is not.  */
+      && (! TREE_UNSIGNED (TREE_TYPE (intop))
+         || (TYPE_PRECISION (TREE_TYPE (intop))
+             == TYPE_PRECISION (TREE_TYPE (ptrop)))))
     {
       enum tree_code subcode = resultcode;
       tree int_type = TREE_TYPE (intop);
@@ -3211,6 +3314,18 @@ mark_addressable (exp)
                       IDENTIFIER_POINTER (DECL_NAME (x)));
                return 0;
              }
+
+           /* If we are making this addressable due to its having
+              volatile components, give a different error message.  Also
+              handle the case of an unnamed parameter by not trying
+              to give the name.  */
+
+           else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x)))
+             {
+               error ("cannot put object with volatile field into register");
+               return 0;
+             }
+
            pedwarn ("address of register variable `%s' requested",
                     IDENTIFIER_POINTER (DECL_NAME (x)));
          }
@@ -3472,10 +3587,28 @@ internal_build_compound_expr (list, first_p)
 
   rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
 
-  /* When pedantic, a compound expression can be neither an lvalue
-     nor an integer constant expression.  */
-  if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)) && ! pedantic)
-    return rest;
+  if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+    {
+      /* The left-hand operand of a comma expression is like an expression
+         statement: with -W or -Wunused, we should warn if it doesn't have
+        any side-effects, unless it was explicitly cast to (void).  */
+      if ((extra_warnings || warn_unused)
+           && ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR
+                && TREE_TYPE (TREE_VALUE (list)) == void_type_node))
+        warning ("left-hand operand of comma expression has no effect");
+
+      /* When pedantic, a compound expression can be neither an lvalue
+         nor an integer constant expression.  */
+      if (! pedantic)
+        return rest;
+    }
+
+  /* With -Wunused, we should also warn if the left-hand operand does have
+     side-effects, but computes a value which is not used.  For example, in
+     `foo() + bar(), baz()' the result of the `+' operator is not used,
+     so we should issue a warning.  */
+  else if (warn_unused)
+    warn_if_unused_value (TREE_VALUE (list));
 
   return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
 }
@@ -3868,14 +4001,15 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
   /* Arithmetic types all interconvert, and enum is treated like int.  */
   if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == ENUMERAL_TYPE
        || codel == COMPLEX_TYPE)
-       &&
-      (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE
-       || coder == COMPLEX_TYPE))
+      && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == ENUMERAL_TYPE
+         || coder == COMPLEX_TYPE))
     return convert_and_check (type, rhs);
+
   /* Conversion to a union from its member types.  */
   else if (codel == UNION_TYPE)
     {
       tree memb_types;
+
       for (memb_types = TYPE_FIELDS (type); memb_types;
           memb_types = TREE_CHAIN (memb_types))
        {
@@ -3886,6 +4020,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
                pedwarn ("ANSI C prohibits argument conversion to union type");
              return build1 (NOP_EXPR, type, rhs);
            }
+
          else if (coder == POINTER_TYPE
                   && TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE)
            {
@@ -3895,44 +4030,59 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
 
              /* 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.  */
+                Meanwhile, the lhs target must have all the qualifiers of
+                the rhs.  */
              if (TYPE_MAIN_VARIANT (ttl) == void_type_node
                  || TYPE_MAIN_VARIANT (ttr) == void_type_node
                  || comp_target_types (memb_type, rhstype))
                {
-                 /* Const and volatile mean something different for function types,
-                    so the usual warnings are not appropriate.  */
+                 /* Const and volatile mean something different for function
+                    types, so the usual warnings are not appropriate.  */
                  if (TREE_CODE (ttr) != FUNCTION_TYPE
                      || TREE_CODE (ttl) != FUNCTION_TYPE)
                    {
                      if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
                        warn_for_assignment ("%s discards `const' from pointer target type",
-                                            get_spelling (errtype), funname, parmnum);
+                                            get_spelling (errtype), funname,
+                                            parmnum);
                      if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
                        warn_for_assignment ("%s discards `volatile' from pointer target type",
-                                            get_spelling (errtype), funname, parmnum);
+                                            get_spelling (errtype), funname,
+                                            parmnum);
                    }
                  else
                    {
-                     /* Because const and volatile on functions are restrictions
-                        that say the function will not do certain things,
-                        it is okay to use a const or volatile function
-                        where an ordinary one is wanted, but not vice-versa.  */
+                     /* Because const and volatile on functions are
+                        restrictions that say the function will not do
+                        certain things, it is okay to use a const or volatile
+                        function where an ordinary one is wanted, but not
+                        vice-versa.  */
                      if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
                        warn_for_assignment ("%s makes `const *' function pointer from non-const",
-                                            get_spelling (errtype), funname, parmnum);
+                                            get_spelling (errtype), funname,
+                                            parmnum);
                      if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
                        warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
-                                            get_spelling (errtype), funname, parmnum);
+                                            get_spelling (errtype), funname,
+                                            parmnum);
                    }
+
                  if (pedantic
                      && !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
                    pedwarn ("ANSI C prohibits argument conversion to union type");
                  return build1 (NOP_EXPR, type, rhs);
                }
            }
+
+         /* Can convert integer zero to any pointer type.  */
+         else if (TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE
+                  && (integer_zerop (rhs)
+                      || (TREE_CODE (rhs) == NOP_EXPR
+                          && integer_zerop (TREE_OPERAND (rhs, 0)))))
+           return build1 (NOP_EXPR, type, null_pointer_node);
        }
     }
+
   /* Conversions among pointers */
   else if (codel == POINTER_TYPE && coder == POINTER_TYPE)
     {
@@ -3962,7 +4112,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
          /* Const and volatile mean something different for function types,
             so the usual warnings are not appropriate.  */
          else if (TREE_CODE (ttr) != FUNCTION_TYPE
-                  || TREE_CODE (ttl) != FUNCTION_TYPE)
+                  && TREE_CODE (ttl) != FUNCTION_TYPE)
            {
              if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
                warn_for_assignment ("%s discards `const' from pointer target type",
@@ -3981,7 +4131,8 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
                warn_for_assignment ("pointer targets in %s differ in signedness",
                                     get_spelling (errtype), funname, parmnum);
            }
-         else
+         else if (TREE_CODE (ttl) == FUNCTION_TYPE
+                  && TREE_CODE (ttr) == FUNCTION_TYPE)
            {
              /* Because const and volatile on functions are restrictions
                 that say the function will not do certain things,
@@ -4108,7 +4259,8 @@ initializer_constant_valid_p (value, endtype)
   switch (TREE_CODE (value))
     {
     case CONSTRUCTOR:
-      if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+      if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
+          || TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
          && TREE_CONSTANT (value))
        return
          initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
@@ -4742,7 +4894,7 @@ digest_init (type, init, require_constant, constructor_constant)
      and it initializes the first element of x to 0.  */
   if (flag_traditional)
     {
-      tree top = 0, prev = 0;
+      tree top = 0, prev = 0, otype = type;
       while (TREE_CODE (type) == RECORD_TYPE
             || TREE_CODE (type) == ARRAY_TYPE
             || TREE_CODE (type) == QUAL_UNION_TYPE
@@ -4764,11 +4916,17 @@ digest_init (type, init, require_constant, constructor_constant)
              return error_mark_node;
            }
        }
-      TREE_OPERAND (prev, 1)
-       = build_tree_list (NULL_TREE,
-                          digest_init (type, init, require_constant,
-                                       constructor_constant));
-      return top;
+
+      if (otype != type)
+       {
+         TREE_OPERAND (prev, 1)
+           = build_tree_list (NULL_TREE,
+                              digest_init (type, init, require_constant,
+                                           constructor_constant));
+         return top;
+       }
+      else
+       return error_mark_node;
     }
   error_init ("invalid initializer%s", " for `%s'", NULL);
   return error_mark_node;
@@ -4790,7 +4948,7 @@ static tree constructor_fields;
 static tree constructor_index;
 
 /* For an ARRAY_TYPE, this is the end index of the range
-   to intitialize with the next element, or NULL in the ordinary case
+   to initialize with the next element, or NULL in the ordinary case
    where the element is used just once.  */
 static tree constructor_range_end;
 
@@ -5079,7 +5237,7 @@ really_start_incremental_init (type)
       || TREE_CODE (constructor_type) == UNION_TYPE)
     {
       constructor_fields = TYPE_FIELDS (constructor_type);
-      /* Skip any nameless bit fields atthe beginning.  */
+      /* Skip any nameless bit fields at the beginning.  */
       while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
             && DECL_NAME (constructor_fields) == 0)
        constructor_fields = TREE_CHAIN (constructor_fields);
@@ -5155,8 +5313,8 @@ push_init_level (implicit)
 
   /* Structure elements may require alignment.  Do this now
      if necessary for the subaggregate.  */
-  if (constructor_incremental && TREE_CODE (constructor_type) == RECORD_TYPE
-      && constructor_fields)
+  if (constructor_incremental && constructor_type != 0
+      && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields)
     {
       /* Advance to offset of this element.  */
       if (! tree_int_cst_equal (constructor_bit_index,
@@ -5214,6 +5372,7 @@ push_init_level (implicit)
        {
          constructor_type = TREE_TYPE (constructor_fields);
          push_member_name (constructor_fields);
+         constructor_depth++;
          if (constructor_fields != constructor_unfilled_fields)
            constructor_incremental = 0;
        }
@@ -5222,6 +5381,7 @@ push_init_level (implicit)
     {
       constructor_type = TREE_TYPE (constructor_type);
       push_array_bounds (TREE_INT_CST_LOW (constructor_index));
+      constructor_depth++;
       if (! tree_int_cst_equal (constructor_index, constructor_unfilled_index)
          || constructor_range_end != 0)
        constructor_incremental = 0;
@@ -5249,7 +5409,7 @@ push_init_level (implicit)
           || TREE_CODE (constructor_type) == UNION_TYPE)
     {
       constructor_fields = TYPE_FIELDS (constructor_type);
-      /* Skip any nameless bit fields atthe beginning.  */
+      /* Skip any nameless bit fields at the beginning.  */
       while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
             && DECL_NAME (constructor_fields) == 0)
        constructor_fields = TREE_CHAIN (constructor_fields);
@@ -5363,7 +5523,8 @@ pop_init_level (implicit)
          && constructor_incremental)
        {
          constructor = digest_init (constructor_type, constructor,
-                                    0, 0);
+                                    require_constant_value,
+                                    require_constant_elements);
 
          /* If initializing an array of unknown size,
             determine the size now.  */
@@ -5582,6 +5743,11 @@ set_init_label (fieldname)
   tree tail;
   int passed = 0;
 
+  /* Don't die if an entire brace-pair level is superfluous
+     in the containing level.  */
+  if (constructor_type == 0)
+    return;
+
   for (tail = TYPE_FIELDS (constructor_type); tail;
        tail = TREE_CHAIN (tail))
     {
@@ -5635,7 +5801,10 @@ output_init_element (value, type, field, pending)
     constructor_erroneous = 1;
   else if (!TREE_CONSTANT (value))
     constructor_constant = 0;
-  else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
+  else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0
+          || ((TREE_CODE (constructor_type) == RECORD_TYPE
+               || TREE_CODE (constructor_type) == UNION_TYPE)
+              && DECL_BIT_FIELD (field) && TREE_CODE (value) != INTEGER_CST))
     constructor_simple = 0;
 
   if (require_constant_value && ! TREE_CONSTANT (value))
@@ -5695,7 +5864,8 @@ output_init_element (value, type, field, pending)
           constructor_index, which is modified in place.  */
        constructor_pending_elts
          = tree_cons (copy_node (field),
-                      digest_init (type, value, 0, 0),
+                      digest_init (type, value, require_constant_value, 
+                                   require_constant_elements),
                       constructor_pending_elts);
     }
   else if (TREE_CODE (constructor_type) == RECORD_TYPE
@@ -5707,7 +5877,8 @@ output_init_element (value, type, field, pending)
       if (!duplicate)
        constructor_pending_elts
          = tree_cons (field,
-                      digest_init (type, value, 0, 0),
+                      digest_init (type, value, require_constant_value, 
+                                   require_constant_elements),
                       constructor_pending_elts);
     }
   else
@@ -5722,7 +5893,9 @@ output_init_element (value, type, field, pending)
              if (field && TREE_CODE (field) == INTEGER_CST)
                field = copy_node (field);
              constructor_elements
-               = tree_cons (field, digest_init (type, value, 0, 0),
+               = tree_cons (field, digest_init (type, value,
+                                                require_constant_value, 
+                                                require_constant_elements),
                             constructor_elements);
            }
          else
@@ -5743,7 +5916,9 @@ output_init_element (value, type, field, pending)
                      assemble_zeros (next - here);
                    }
                }
-             output_constant (digest_init (type, value, 0, 0),
+             output_constant (digest_init (type, value,
+                                           require_constant_value,
+                                           require_constant_elements),
                               int_size_in_bytes (type));
 
              /* For a record or union,
@@ -6052,7 +6227,7 @@ process_init_element (value)
            }
 
          constructor_fields = TREE_CHAIN (constructor_fields);
-         /* Skip any nameless bit fields atthe beginning.  */
+         /* Skip any nameless bit fields at the beginning.  */
          while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
                 && DECL_NAME (constructor_fields) == 0)
            constructor_fields = TREE_CHAIN (constructor_fields);
@@ -6145,6 +6320,10 @@ process_init_element (value)
              break;
            }
 
+         /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */
+         if (constructor_range_end)
+           value = save_expr (value);
+
          /* Now output the actual element.
             Ordinarily, output once.
             If there is a range, repeat it till we advance past the range.  */
@@ -6201,7 +6380,8 @@ process_init_element (value)
 
   /* If the (lexically) previous elments are not now saved,
      we can discard the storage for them.  */
-  if (constructor_incremental && constructor_pending_elts == 0 && value != 0)
+  if (constructor_incremental && constructor_pending_elts == 0 && value != 0
+      && constructor_stack == 0)
     clear_momentary ();
 }
 \f
@@ -6263,7 +6443,8 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
       else
        {
          tree type = TREE_TYPE (o[i]);
-         if (TYPE_READONLY (type)
+         if (TREE_READONLY (o[i])
+             || TYPE_READONLY (type)
              || ((TREE_CODE (type) == RECORD_TYPE
                   || TREE_CODE (type) == UNION_TYPE)
                  && C_TYPE_FIELDS_READONLY (type)))
@@ -6316,25 +6497,50 @@ c_expand_return (retval)
 
       /* Strip any conversions, additions, and subtractions, and see if
         we are returning the address of a local variable.  Warn if so.  */
-      while (TREE_CODE (inner) == NOP_EXPR
-            || TREE_CODE (inner) == NON_LVALUE_EXPR
-            || TREE_CODE (inner) == CONVERT_EXPR
-            || TREE_CODE (inner) == PLUS_EXPR
-            || TREE_CODE (inner) == MINUS_EXPR)
-       inner = TREE_OPERAND (inner, 0);
-
-      if (TREE_CODE (inner) == ADDR_EXPR)
+      while (1)
        {
-         inner = TREE_OPERAND (inner, 0);
+         switch (TREE_CODE (inner))
+           {
+           case NOP_EXPR:   case NON_LVALUE_EXPR:  case CONVERT_EXPR:
+           case PLUS_EXPR:
+             inner = TREE_OPERAND (inner, 0);
+             continue;
 
-         while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
-           inner = TREE_OPERAND (inner, 0);
+           case MINUS_EXPR:
+             /* If the second operand of the MINUS_EXPR has a pointer
+                type (or is converted from it), this may be valid, so
+                don't give a warning.  */
+             {
+               tree op1 = TREE_OPERAND (inner, 1);
+
+               while (! POINTER_TYPE_P (TREE_TYPE (op1))
+                      && (TREE_CODE (op1) == NOP_EXPR
+                          || TREE_CODE (op1) == NON_LVALUE_EXPR
+                          || TREE_CODE (op1) == CONVERT_EXPR))
+                 op1 = TREE_OPERAND (op1, 0);
+
+               if (POINTER_TYPE_P (TREE_TYPE (op1)))
+                 break;
+
+               inner = TREE_OPERAND (inner, 0);
+               continue;
+             }
+             
+           case ADDR_EXPR:
+             inner = TREE_OPERAND (inner, 0);
+
+             while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
+               inner = TREE_OPERAND (inner, 0);
+
+             if (TREE_CODE (inner) == VAR_DECL
+                 && ! DECL_EXTERNAL (inner)
+                 && ! TREE_STATIC (inner)
+                 && DECL_CONTEXT (inner) == current_function_decl)
+               warning ("function returns address of local variable");
+             break;
+           }
 
-         if (TREE_CODE (inner) == VAR_DECL
-             && ! DECL_EXTERNAL (inner)
-             && ! TREE_STATIC (inner)
-             && DECL_CONTEXT (inner) == current_function_decl)
-           warning ("function returns address of local variable");
+         break;
        }
 
       t = build (MODIFY_EXPR, TREE_TYPE (res), res, t);