OSDN Git Service

* builtins.c, c-aux-info.c, c-common.c, c-cppbuiltin.c, c-decl.c:
[pf3gnuchains/gcc-fork.git] / gcc / c-typeck.c
index a6213e2..9bd63e5 100644 (file)
@@ -1,6 +1,6 @@
 /* Build expressions with type checking for C compiler.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-   1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -35,6 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tm.h"
 #include "rtl.h"
 #include "tree.h"
+#include "langhooks.h"
 #include "c-tree.h"
 #include "tm_p.h"
 #include "flags.h"
@@ -49,42 +50,36 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    message within this initializer.  */
 static int missing_braces_mentioned;
 
-/* 1 if we explained undeclared var errors.  */
-static int undeclared_variable_notice;
-
-static tree qualify_type               PARAMS ((tree, tree));
-static int comp_target_types           PARAMS ((tree, tree, int));
-static int function_types_compatible_p PARAMS ((tree, tree));
-static int type_lists_compatible_p     PARAMS ((tree, tree));
-static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
-static tree default_function_array_conversion  PARAMS ((tree));
-static tree lookup_field               PARAMS ((tree, tree));
-static void undeclared_variable                PARAMS ((tree));
-static tree convert_arguments          PARAMS ((tree, tree, tree, tree));
-static tree pointer_diff               PARAMS ((tree, tree));
-static tree unary_complex_lvalue       PARAMS ((enum tree_code, tree, int));
-static void pedantic_lvalue_warning    PARAMS ((enum tree_code));
-static tree internal_build_compound_expr PARAMS ((tree, int));
-static tree convert_for_assignment     PARAMS ((tree, tree, const char *,
-                                                tree, tree, int));
-static void warn_for_assignment                PARAMS ((const char *, const char *,
-                                                tree, int));
-static tree valid_compound_expr_initializer PARAMS ((tree, tree));
-static void push_string                        PARAMS ((const char *));
-static void push_member_name           PARAMS ((tree));
-static void push_array_bounds          PARAMS ((int));
-static int spelling_length             PARAMS ((void));
-static char *print_spelling            PARAMS ((char *));
-static void warning_init               PARAMS ((const char *));
-static tree digest_init                        PARAMS ((tree, tree, int));
-static void output_init_element                PARAMS ((tree, tree, tree, int));
-static void output_pending_init_elements PARAMS ((int));
-static int set_designator              PARAMS ((int));
-static void push_range_stack           PARAMS ((tree));
-static void add_pending_init           PARAMS ((tree, tree));
-static void set_nonincremental_init    PARAMS ((void));
-static void set_nonincremental_init_from_string        PARAMS ((tree));
-static tree find_init_member           PARAMS ((tree));
+static tree qualify_type (tree, tree);
+static int tagged_types_tu_compatible_p (tree, tree, int);
+static int comp_target_types (tree, tree, int);
+static int function_types_compatible_p (tree, tree, int);
+static int type_lists_compatible_p (tree, tree, int);
+static tree decl_constant_value_for_broken_optimization (tree);
+static tree default_function_array_conversion (tree);
+static tree lookup_field (tree, tree);
+static tree convert_arguments (tree, tree, tree, tree);
+static tree pointer_diff (tree, tree);
+static tree internal_build_compound_expr (tree, int);
+static tree convert_for_assignment (tree, tree, const char *, tree, tree,
+                                   int);
+static void warn_for_assignment (const char *, const char *, tree, int);
+static tree valid_compound_expr_initializer (tree, tree);
+static void push_string (const char *);
+static void push_member_name (tree);
+static void push_array_bounds (int);
+static int spelling_length (void);
+static char *print_spelling (char *);
+static void warning_init (const char *);
+static tree digest_init (tree, tree, int);
+static void output_init_element (tree, tree, tree, int);
+static void output_pending_init_elements (int);
+static int set_designator (int);
+static void push_range_stack (tree);
+static void add_pending_init (tree, tree);
+static void set_nonincremental_init (void);
+static void set_nonincremental_init_from_string (tree);
+static tree find_init_member (tree);
 \f
 /* Do `exp = require_complete_type (exp);' to make sure exp
    does not have an incomplete type.  (That includes void types.)  */
@@ -185,7 +180,7 @@ c_type_promotes_to (tree type)
   if (c_promoting_integer_type_p (type))
     {
       /* Preserve unsignedness if not really getting any wider.  */
-      if (TREE_UNSIGNED (type)
+      if (TYPE_UNSIGNED (type)
           && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
         return unsigned_type_node;
       return integer_type_node;
@@ -230,7 +225,7 @@ common_type (tree t1, tree t2)
     return t1;
 
   /* Merge the attributes.  */
-  attributes = (*targetm.merge_type_attributes) (t1, t2);
+  attributes = targetm.merge_type_attributes (t1, t2);
 
   /* Treat an enum type as the unsigned integer type of the same width.  */
 
@@ -291,7 +286,7 @@ common_type (tree t1, tree t2)
        {
          /* But preserve unsignedness from the other type,
             since long cannot hold all the values of an unsigned int.  */
-         if (TREE_UNSIGNED (t1) || TREE_UNSIGNED (t2))
+         if (TYPE_UNSIGNED (t1) || TYPE_UNSIGNED (t2))
             t1 = long_unsigned_type_node;
          else
             t1 = long_integer_type_node;
@@ -306,7 +301,7 @@ common_type (tree t1, tree t2)
 
       /* Otherwise prefer the unsigned one.  */
 
-      if (TREE_UNSIGNED (t1))
+      if (TYPE_UNSIGNED (t1))
        return build_type_attribute_variant (t1, attributes);
       else
        return build_type_attribute_variant (t2, attributes);
@@ -373,9 +368,9 @@ common_type (tree t1, tree t2)
 
        /* If both args specify argument types, we must merge the two
           lists, argument by argument.  */
-
-       pushlevel (0);
-       declare_parm_level (1);
+       /* Tell global_bindings_p to return false so that variable_size
+          doesn't abort on VLAs in parameter types.  */
+       c_override_global_bindings_to_false = true;
 
        len = list_length (p1);
        newargs = 0;
@@ -410,7 +405,8 @@ common_type (tree t1, tree t2)
                tree memb;
                for (memb = TYPE_FIELDS (TREE_VALUE (p1));
                     memb; memb = TREE_CHAIN (memb))
-                 if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2)))
+                 if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2), 
+                                COMPARE_STRICT))
                    {
                      TREE_VALUE (n) = TREE_VALUE (p2);
                      if (pedantic)
@@ -424,7 +420,8 @@ common_type (tree t1, tree t2)
                tree memb;
                for (memb = TYPE_FIELDS (TREE_VALUE (p2));
                     memb; memb = TREE_CHAIN (memb))
-                 if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1)))
+                 if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1), 
+                                COMPARE_STRICT))
                    {
                      TREE_VALUE (n) = TREE_VALUE (p1);
                      if (pedantic)
@@ -436,8 +433,7 @@ common_type (tree t1, tree t2)
          parm_done: ;
          }
 
-       poplevel (0, 0, 0);
-
+       c_override_global_bindings_to_false = false;
        t1 = build_function_type (valtype, newargs);
        /* ... falls through ...  */
       }
@@ -453,7 +449,7 @@ common_type (tree t1, tree t2)
    but a warning may be needed if you use them together.  */
 
 int
-comptypes (tree type1, tree type2)
+comptypes (tree type1, tree type2, int flags)
 {
   tree t1 = type1;
   tree t2 = type2;
@@ -468,20 +464,22 @@ comptypes (tree type1, tree type2)
   /* If either type is the internal version of sizetype, return the
      language version.  */
   if (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
-      && TYPE_DOMAIN (t1) != 0)
-    t1 = TYPE_DOMAIN (t1);
+      && TYPE_ORIG_SIZE_TYPE (t1))
+    t1 = TYPE_ORIG_SIZE_TYPE (t1);
 
   if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
-      && TYPE_DOMAIN (t2) != 0)
-    t2 = TYPE_DOMAIN (t2);
+      && TYPE_ORIG_SIZE_TYPE (t2))
+    t2 = TYPE_ORIG_SIZE_TYPE (t2);
 
-  /* Treat an enum type as the integer type of the same width and
-     signedness.  */
 
-  if (TREE_CODE (t1) == ENUMERAL_TYPE)
-    t1 = c_common_type_for_size (TYPE_PRECISION (t1), TREE_UNSIGNED (t1));
-  if (TREE_CODE (t2) == ENUMERAL_TYPE)
-    t2 = c_common_type_for_size (TYPE_PRECISION (t2), TREE_UNSIGNED (t2));
+  /* Enumerated types are compatible with integer types, but this is
+     not transitive: two enumerated types in the same translation unit
+     are compatible with each other only if they are the same type.  */
+
+  if (TREE_CODE (t1) == ENUMERAL_TYPE && TREE_CODE (t2) != ENUMERAL_TYPE)
+    t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1));
+  else if (TREE_CODE (t2) == ENUMERAL_TYPE && TREE_CODE (t1) != ENUMERAL_TYPE)
+    t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2));
 
   if (t1 == t2)
     return 1;
@@ -503,7 +501,7 @@ comptypes (tree type1, tree type2)
     return 1;
 
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
-  if (! (attrval = (*targetm.comp_type_attributes) (t1, t2)))
+  if (! (attrval = targetm.comp_type_attributes (t1, t2)))
      return 0;
 
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
@@ -512,12 +510,16 @@ comptypes (tree type1, tree type2)
   switch (TREE_CODE (t1))
     {
     case POINTER_TYPE:
+      /* We must give ObjC the first crack at comparing pointers, since
+          protocol qualifiers may be involved.  */
+      if (c_dialect_objc () && (val = objc_comptypes (t1, t2, 0)) >= 0)
+       break;
       val = (TREE_TYPE (t1) == TREE_TYPE (t2)
-             ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
+            ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2), flags));
       break;
 
     case FUNCTION_TYPE:
-      val = function_types_compatible_p (t1, t2);
+      val = function_types_compatible_p (t1, t2, flags);
       break;
 
     case ARRAY_TYPE:
@@ -530,7 +532,8 @@ comptypes (tree type1, tree type2)
 
        /* Target types must match incl. qualifiers.  */
        if (TREE_TYPE (t1) != TREE_TYPE (t2)
-           && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2))))
+           && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2),
+                                     flags)))
          return 0;
 
        /* Sizes must match unless one is missing or variable.  */
@@ -560,14 +563,22 @@ comptypes (tree type1, tree type2)
       }
 
     case RECORD_TYPE:
+      /* We are dealing with two distinct structs.  In assorted Objective-C
+        corner cases, however, these can still be deemed equivalent.  */
       if (c_dialect_objc () && objc_comptypes (t1, t2, 0) == 1)
        val = 1;
+
+    case ENUMERAL_TYPE:
+    case UNION_TYPE:
+      if (val != 1 && !same_translation_unit_p (t1, t2))
+       val = tagged_types_tu_compatible_p (t1, t2, flags);
       break;
 
     case VECTOR_TYPE:
       /* The target might allow certain vector types to be compatible.  */
-      val = (*targetm.vector_opaque_p) (t1)
-       || (*targetm.vector_opaque_p) (t2);
+      val = targetm.vector_opaque_p (t1)
+       || targetm.vector_opaque_p (t2)
+       || TYPE_MODE (t1) == TYPE_MODE (t2);
       break;
 
     default:
@@ -593,7 +604,7 @@ comp_target_types (tree ttl, tree ttr, int reflexive)
     return val;
 
   val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
-                  TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+                  TYPE_MAIN_VARIANT (TREE_TYPE (ttr)), COMPARE_STRICT);
 
   if (val == 2 && pedantic)
     pedwarn ("types are not quite compatible");
@@ -602,6 +613,212 @@ comp_target_types (tree ttl, tree ttr, int reflexive)
 \f
 /* Subroutines of `comptypes'.  */
 
+/* Determine whether two trees derive from the same translation unit.
+   If the CONTEXT chain ends in a null, that tree's context is still
+   being parsed, so if two trees have context chains ending in null,
+   they're in the same translation unit.  */
+int
+same_translation_unit_p (tree t1, tree t2)
+{
+  while (t1 && TREE_CODE (t1) != TRANSLATION_UNIT_DECL)
+    switch (TREE_CODE_CLASS (TREE_CODE (t1)))
+      {
+      case 'd': t1 = DECL_CONTEXT (t1); break;
+      case 't': t1 = TYPE_CONTEXT (t1); break;
+      case 'b': t1 = BLOCK_SUPERCONTEXT (t1); break;
+      default: abort ();
+      }
+
+  while (t2 && TREE_CODE (t2) != TRANSLATION_UNIT_DECL)
+    switch (TREE_CODE_CLASS (TREE_CODE (t2)))
+      {
+      case 'd': t2 = DECL_CONTEXT (t2); break;
+      case 't': t2 = TYPE_CONTEXT (t2); break;
+      case 'b': t2 = BLOCK_SUPERCONTEXT (t2); break;
+      default: abort ();
+      }
+
+  return t1 == t2;
+}
+
+/* The C standard says that two structures in different translation
+   units are compatible with each other only if the types of their
+   fields are compatible (among other things).  So, consider two copies
+   of this structure:  */
+
+struct tagged_tu_seen {
+  const struct tagged_tu_seen * next;
+  tree t1;
+  tree t2;
+};
+
+/* Can they be compatible with each other?  We choose to break the
+   recursion by allowing those types to be compatible.  */
+
+static const struct tagged_tu_seen * tagged_tu_seen_base;
+
+/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are
+   compatible.  If the two types are not the same (which has been
+   checked earlier), this can only happen when multiple translation
+   units are being compiled.  See C99 6.2.7 paragraph 1 for the exact
+   rules.  */
+
+static int
+tagged_types_tu_compatible_p (tree t1, tree t2, int flags)
+{
+  tree s1, s2;
+  bool needs_warning = false;
+  
+  /* We have to verify that the tags of the types are the same.  This
+     is harder than it looks because this may be a typedef, so we have
+     to go look at the original type.  It may even be a typedef of a
+     typedef...  */
+  while (TYPE_NAME (t1)
+        && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL
+        && DECL_ORIGINAL_TYPE (TYPE_NAME (t1)))
+    t1 = DECL_ORIGINAL_TYPE (TYPE_NAME (t1));
+
+  while (TYPE_NAME (t2)
+        && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL
+        && DECL_ORIGINAL_TYPE (TYPE_NAME (t2)))
+    t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2));
+
+  /* C90 didn't have the requirement that the two tags be the same.  */
+  if (flag_isoc99 && TYPE_NAME (t1) != TYPE_NAME (t2))
+    return 0;
+  
+  /* C90 didn't say what happened if one or both of the types were
+     incomplete; we choose to follow C99 rules here, which is that they
+     are compatible.  */
+  if (TYPE_SIZE (t1) == NULL
+      || TYPE_SIZE (t2) == NULL)
+    return 1;
+  
+  {
+    const struct tagged_tu_seen * tts_i;
+    for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next)
+      if (tts_i->t1 == t1 && tts_i->t2 == t2)
+       return 1;
+  }
+  
+  switch (TREE_CODE (t1))
+    {
+    case ENUMERAL_TYPE:
+      {
+      
+        /* Speed up the case where the type values are in the same order.  */
+        tree tv1 = TYPE_VALUES (t1);
+        tree tv2 = TYPE_VALUES (t2);
+        
+        if (tv1 == tv2)
+          return 1;
+        
+        for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2))
+          {
+            if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2))
+              break;
+            if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1)
+              return 0;
+          }
+        
+        if (tv1 == NULL_TREE && tv2 == NULL_TREE)
+          return 1;
+        if (tv1 == NULL_TREE || tv2 == NULL_TREE)
+          return 0;
+        
+       if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2)))
+         return 0;
+       
+       for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1))
+         {
+           s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2));
+           if (s2 == NULL
+               || simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1)
+             return 0;
+         }
+       return 1;
+      }
+
+    case UNION_TYPE:
+      {
+       if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
+         return 0;
+
+       for (s1 = TYPE_FIELDS (t1); s1; s1 = TREE_CHAIN (s1))
+         {
+           bool ok = false;
+           struct tagged_tu_seen tts;
+
+           tts.next = tagged_tu_seen_base;
+           tts.t1 = t1;
+           tts.t2 = t2;
+           tagged_tu_seen_base = &tts;
+       
+           if (DECL_NAME (s1) != NULL)
+             for (s2 = TYPE_VALUES (t2); s2; s2 = TREE_CHAIN (s2))
+               if (DECL_NAME (s1) == DECL_NAME (s2))
+                 {
+                   int result;
+                   result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2), flags);
+                   if (result == 0)
+                     break;
+                   if (result == 2)
+                     needs_warning = true;
+                   
+                   if (TREE_CODE (s1) == FIELD_DECL
+                       && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
+                                            DECL_FIELD_BIT_OFFSET (s2)) != 1)
+                     break;
+
+                   ok = true;
+                   break;
+                 }
+           tagged_tu_seen_base = tts.next;
+           if (! ok)
+             return 0;
+         }
+       return needs_warning ? 2 : 1;
+      }
+
+    case RECORD_TYPE:
+      {
+       struct tagged_tu_seen tts;
+       
+       tts.next = tagged_tu_seen_base;
+       tts.t1 = t1;
+       tts.t2 = t2;
+       tagged_tu_seen_base = &tts;
+         
+       for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); 
+            s1 && s2;
+            s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
+         {
+           int result;
+           if (TREE_CODE (s1) != TREE_CODE (s2)
+               || DECL_NAME (s1) != DECL_NAME (s2))
+             break;
+           result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2), flags);
+           if (result == 0)
+             break;
+           if (result == 2)
+             needs_warning = true;
+           
+           if (TREE_CODE (s1) == FIELD_DECL
+               && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
+                                    DECL_FIELD_BIT_OFFSET (s2)) != 1)
+             break;
+         }
+       tagged_tu_seen_base = tts.next;
+       if (s1 && s2)
+         return 0;
+       return needs_warning ? 2 : 1;
+      }
+
+    default:
+      abort ();
+    }
+}
+
 /* Return 1 if two function types F1 and F2 are compatible.
    If either type specifies no argument types,
    the other must specify a fixed number of self-promoting arg types.
@@ -610,7 +827,7 @@ comp_target_types (tree ttl, tree ttr, int reflexive)
    Otherwise, the argument types must match.  */
 
 static int
-function_types_compatible_p (tree f1, tree f2)
+function_types_compatible_p (tree f1, tree f2, int flags)
 {
   tree args1, args2;
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
@@ -631,7 +848,7 @@ function_types_compatible_p (tree f1, tree f2)
   if (TYPE_VOLATILE (ret2))
     ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
                                 TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
-  val = comptypes (ret1, ret2);
+  val = comptypes (ret1, ret2, flags);
   if (val == 0)
     return 0;
 
@@ -649,7 +866,8 @@ function_types_compatible_p (tree f1, tree f2)
         compare that with the other type's arglist.
         If they don't match, ask for a warning (but no error).  */
       if (TYPE_ACTUAL_ARG_TYPES (f1)
-         && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1)))
+         && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1),
+                                          flags))
        val = 2;
       return val;
     }
@@ -658,13 +876,14 @@ function_types_compatible_p (tree f1, tree f2)
       if (!self_promoting_args_p (args1))
        return 0;
       if (TYPE_ACTUAL_ARG_TYPES (f2)
-         && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2)))
+         && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
+                                          flags))
        val = 2;
       return val;
     }
 
   /* Both types have argument lists: compare them and propagate results.  */
-  val1 = type_lists_compatible_p (args1, args2);
+  val1 = type_lists_compatible_p (args1, args2, flags);
   return val1 != 1 ? val1 : val;
 }
 
@@ -673,7 +892,7 @@ function_types_compatible_p (tree f1, tree f2)
    or 2 for compatible with warning.  */
 
 static int
-type_lists_compatible_p (tree args1, tree args2)
+type_lists_compatible_p (tree args1, tree args2, int flags)
 {
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
   int val = 1;
@@ -701,8 +920,13 @@ type_lists_compatible_p (tree args1, tree args2)
          if (c_type_promotes_to (TREE_VALUE (args1)) != TREE_VALUE (args1))
            return 0;
        }
+      /* If one of the lists has an error marker, ignore this arg.  */
+      else if (TREE_CODE (TREE_VALUE (args1)) == ERROR_MARK
+              || TREE_CODE (TREE_VALUE (args2)) == ERROR_MARK)
+       ;
       else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)),
-                                     TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
+                                     TYPE_MAIN_VARIANT (TREE_VALUE (args2)),
+                                     flags)))
        {
          /* Allow  wait (union {union wait *u; int *i} *)
             and  wait (union wait *)  to be compatible.  */
@@ -716,7 +940,8 @@ type_lists_compatible_p (tree args1, tree args2)
              tree memb;
              for (memb = TYPE_FIELDS (TREE_VALUE (args1));
                   memb; memb = TREE_CHAIN (memb))
-               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2)))
+               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2),
+                              flags))
                  break;
              if (memb == 0)
                return 0;
@@ -731,7 +956,8 @@ type_lists_compatible_p (tree args1, tree args2)
              tree memb;
              for (memb = TYPE_FIELDS (TREE_VALUE (args2));
                   memb; memb = TREE_CHAIN (memb))
-               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1)))
+               if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1),
+                              flags))
                  break;
              if (memb == 0)
                return 0;
@@ -963,7 +1189,7 @@ default_conversion (tree exp)
                                          TYPE_PRECISION (integer_type_node)),
                                     ((TYPE_PRECISION (type)
                                       >= TYPE_PRECISION (integer_type_node))
-                                     && TREE_UNSIGNED (type)));
+                                     && TYPE_UNSIGNED (type)));
 
       return convert (type, exp);
     }
@@ -979,7 +1205,7 @@ default_conversion (tree exp)
   if (c_promoting_integer_type_p (type))
     {
       /* Preserve unsignedness if not really getting any wider.  */
-      if (TREE_UNSIGNED (type)
+      if (TYPE_UNSIGNED (type)
          && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
        return convert (unsigned_type_node, exp);
 
@@ -1017,11 +1243,11 @@ lookup_field (tree decl, tree component)
   if (TYPE_LANG_SPECIFIC (type))
     {
       int bot, top, half;
-      tree *field_array = &TYPE_LANG_SPECIFIC (type)->elts[0];
+      tree *field_array = &TYPE_LANG_SPECIFIC (type)->s->elts[0];
 
       field = TYPE_FIELDS (type);
       bot = 0;
-      top = TYPE_LANG_SPECIFIC (type)->len;
+      top = TYPE_LANG_SPECIFIC (type)->s->len;
       while (top - bot > 1)
        {
          half = (top - bot + 1) >> 1;
@@ -1101,7 +1327,7 @@ build_component_ref (tree datum, tree component)
   tree ref;
 
   /* If DATUM is a COMPOUND_EXPR, move our reference inside it.
-     If pedantic ensure that the arguments are not lvalues; otherwise,
+     Ensure that the arguments are not lvalues; otherwise,
      if the component is an array, it would wrongly decay to a pointer in
      C89 mode.
      We cannot do this with a COND_EXPR, because in a conditional expression
@@ -1114,7 +1340,7 @@ build_component_ref (tree datum, tree component)
       {
        tree value = build_component_ref (TREE_OPERAND (datum, 1), component);
        return build (COMPOUND_EXPR, TREE_TYPE (value),
-                     TREE_OPERAND (datum, 0), pedantic_non_lvalue (value));
+                     TREE_OPERAND (datum, 0), non_lvalue (value));
       }
     default:
       break;
@@ -1287,8 +1513,8 @@ build_array_ref (tree array, tree index)
         would get a crash in store_bit_field/extract_bit_field when trying
         to access a non-existent part of the register.  */
       if (TREE_CODE (index) == INTEGER_CST
-         && TYPE_VALUES (TREE_TYPE (array))
-         && ! int_fits_type_p (index, TYPE_VALUES (TREE_TYPE (array))))
+         && TYPE_DOMAIN (TREE_TYPE (array))
+         && ! int_fits_type_p (index, TYPE_DOMAIN (TREE_TYPE (array))))
        {
          if (!c_mark_addressable (array))
            return error_mark_node;
@@ -1299,7 +1525,7 @@ build_array_ref (tree array, tree index)
          tree foo = array;
          while (TREE_CODE (foo) == COMPONENT_REF)
            foo = TREE_OPERAND (foo, 0);
-         if (TREE_CODE (foo) == VAR_DECL && DECL_REGISTER (foo))
+         if (TREE_CODE (foo) == VAR_DECL && C_DECL_REGISTER (foo))
            pedwarn ("ISO C forbids subscripting `register' array");
          else if (! flag_isoc99 && ! lvalue_p (foo))
            pedwarn ("ISO C90 forbids subscripting non-lvalue array");
@@ -1365,37 +1591,6 @@ build_array_ref (tree array, tree index)
   }
 }
 \f
-/* Issue an error message for a reference to an undeclared variable ID,
-   including a reference to a builtin outside of function-call context.
-   Arrange to suppress further errors for the same identifier.  */
-static void
-undeclared_variable (tree id)
-{
-  if (current_function_decl == 0)
-    {
-      error ("`%s' undeclared here (not in a function)",
-            IDENTIFIER_POINTER (id));
-      IDENTIFIER_SYMBOL_VALUE (id) = error_mark_node;
-    }
-  else
-    {
-      error ("`%s' undeclared (first use in this function)",
-            IDENTIFIER_POINTER (id));
-
-      if (! undeclared_variable_notice)
-       {
-         error ("(Each undeclared identifier is reported only once");
-         error ("for each function it appears in.)");
-         undeclared_variable_notice = 1;
-       }
-
-      /* Set IDENTIFIER_SYMBOL_VALUE (id) to error_mark_node
-        at function scope.  This suppresses further warnings
-        about this undeclared identifier in this function.  */
-      pushdecl_function_level (error_mark_node, id);
-    }
-}
-
 /* Build an external reference to identifier ID.  FUN indicates
    whether this will be used for a function call.  */
 tree
@@ -1410,7 +1605,7 @@ build_external_ref (tree id, int fun)
       /* Properly declared variable or function reference.  */
       if (!objc_ivar)
        ref = decl;
-      else if (decl != objc_ivar && DECL_CONTEXT (decl) != 0)
+      else if (decl != objc_ivar && !DECL_FILE_SCOPE_P (decl))
        {
          warning ("local declaration of `%s' hides instance variable",
                   IDENTIFIER_POINTER (id));
@@ -1450,7 +1645,7 @@ build_external_ref (tree id, int fun)
       TREE_CONSTANT (ref) = 1;
     }
   else if (current_function_decl != 0
-          && DECL_CONTEXT (current_function_decl) != 0
+          && !DECL_FILE_SCOPE_P (current_function_decl)
           && (TREE_CODE (ref) == VAR_DECL
               || TREE_CODE (ref) == PARM_DECL
               || TREE_CODE (ref) == FUNCTION_DECL))
@@ -1475,6 +1670,7 @@ build_function_call (tree function, tree params)
   tree fntype, fundecl = 0;
   tree coerced_params;
   tree name = NULL_TREE, result;
+  tree tem;
 
   /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
   STRIP_TYPE_NOPS (function);
@@ -1514,6 +1710,51 @@ build_function_call (tree function, tree params)
   /* fntype now gets the type of function pointed to.  */
   fntype = TREE_TYPE (fntype);
 
+  /* Check that the function is called through a compatible prototype.
+     If it is not, replace the call by a trap, wrapped up in a compound
+     expression if necessary.  This has the nice side-effect to prevent
+     the tree-inliner from generating invalid assignment trees which may
+     blow up in the RTL expander later.
+
+     ??? This doesn't work for Objective-C because objc_comptypes
+     refuses to compare function prototypes, yet the compiler appears
+     to build calls that are flagged as invalid by C's comptypes.  */
+  if (! c_dialect_objc ()
+      && TREE_CODE (function) == NOP_EXPR
+      && TREE_CODE (tem = TREE_OPERAND (function, 0)) == ADDR_EXPR
+      && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
+      && ! comptypes (fntype, TREE_TYPE (tem), COMPARE_STRICT))
+    {
+      tree return_type = TREE_TYPE (fntype);
+      tree trap = build_function_call (built_in_decls[BUILT_IN_TRAP],
+                                      NULL_TREE);
+
+      /* This situation leads to run-time undefined behavior.  We can't,
+        therefore, simply error unless we can prove that all possible
+        executions of the program must execute the code.  */
+      warning ("function called through a non-compatible type");
+
+      /* We can, however, treat "undefined" any way we please.
+        Call abort to encourage the user to fix the program.  */
+      inform ("if this code is reached, the program will abort");
+
+      if (VOID_TYPE_P (return_type))
+       return trap;
+      else
+       {
+         tree rhs;
+
+         if (AGGREGATE_TYPE_P (return_type))
+           rhs = build_compound_literal (return_type,
+                                         build_constructor (return_type,
+                                                            NULL_TREE));
+         else
+           rhs = fold (build1 (NOP_EXPR, return_type, integer_zero_node));
+
+         return build (COMPOUND_EXPR, return_type, trap, rhs);
+       }
+    }
+
   /* Convert the parameters to the types declared in the
      function prototype, or apply default promotions.  */
 
@@ -1667,7 +1908,7 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                        ;
                      else if (formal_prec != TYPE_PRECISION (type1))
                        warn_for_assignment ("%s with different width due to prototype", (char *) 0, name, parmnum + 1);
-                     else if (TREE_UNSIGNED (type) == TREE_UNSIGNED (type1))
+                     else if (TYPE_UNSIGNED (type) == TYPE_UNSIGNED (type1))
                        ;
                      /* Don't complain if the formal parameter type
                         is an enum, because we can't tell now whether
@@ -1689,9 +1930,9 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                         pass it as signed or unsigned; the value
                         certainly is the same either way.  */
                      else if (TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type)
-                              && TREE_UNSIGNED (TREE_TYPE (val)))
+                              && TYPE_UNSIGNED (TREE_TYPE (val)))
                        ;
-                     else if (TREE_UNSIGNED (type))
+                     else if (TYPE_UNSIGNED (type))
                        warn_for_assignment ("%s as unsigned due to prototype", (char *) 0, name, parmnum + 1);
                      else
                        warn_for_assignment ("%s as signed due to prototype", (char *) 0, name, parmnum + 1);
@@ -1702,7 +1943,7 @@ convert_arguments (tree typelist, tree values, tree name, tree fundecl)
                                                (char *) 0, /* arg passing  */
                                                fundecl, name, parmnum + 1);
 
-             if (PROMOTE_PROTOTYPES
+             if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
                  && INTEGRAL_TYPE_P (type)
                  && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
                parmval = default_conversion (parmval);
@@ -1842,1002 +2083,266 @@ parser_build_binary_op (enum tree_code code, tree arg1, tree arg2)
 
   return result;
 }
+\f
 
-/* Build a binary-operation expression without default conversions.
-   CODE is the kind of expression to build.
-   This function differs from `build' in several ways:
-   the data type of the result is computed and recorded in it,
-   warnings are generated if arg data types are invalid,
-   special handling for addition and subtraction of pointers is known,
-   and some optimization is done (operations on narrow ints
-   are done in the narrower type when that gives the same result).
-   Constant folding is also done before the result is returned.
-
-   Note that the operands will never have enumeral types, or function
-   or array types, because either they will have the default conversions
-   performed or they have both just been converted to some other type in which
-   the arithmetic is to be done.  */
+/* Return true if `t' is known to be non-negative.  */
 
-tree
-build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, int convert_p)
+int
+c_tree_expr_nonnegative_p (tree t)
 {
-  tree type0, type1;
-  enum tree_code code0, code1;
-  tree op0, op1;
-
-  /* Expression code to give to the expression when it is built.
-     Normally this is CODE, which is what the caller asked for,
-     but in some special cases we change it.  */
-  enum tree_code resultcode = code;
-
-  /* Data type in which the computation is to be performed.
-     In the simplest cases this is the common type of the arguments.  */
-  tree result_type = NULL;
+  if (TREE_CODE (t) == STMT_EXPR)
+    {
+      t = COMPOUND_BODY (STMT_EXPR_STMT (t));
 
-  /* Nonzero means operands have already been type-converted
-     in whatever way is necessary.
-     Zero means they need to be converted to RESULT_TYPE.  */
-  int converted = 0;
+      /* Find the last statement in the chain, ignoring the final
+            * scope statement */
+      while (TREE_CHAIN (t) != NULL_TREE
+             && TREE_CODE (TREE_CHAIN (t)) != SCOPE_STMT)
+        t = TREE_CHAIN (t);
+      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+    }
+  return tree_expr_nonnegative_p (t);
+}
 
-  /* Nonzero means create the expression with this type, rather than
-     RESULT_TYPE.  */
-  tree build_type = 0;
+/* Return a tree for the difference of pointers OP0 and OP1.
+   The resulting tree has type int.  */
 
-  /* Nonzero means after finally constructing the expression
-     convert it to this type.  */
-  tree final_type = 0;
+static tree
+pointer_diff (tree op0, tree op1)
+{
+  tree result, folded;
+  tree restype = ptrdiff_type_node;
 
-  /* Nonzero if this is an operation like MIN or MAX which can
-     safely be computed in short if both args are promoted shorts.
-     Also implies COMMON.
-     -1 indicates a bitwise operation; this makes a difference
-     in the exact conditions for when it is safe to do the operation
-     in a narrower mode.  */
-  int shorten = 0;
+  tree target_type = TREE_TYPE (TREE_TYPE (op0));
+  tree con0, con1, lit0, lit1;
+  tree orig_op1 = op1;
 
-  /* Nonzero if this is a comparison operation;
-     if both args are promoted shorts, compare the original shorts.
-     Also implies COMMON.  */
-  int short_compare = 0;
+  if (pedantic || warn_pointer_arith)
+    {
+      if (TREE_CODE (target_type) == VOID_TYPE)
+       pedwarn ("pointer of type `void *' used in subtraction");
+      if (TREE_CODE (target_type) == FUNCTION_TYPE)
+       pedwarn ("pointer to a function used in subtraction");
+    }
 
-  /* Nonzero if this is a right-shift operation, which can be computed on the
-     original short and then promoted if the operand is a promoted short.  */
-  int short_shift = 0;
+  /* If the conversion to ptrdiff_type does anything like widening or
+     converting a partial to an integral mode, we get a convert_expression
+     that is in the way to do any simplifications.
+     (fold-const.c doesn't know that the extra bits won't be needed.
+     split_tree uses STRIP_SIGN_NOPS, which leaves conversions to a
+     different mode in place.)
+     So first try to find a common term here 'by hand'; we want to cover
+     at least the cases that occur in legal static initializers.  */
+  con0 = TREE_CODE (op0) == NOP_EXPR ? TREE_OPERAND (op0, 0) : op0;
+  con1 = TREE_CODE (op1) == NOP_EXPR ? TREE_OPERAND (op1, 0) : op1;
 
-  /* Nonzero means set RESULT_TYPE to the common type of the args.  */
-  int common = 0;
+  if (TREE_CODE (con0) == PLUS_EXPR)
+    {
+      lit0 = TREE_OPERAND (con0, 1);
+      con0 = TREE_OPERAND (con0, 0);
+    }
+  else
+    lit0 = integer_zero_node;
 
-  if (convert_p)
+  if (TREE_CODE (con1) == PLUS_EXPR)
     {
-      op0 = default_conversion (orig_op0);
-      op1 = default_conversion (orig_op1);
+      lit1 = TREE_OPERAND (con1, 1);
+      con1 = TREE_OPERAND (con1, 0);
     }
   else
+    lit1 = integer_zero_node;
+
+  if (operand_equal_p (con0, con1, 0))
     {
-      op0 = orig_op0;
-      op1 = orig_op1;
+      op0 = lit0;
+      op1 = lit1;
     }
 
-  type0 = TREE_TYPE (op0);
-  type1 = TREE_TYPE (op1);
 
-  /* The expression codes of the data types of the arguments tell us
-     whether the arguments are integers, floating, pointers, etc.  */
-  code0 = TREE_CODE (type0);
-  code1 = TREE_CODE (type1);
+  /* First do the subtraction as integers;
+     then drop through to build the divide operator.
+     Do not do default conversions on the minus operator
+     in case restype is a short type.  */
 
-  /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
-  STRIP_TYPE_NOPS (op0);
-  STRIP_TYPE_NOPS (op1);
+  op0 = build_binary_op (MINUS_EXPR, convert (restype, op0),
+                        convert (restype, op1), 0);
+  /* This generates an error if op1 is pointer to incomplete type.  */
+  if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
+    error ("arithmetic on pointer to an incomplete type");
 
-  /* If an error was already reported for one of the arguments,
-     avoid reporting another error.  */
+  /* This generates an error if op0 is pointer to incomplete type.  */
+  op1 = c_size_in_bytes (target_type);
 
-  if (code0 == ERROR_MARK || code1 == ERROR_MARK)
+  /* Divide by the size, in easiest possible way.  */
+
+  result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
+
+  folded = fold (result);
+  if (folded == result)
+    TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
+  return folded;
+}
+\f
+/* Construct and perhaps optimize a tree representation
+   for a unary operation.  CODE, a tree_code, specifies the operation
+   and XARG is the operand.
+   For any CODE other than ADDR_EXPR, FLAG nonzero suppresses
+   the default promotions (such as from short to int).
+   For ADDR_EXPR, the default promotions are not applied; FLAG nonzero
+   allows non-lvalues; this is only used to handle conversion of non-lvalue
+   arrays to pointers in C99.  */
+
+tree
+build_unary_op (enum tree_code code, tree xarg, int flag)
+{
+  /* No default_conversion here.  It causes trouble for ADDR_EXPR.  */
+  tree arg = xarg;
+  tree argtype = 0;
+  enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
+  tree val;
+  int noconvert = flag;
+
+  if (typecode == ERROR_MARK)
     return error_mark_node;
+  if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
+    typecode = INTEGER_TYPE;
 
   switch (code)
     {
-    case PLUS_EXPR:
-      /* Handle the pointer + int case.  */
-      if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       return pointer_int_sum (PLUS_EXPR, op0, op1);
-      else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
-       return pointer_int_sum (PLUS_EXPR, op1, op0);
-      else
-       common = 1;
-      break;
-
-    case MINUS_EXPR:
-      /* Subtraction of two similar pointers.
-        We must subtract them as integers, then divide by object size.  */
-      if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
-         && comp_target_types (type0, type1, 1))
-       return pointer_diff (op0, op1);
-      /* Handle pointer minus int.  Just like pointer plus int.  */
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       return pointer_int_sum (MINUS_EXPR, op0, op1);
-      else
-       common = 1;
+    case CONVERT_EXPR:
+      /* This is used for unary plus, because a CONVERT_EXPR
+        is enough to prevent anybody from looking inside for
+        associativity, but won't generate any code.  */
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
+           || typecode == COMPLEX_TYPE))
+       {
+         error ("wrong type argument to unary plus");
+         return error_mark_node;
+       }
+      else if (!noconvert)
+       arg = default_conversion (arg);
+      arg = non_lvalue (arg);
       break;
 
-    case MULT_EXPR:
-      common = 1;
+    case NEGATE_EXPR:
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
+           || typecode == COMPLEX_TYPE
+           || typecode == VECTOR_TYPE))
+       {
+         error ("wrong type argument to unary minus");
+         return error_mark_node;
+       }
+      else if (!noconvert)
+       arg = default_conversion (arg);
       break;
 
-    case TRUNC_DIV_EXPR:
-    case CEIL_DIV_EXPR:
-    case FLOOR_DIV_EXPR:
-    case ROUND_DIV_EXPR:
-    case EXACT_DIV_EXPR:
-      /* Floating point division by zero is a legitimate way to obtain
-        infinities and NaNs.  */
-      if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
-       warning ("division by zero");
-
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-          || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-             || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
+    case BIT_NOT_EXPR:
+      if (typecode == INTEGER_TYPE || typecode == VECTOR_TYPE)
        {
-         if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
-           resultcode = RDIV_EXPR;
-         else
-           /* Although it would be tempting to shorten always here, that
-              loses on some targets, since the modulo instruction is
-              undefined if the quotient can't be represented in the
-              computation mode.  We shorten only if unsigned or if
-              dividing by something we know != -1.  */
-           shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0))
-                      || (TREE_CODE (op1) == INTEGER_CST
-                          && ! integer_all_onesp (op1)));
-         common = 1;
+         if (!noconvert)
+           arg = default_conversion (arg);
+       }
+      else if (typecode == COMPLEX_TYPE)
+       {
+         code = CONJ_EXPR;
+         if (pedantic)
+           pedwarn ("ISO C does not support `~' for complex conjugation");
+         if (!noconvert)
+           arg = default_conversion (arg);
+       }
+      else
+       {
+         error ("wrong type argument to bit-complement");
+         return error_mark_node;
        }
       break;
 
-    case BIT_AND_EXPR:
-    case BIT_ANDTC_EXPR:
-    case BIT_IOR_EXPR:
-    case BIT_XOR_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
-       shorten = -1;
-      else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
-       common = 1;
+    case ABS_EXPR:
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE))
+       {
+         error ("wrong type argument to abs");
+         return error_mark_node;
+       }
+      else if (!noconvert)
+       arg = default_conversion (arg);
       break;
 
-    case TRUNC_MOD_EXPR:
-    case FLOOR_MOD_EXPR:
-      if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
-       warning ("division by zero");
-
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+    case CONJ_EXPR:
+      /* Conjugating a real value is a no-op, but allow it anyway.  */
+      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
+           || typecode == COMPLEX_TYPE))
        {
-         /* Although it would be tempting to shorten always here, that loses
-            on some targets, since the modulo instruction is undefined if the
-            quotient can't be represented in the computation mode.  We shorten
-            only if unsigned or if dividing by something we know != -1.  */
-         shorten = (TREE_UNSIGNED (TREE_TYPE (orig_op0))
-                    || (TREE_CODE (op1) == INTEGER_CST
-                        && ! integer_all_onesp (op1)));
-         common = 1;
+         error ("wrong type argument to conjugation");
+         return error_mark_node;
        }
+      else if (!noconvert)
+       arg = default_conversion (arg);
       break;
 
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-    case TRUTH_AND_EXPR:
-    case TRUTH_OR_EXPR:
-    case TRUTH_XOR_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
-          || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
-             || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
+    case TRUTH_NOT_EXPR:
+      if (typecode != INTEGER_TYPE
+         && typecode != REAL_TYPE && typecode != POINTER_TYPE
+         && typecode != COMPLEX_TYPE
+         /* These will convert to a pointer.  */
+         && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
        {
-         /* Result of these operations is always an int,
-            but that does not mean the operands should be
-            converted to ints!  */
-         result_type = integer_type_node;
-         op0 = c_common_truthvalue_conversion (op0);
-         op1 = c_common_truthvalue_conversion (op1);
-         converted = 1;
+         error ("wrong type argument to unary exclamation mark");
+         return error_mark_node;
        }
-      break;
+      arg = lang_hooks.truthvalue_conversion (arg);
+      return invert_truthvalue (arg);
 
-      /* Shift operations: result has same type as first operand;
-        always convert second operand to int.
-        Also set SHORT_SHIFT if shifting rightward.  */
+    case NOP_EXPR:
+      break;
 
-    case RSHIFT_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
-       {
-         if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
-           {
-             if (tree_int_cst_sgn (op1) < 0)
-               warning ("right shift count is negative");
-             else
-               {
-                 if (! integer_zerop (op1))
-                   short_shift = 1;
+    case REALPART_EXPR:
+      if (TREE_CODE (arg) == COMPLEX_CST)
+       return TREE_REALPART (arg);
+      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+      else
+       return arg;
 
-                 if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-                   warning ("right shift count >= width of type");
-               }
-           }
+    case IMAGPART_EXPR:
+      if (TREE_CODE (arg) == COMPLEX_CST)
+       return TREE_IMAGPART (arg);
+      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+       return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+      else
+       return convert (TREE_TYPE (arg), integer_zero_node);
 
-         /* Use the type of the value to be shifted.  */
-         result_type = type0;
-         /* Convert the shift-count to an integer, regardless of size
-            of value being shifted.  */
-         if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-           op1 = convert (integer_type_node, op1);
-         /* Avoid converting op1 to result_type later.  */
-         converted = 1;
-       }
-      break;
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
 
-    case LSHIFT_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      /* Increment or decrement the real part of the value,
+        and don't change the imaginary part.  */
+      if (typecode == COMPLEX_TYPE)
        {
-         if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
-           {
-             if (tree_int_cst_sgn (op1) < 0)
-               warning ("left shift count is negative");
+         tree real, imag;
 
-             else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning ("left shift count >= width of type");
-           }
+         if (pedantic)
+           pedwarn ("ISO C does not support `++' and `--' on complex types");
 
-         /* Use the type of the value to be shifted.  */
-         result_type = type0;
-         /* Convert the shift-count to an integer, regardless of size
-            of value being shifted.  */
-         if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-           op1 = convert (integer_type_node, op1);
-         /* Avoid converting op1 to result_type later.  */
-         converted = 1;
+         arg = stabilize_reference (arg);
+         real = build_unary_op (REALPART_EXPR, arg, 1);
+         imag = build_unary_op (IMAGPART_EXPR, arg, 1);
+         return build (COMPLEX_EXPR, TREE_TYPE (arg),
+                       build_unary_op (code, real, 1), imag);
        }
-      break;
 
-    case RROTATE_EXPR:
-    case LROTATE_EXPR:
-      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+      /* Report invalid types.  */
+
+      if (typecode != POINTER_TYPE
+         && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
        {
-         if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
-           {
-             if (tree_int_cst_sgn (op1) < 0)
-               warning ("shift count is negative");
-             else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-               warning ("shift count >= width of type");
-           }
+         if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+            error ("wrong type argument to increment");
+          else
+            error ("wrong type argument to decrement");
 
-         /* Use the type of the value to be shifted.  */
-         result_type = type0;
-         /* Convert the shift-count to an integer, regardless of size
-            of value being shifted.  */
-         if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-           op1 = convert (integer_type_node, op1);
-         /* Avoid converting op1 to result_type later.  */
-         converted = 1;
-       }
-      break;
-
-    case EQ_EXPR:
-    case NE_EXPR:
-      if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
-       warning ("comparing floating point with == or != is unsafe");
-      /* Result of comparison is always int,
-        but don't convert the args to int!  */
-      build_type = integer_type_node;
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-          || code0 == COMPLEX_TYPE
-          || code0 == VECTOR_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-             || code1 == COMPLEX_TYPE
-             || code1 == VECTOR_TYPE))
-       short_compare = 1;
-      else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
-       {
-         tree tt0 = TREE_TYPE (type0);
-         tree tt1 = TREE_TYPE (type1);
-         /* Anything compares with void *.  void * compares with anything.
-            Otherwise, the targets must be compatible
-            and both must be object or both incomplete.  */
-         if (comp_target_types (type0, type1, 1))
-           result_type = common_type (type0, type1);
-         else if (VOID_TYPE_P (tt0))
-           {
-             /* op0 != orig_op0 detects the case of something
-                whose value is 0 but which isn't a valid null ptr const.  */
-             if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
-                 && TREE_CODE (tt1) == FUNCTION_TYPE)
-               pedwarn ("ISO C forbids comparison of `void *' with function pointer");
-           }
-         else if (VOID_TYPE_P (tt1))
-           {
-             if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
-                 && TREE_CODE (tt0) == FUNCTION_TYPE)
-               pedwarn ("ISO C forbids comparison of `void *' with function pointer");
-           }
-         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))
-       result_type = type0;
-      else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
-              && integer_zerop (op0))
-       result_type = type1;
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       {
-         result_type = type0;
-         pedwarn ("comparison between pointer and integer");
-       }
-      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
-       {
-         result_type = type1;
-         pedwarn ("comparison between pointer and integer");
-       }
-      break;
-
-    case MAX_EXPR:
-    case MIN_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
-         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
-       shorten = 1;
-      else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
-       {
-         if (comp_target_types (type0, type1, 1))
-           {
-             result_type = common_type (type0, type1);
-             if (pedantic
-                 && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-               pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
-           }
-         else
-           {
-             result_type = ptr_type_node;
-             pedwarn ("comparison of distinct pointer types lacks a cast");
-           }
-       }
-      break;
-
-    case LE_EXPR:
-    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, 1))
-           {
-             result_type = common_type (type0, type1);
-             if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
-                 != !COMPLETE_TYPE_P (TREE_TYPE (type1)))
-               pedwarn ("comparison of complete and incomplete pointers");
-             else if (pedantic
-                      && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-               pedwarn ("ISO 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 = 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 = type1;
-         if (pedantic)
-           pedwarn ("ordered comparison of pointer with integer zero");
-       }
-      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
-       {
-         result_type = type0;
-         pedwarn ("comparison between pointer and integer");
-       }
-      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
-       {
-         result_type = type1;
-         pedwarn ("comparison between pointer and integer");
-       }
-      break;
-
-    case UNORDERED_EXPR:
-    case ORDERED_EXPR:
-    case UNLT_EXPR:
-    case UNLE_EXPR:
-    case UNGT_EXPR:
-    case UNGE_EXPR:
-    case UNEQ_EXPR:
-      build_type = integer_type_node;
-      if (code0 != REAL_TYPE || code1 != REAL_TYPE)
-       {
-         error ("unordered comparison on non-floating point argument");
-         return error_mark_node;
-       }
-      common = 1;
-      break;
-
-    default:
-      break;
-    }
-
-  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
-       || code0 == VECTOR_TYPE)
-      &&
-      (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
-       || code1 == VECTOR_TYPE))
-    {
-      int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
-
-      if (shorten || common || short_compare)
-       result_type = common_type (type0, type1);
-
-      /* For certain operations (which identify themselves by shorten != 0)
-        if both args were extended from the same smaller type,
-        do the arithmetic in that type and then extend.
-
-        shorten !=0 and !=1 indicates a bitwise operation.
-        For them, this optimization is safe only if
-        both args are zero-extended or both are sign-extended.
-        Otherwise, we might change the result.
-        Eg, (short)-1 | (unsigned short)-1 is (int)-1
-        but calculated in (unsigned short) it would be (unsigned short)-1.  */
-
-      if (shorten && none_complex)
-       {
-         int unsigned0, unsigned1;
-         tree arg0 = get_narrower (op0, &unsigned0);
-         tree arg1 = get_narrower (op1, &unsigned1);
-         /* UNS is 1 if the operation to be done is an unsigned one.  */
-         int uns = TREE_UNSIGNED (result_type);
-         tree type;
-
-         final_type = result_type;
-
-         /* Handle the case that OP0 (or OP1) does not *contain* a conversion
-            but it *requires* conversion to FINAL_TYPE.  */
-
-         if ((TYPE_PRECISION (TREE_TYPE (op0))
-              == TYPE_PRECISION (TREE_TYPE (arg0)))
-             && TREE_TYPE (op0) != final_type)
-           unsigned0 = TREE_UNSIGNED (TREE_TYPE (op0));
-         if ((TYPE_PRECISION (TREE_TYPE (op1))
-              == TYPE_PRECISION (TREE_TYPE (arg1)))
-             && TREE_TYPE (op1) != final_type)
-           unsigned1 = TREE_UNSIGNED (TREE_TYPE (op1));
-
-         /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE.  */
-
-         /* For bitwise operations, signedness of nominal type
-            does not matter.  Consider only how operands were extended.  */
-         if (shorten == -1)
-           uns = unsigned0;
-
-         /* Note that in all three cases below we refrain from optimizing
-            an unsigned operation on sign-extended args.
-            That would not be valid.  */
-
-         /* Both args variable: if both extended in same way
-            from same width, do it in that width.
-            Do it unsigned if args were zero-extended.  */
-         if ((TYPE_PRECISION (TREE_TYPE (arg0))
-              < TYPE_PRECISION (result_type))
-             && (TYPE_PRECISION (TREE_TYPE (arg1))
-                 == TYPE_PRECISION (TREE_TYPE (arg0)))
-             && unsigned0 == unsigned1
-             && (unsigned0 || !uns))
-           result_type
-             = c_common_signed_or_unsigned_type
-             (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
-         else if (TREE_CODE (arg0) == INTEGER_CST
-                  && (unsigned1 || !uns)
-                  && (TYPE_PRECISION (TREE_TYPE (arg1))
-                      < TYPE_PRECISION (result_type))
-                  && (type
-                      = c_common_signed_or_unsigned_type (unsigned1,
-                                                          TREE_TYPE (arg1)),
-                      int_fits_type_p (arg0, type)))
-           result_type = type;
-         else if (TREE_CODE (arg1) == INTEGER_CST
-                  && (unsigned0 || !uns)
-                  && (TYPE_PRECISION (TREE_TYPE (arg0))
-                      < TYPE_PRECISION (result_type))
-                  && (type
-                      = c_common_signed_or_unsigned_type (unsigned0,
-                                                          TREE_TYPE (arg0)),
-                      int_fits_type_p (arg1, type)))
-           result_type = type;
-       }
-
-      /* Shifts can be shortened if shifting right.  */
-
-      if (short_shift)
-       {
-         int unsigned_arg;
-         tree arg0 = get_narrower (op0, &unsigned_arg);
-
-         final_type = result_type;
-
-         if (arg0 == op0 && final_type == TREE_TYPE (op0))
-           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.  */
-             && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
-             /* We cannot drop an unsigned shift after sign-extension.  */
-             && (!TREE_UNSIGNED (final_type) || unsigned_arg))
-           {
-             /* Do an unsigned shift if the operand was zero-extended.  */
-             result_type
-               = c_common_signed_or_unsigned_type (unsigned_arg,
-                                                   TREE_TYPE (arg0));
-             /* Convert value-to-be-shifted to that type.  */
-             if (TREE_TYPE (op0) != result_type)
-               op0 = convert (result_type, op0);
-             converted = 1;
-           }
-       }
-
-      /* Comparison operations are shortened too but differently.
-        They identify themselves by setting short_compare = 1.  */
-
-      if (short_compare)
-       {
-         /* Don't write &op0, etc., because that would prevent op0
-            from being kept in a register.
-            Instead, make copies of the our local variables and
-            pass the copies by reference, then copy them back afterward.  */
-         tree xop0 = op0, xop1 = op1, xresult_type = result_type;
-         enum tree_code xresultcode = resultcode;
-         tree val
-           = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
-
-         if (val != 0)
-           return val;
-
-         op0 = xop0, op1 = xop1;
-         converted = 1;
-         resultcode = xresultcode;
-
-         if (warn_sign_compare && skip_evaluation == 0)
-           {
-             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);
-
-             xop0 = orig_op0;
-             xop1 = orig_op1;
-             STRIP_TYPE_NOPS (xop0);
-             STRIP_TYPE_NOPS (xop1);
-
-             /* Give warnings for comparisons between signed and unsigned
-                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.
-
-                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 the same signedness.  */
-              else if (op0_signed == op1_signed)
-                /* OK */;
-             else
-               {
-                 tree sop, uop;
-
-                 if (op0_signed)
-                   sop = xop0, uop = xop1;
-                 else
-                   sop = xop1, uop = xop0;
-
-                 /* Do not warn if the signed quantity is an
-                    unsuffixed integer literal (or some static
-                    constant expression involving such literals or a
-                    conditional expression involving such literals)
-                    and it is non-negative.  */
-                 if (c_tree_expr_nonnegative_p (sop))
-                   /* OK */;
-                 /* Do not warn if the comparison is an equality operation,
-                    the unsigned quantity is an integral constant, and it
-                    would fit in the result if the result were signed.  */
-                 else if (TREE_CODE (uop) == INTEGER_CST
-                          && (resultcode == EQ_EXPR || resultcode == NE_EXPR)
-                          && int_fits_type_p
-                          (uop, c_common_signed_type (result_type)))
-                   /* OK */;
-                 /* Do not warn if the unsigned quantity is an enumeration
-                    constant and its maximum value would fit in the result
-                    if the result were signed.  */
-                 else if (TREE_CODE (uop) == INTEGER_CST
-                          && TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE
-                          && int_fits_type_p
-                          (TYPE_MAX_VALUE (TREE_TYPE(uop)),
-                           c_common_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 (host_integerp (primop0, 0) || host_integerp (primop1, 0))
-                   {
-                     tree primop;
-                     HOST_WIDE_INT constant, mask;
-                     int unsignedp, bits;
-
-                     if (host_integerp (primop0, 0))
-                       {
-                         primop = primop1;
-                         unsignedp = unsignedp1;
-                         constant = tree_low_cst (primop0, 0);
-                       }
-                     else
-                       {
-                         primop = primop0;
-                         unsignedp = unsignedp0;
-                         constant = tree_low_cst (primop1, 0);
-                       }
-
-                     bits = TYPE_PRECISION (TREE_TYPE (primop));
-                     if (bits < TYPE_PRECISION (result_type)
-                         && bits < HOST_BITS_PER_WIDE_INT && unsignedp)
-                       {
-                         mask = (~ (HOST_WIDE_INT) 0) << 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");
-               }
-           }
-       }
-    }
-
-  /* At this point, RESULT_TYPE must be nonzero to avoid an error message.
-     If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
-     Then the expression will be built.
-     It will be given type FINAL_TYPE if that is nonzero;
-     otherwise, it will be given type RESULT_TYPE.  */
-
-  if (!result_type)
-    {
-      binary_op_error (code);
-      return error_mark_node;
-    }
-
-  if (! converted)
-    {
-      if (TREE_TYPE (op0) != result_type)
-       op0 = convert (result_type, op0);
-      if (TREE_TYPE (op1) != result_type)
-       op1 = convert (result_type, op1);
-    }
-
-  if (build_type == NULL_TREE)
-    build_type = result_type;
-
-  {
-    tree result = build (resultcode, build_type, op0, op1);
-    tree folded;
-
-    folded = fold (result);
-    if (folded == result)
-      TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
-    if (final_type != 0)
-      return convert (final_type, folded);
-    return folded;
-  }
-}
-\f
-
-/* Return true if `t' is known to be non-negative.  */
-
-int
-c_tree_expr_nonnegative_p (tree t)
-{
-  if (TREE_CODE (t) == STMT_EXPR)
-    {
-      t = COMPOUND_BODY (STMT_EXPR_STMT (t));
-
-      /* Find the last statement in the chain, ignoring the final
-            * scope statement */
-      while (TREE_CHAIN (t) != NULL_TREE
-             && TREE_CODE (TREE_CHAIN (t)) != SCOPE_STMT)
-        t = TREE_CHAIN (t);
-      return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
-    }
-  return tree_expr_nonnegative_p (t);
-}
-
-/* Return a tree for the difference of pointers OP0 and OP1.
-   The resulting tree has type int.  */
-
-static tree
-pointer_diff (tree op0, tree op1)
-{
-  tree result, folded;
-  tree restype = ptrdiff_type_node;
-
-  tree target_type = TREE_TYPE (TREE_TYPE (op0));
-  tree con0, con1, lit0, lit1;
-  tree orig_op1 = op1;
-
-  if (pedantic || warn_pointer_arith)
-    {
-      if (TREE_CODE (target_type) == VOID_TYPE)
-       pedwarn ("pointer of type `void *' used in subtraction");
-      if (TREE_CODE (target_type) == FUNCTION_TYPE)
-       pedwarn ("pointer to a function used in subtraction");
-    }
-
-  /* If the conversion to ptrdiff_type does anything like widening or
-     converting a partial to an integral mode, we get a convert_expression
-     that is in the way to do any simplifications.
-     (fold-const.c doesn't know that the extra bits won't be needed.
-     split_tree uses STRIP_SIGN_NOPS, which leaves conversions to a
-     different mode in place.)
-     So first try to find a common term here 'by hand'; we want to cover
-     at least the cases that occur in legal static initializers.  */
-  con0 = TREE_CODE (op0) == NOP_EXPR ? TREE_OPERAND (op0, 0) : op0;
-  con1 = TREE_CODE (op1) == NOP_EXPR ? TREE_OPERAND (op1, 0) : op1;
-
-  if (TREE_CODE (con0) == PLUS_EXPR)
-    {
-      lit0 = TREE_OPERAND (con0, 1);
-      con0 = TREE_OPERAND (con0, 0);
-    }
-  else
-    lit0 = integer_zero_node;
-
-  if (TREE_CODE (con1) == PLUS_EXPR)
-    {
-      lit1 = TREE_OPERAND (con1, 1);
-      con1 = TREE_OPERAND (con1, 0);
-    }
-  else
-    lit1 = integer_zero_node;
-
-  if (operand_equal_p (con0, con1, 0))
-    {
-      op0 = lit0;
-      op1 = lit1;
-    }
-
-
-  /* First do the subtraction as integers;
-     then drop through to build the divide operator.
-     Do not do default conversions on the minus operator
-     in case restype is a short type.  */
-
-  op0 = build_binary_op (MINUS_EXPR, convert (restype, op0),
-                        convert (restype, op1), 0);
-  /* This generates an error if op1 is pointer to incomplete type.  */
-  if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1))))
-    error ("arithmetic on pointer to an incomplete type");
-
-  /* This generates an error if op0 is pointer to incomplete type.  */
-  op1 = c_size_in_bytes (target_type);
-
-  /* Divide by the size, in easiest possible way.  */
-
-  result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
-
-  folded = fold (result);
-  if (folded == result)
-    TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
-  return folded;
-}
-\f
-/* Construct and perhaps optimize a tree representation
-   for a unary operation.  CODE, a tree_code, specifies the operation
-   and XARG is the operand.
-   For any CODE other than ADDR_EXPR, FLAG nonzero suppresses
-   the default promotions (such as from short to int).
-   For ADDR_EXPR, the default promotions are not applied; FLAG nonzero
-   allows non-lvalues; this is only used to handle conversion of non-lvalue
-   arrays to pointers in C99.  */
-
-tree
-build_unary_op (enum tree_code code, tree xarg, int flag)
-{
-  /* No default_conversion here.  It causes trouble for ADDR_EXPR.  */
-  tree arg = xarg;
-  tree argtype = 0;
-  enum tree_code typecode = TREE_CODE (TREE_TYPE (arg));
-  tree val;
-  int noconvert = flag;
-
-  if (typecode == ERROR_MARK)
-    return error_mark_node;
-  if (typecode == ENUMERAL_TYPE || typecode == BOOLEAN_TYPE)
-    typecode = INTEGER_TYPE;
-
-  switch (code)
-    {
-    case CONVERT_EXPR:
-      /* This is used for unary plus, because a CONVERT_EXPR
-        is enough to prevent anybody from looking inside for
-        associativity, but won't generate any code.  */
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
-           || typecode == COMPLEX_TYPE))
-       {
-         error ("wrong type argument to unary plus");
-         return error_mark_node;
-       }
-      else if (!noconvert)
-       arg = default_conversion (arg);
-      arg = non_lvalue (arg);
-      break;
-
-    case NEGATE_EXPR:
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
-           || typecode == COMPLEX_TYPE
-           || typecode == VECTOR_TYPE))
-       {
-         error ("wrong type argument to unary minus");
-         return error_mark_node;
-       }
-      else if (!noconvert)
-       arg = default_conversion (arg);
-      break;
-
-    case BIT_NOT_EXPR:
-      if (typecode == INTEGER_TYPE || typecode == VECTOR_TYPE)
-       {
-         if (!noconvert)
-           arg = default_conversion (arg);
-       }
-      else if (typecode == COMPLEX_TYPE)
-       {
-         code = CONJ_EXPR;
-         if (pedantic)
-           pedwarn ("ISO C does not support `~' for complex conjugation");
-         if (!noconvert)
-           arg = default_conversion (arg);
-       }
-      else
-       {
-         error ("wrong type argument to bit-complement");
-         return error_mark_node;
-       }
-      break;
-
-    case ABS_EXPR:
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
-           || typecode == COMPLEX_TYPE))
-       {
-         error ("wrong type argument to abs");
-         return error_mark_node;
-       }
-      else if (!noconvert)
-       arg = default_conversion (arg);
-      break;
-
-    case CONJ_EXPR:
-      /* Conjugating a real value is a no-op, but allow it anyway.  */
-      if (!(typecode == INTEGER_TYPE || typecode == REAL_TYPE
-           || typecode == COMPLEX_TYPE))
-       {
-         error ("wrong type argument to conjugation");
-         return error_mark_node;
-       }
-      else if (!noconvert)
-       arg = default_conversion (arg);
-      break;
-
-    case TRUTH_NOT_EXPR:
-      if (typecode != INTEGER_TYPE
-         && typecode != REAL_TYPE && typecode != POINTER_TYPE
-         && typecode != COMPLEX_TYPE
-         /* These will convert to a pointer.  */
-         && typecode != ARRAY_TYPE && typecode != FUNCTION_TYPE)
-       {
-         error ("wrong type argument to unary exclamation mark");
-         return error_mark_node;
-       }
-      arg = c_common_truthvalue_conversion (arg);
-      return invert_truthvalue (arg);
-
-    case NOP_EXPR:
-      break;
-
-    case REALPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-       return TREE_REALPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-       return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
-      else
-       return arg;
-
-    case IMAGPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-       return TREE_IMAGPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-       return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
-      else
-       return convert (TREE_TYPE (arg), integer_zero_node);
-
-    case PREINCREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-    case PREDECREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-      /* Handle complex lvalues (when permitted)
-        by reduction to simpler cases.  */
-
-      val = unary_complex_lvalue (code, arg, 0);
-      if (val != 0)
-       return val;
-
-      /* Increment or decrement the real part of the value,
-        and don't change the imaginary part.  */
-      if (typecode == COMPLEX_TYPE)
-       {
-         tree real, imag;
-
-         if (pedantic)
-           pedwarn ("ISO C does not support `++' and `--' on complex types");
-
-         arg = stabilize_reference (arg);
-         real = build_unary_op (REALPART_EXPR, arg, 1);
-         imag = build_unary_op (IMAGPART_EXPR, arg, 1);
-         return build (COMPLEX_EXPR, TREE_TYPE (arg),
-                       build_unary_op (code, real, 1), imag);
-       }
-
-      /* Report invalid types.  */
-
-      if (typecode != POINTER_TYPE
-         && typecode != INTEGER_TYPE && typecode != REAL_TYPE)
-       {
-         if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
-            error ("wrong type argument to increment");
-          else
-            error ("wrong type argument to decrement");
-
-         return error_mark_node;
+         return error_mark_node;
        }
 
       {
@@ -2877,57 +2382,6 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
 
        inc = convert (argtype, inc);
 
-       /* Handle incrementing a cast-expression.  */
-
-       while (1)
-         switch (TREE_CODE (arg))
-           {
-           case NOP_EXPR:
-           case CONVERT_EXPR:
-           case FLOAT_EXPR:
-           case FIX_TRUNC_EXPR:
-           case FIX_FLOOR_EXPR:
-           case FIX_ROUND_EXPR:
-           case FIX_CEIL_EXPR:
-             pedantic_lvalue_warning (CONVERT_EXPR);
-             /* If the real type has the same machine representation
-                as the type it is cast to, we can make better output
-                by adding directly to the inside of the cast.  */
-             if ((TREE_CODE (TREE_TYPE (arg))
-                  == TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))))
-                 && (TYPE_MODE (TREE_TYPE (arg))
-                     == TYPE_MODE (TREE_TYPE (TREE_OPERAND (arg, 0)))))
-               arg = TREE_OPERAND (arg, 0);
-             else
-               {
-                 tree incremented, modify, value;
-                 if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
-                   value = boolean_increment (code, arg);
-                 else
-                   {
-                     arg = stabilize_reference (arg);
-                     if (code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR)
-                       value = arg;
-                     else
-                       value = save_expr (arg);
-                     incremented = build (((code == PREINCREMENT_EXPR
-                                            || code == POSTINCREMENT_EXPR)
-                                           ? PLUS_EXPR : MINUS_EXPR),
-                                          argtype, value, inc);
-                     TREE_SIDE_EFFECTS (incremented) = 1;
-                     modify = build_modify_expr (arg, NOP_EXPR, incremented);
-                     value = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
-                   }
-                 TREE_USED (value) = 1;
-                 return value;
-               }
-             break;
-
-           default:
-             goto give_up;
-           }
-      give_up:
-
        /* Complain about anything else that is not a true lvalue.  */
        if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
                                    || code == POSTINCREMENT_EXPR)
@@ -2937,10 +2391,10 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
 
        /* Report a read-only lvalue.  */
        if (TREE_READONLY (arg))
-         readonly_warning (arg,
-                           ((code == PREINCREMENT_EXPR
-                             || code == POSTINCREMENT_EXPR)
-                            ? "increment" : "decrement"));
+         readonly_error (arg,
+                         ((code == PREINCREMENT_EXPR
+                           || code == POSTINCREMENT_EXPR)
+                          ? "increment" : "decrement"));
 
        if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
          val = boolean_increment (code, arg);
@@ -2974,12 +2428,6 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
                                  TREE_OPERAND (arg, 1), 1);
        }
 
-      /* Handle complex lvalues (when permitted)
-        by reduction to simpler cases.  */
-      val = unary_complex_lvalue (code, arg, flag);
-      if (val != 0)
-       return val;
-
       /* Anything not already handled and not a true memory reference
         or a non-lvalue array is an error.  */
       else if (typecode != FUNCTION_TYPE && !flag
@@ -3031,7 +2479,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
           file-scope function counts as a constant.  */
        if (staticp (arg)
            && ! (TREE_CODE (arg) == FUNCTION_DECL
-                 && DECL_CONTEXT (arg) != 0))
+                 && !DECL_FILE_SCOPE_P (arg)))
          TREE_CONSTANT (addr) = 1;
        return addr;
       }
@@ -3047,7 +2495,7 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
 
 /* Return nonzero if REF is an lvalue valid for this language.
    Lvalues can be assigned, unless their type has TYPE_READONLY.
-   Lvalues can have their address taken, unless they have DECL_REGISTER.  */
+   Lvalues can have their address taken, unless they have C_DECL_REGISTER.  */
 
 int
 lvalue_p (tree ref)
@@ -3091,93 +2539,31 @@ lvalue_or_else (tree ref, const char *msgid)
 {
   int win = lvalue_p (ref);
 
-  if (! win)
-    error ("%s", msgid);
-
-  return win;
-}
-
-/* Apply unary lvalue-demanding operator CODE to the expression ARG
-   for certain kinds of expressions which are not really lvalues
-   but which we can accept as lvalues.  If FLAG is nonzero, then
-   non-lvalues are OK since we may be converting a non-lvalue array to
-   a pointer in C99.
-
-   If ARG is not a kind of expression we can handle, return zero.  */
-
-static tree
-unary_complex_lvalue (enum tree_code code, tree arg, int flag)
-{
-  /* Handle (a, b) used as an "lvalue".  */
-  if (TREE_CODE (arg) == COMPOUND_EXPR)
-    {
-      tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
-
-      /* If this returns a function type, it isn't really being used as
-        an lvalue, so don't issue a warning about it.  */
-      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
-       pedantic_lvalue_warning (COMPOUND_EXPR);
-
-      return build (COMPOUND_EXPR, TREE_TYPE (real_result),
-                   TREE_OPERAND (arg, 0), real_result);
-    }
-
-  /* Handle (a ? b : c) used as an "lvalue".  */
-  if (TREE_CODE (arg) == COND_EXPR)
-    {
-      if (!flag)
-       pedantic_lvalue_warning (COND_EXPR);
-      if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE && !flag)
-       pedantic_lvalue_warning (COMPOUND_EXPR);
-
-      return (build_conditional_expr
-             (TREE_OPERAND (arg, 0),
-              build_unary_op (code, TREE_OPERAND (arg, 1), flag),
-              build_unary_op (code, TREE_OPERAND (arg, 2), flag)));
-    }
-
-  return 0;
-}
-
-/* If pedantic, warn about improper lvalue.   CODE is either COND_EXPR
-   COMPOUND_EXPR, or CONVERT_EXPR (for casts).  */
-
-static void
-pedantic_lvalue_warning (enum tree_code code)
-{
-  if (pedantic)
-    switch (code)
-      {
-      case COND_EXPR:
-       pedwarn ("ISO C forbids use of conditional expressions as lvalues");
-       break;
-      case COMPOUND_EXPR:
-       pedwarn ("ISO C forbids use of compound expressions as lvalues");
-       break;
-      default:
-       pedwarn ("ISO C forbids use of cast expressions as lvalues");
-       break;
-      }
+  if (! win)
+    error ("%s", msgid);
+
+  return win;
 }
+
 \f
 /* Warn about storing in something that is `const'.  */
 
 void
-readonly_warning (tree arg, const char *msgid)
+readonly_error (tree arg, const char *msgid)
 {
   if (TREE_CODE (arg) == COMPONENT_REF)
     {
       if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
-       readonly_warning (TREE_OPERAND (arg, 0), msgid);
+       readonly_error (TREE_OPERAND (arg, 0), msgid);
       else
-       pedwarn ("%s of read-only member `%s'", _(msgid),
-                IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
+       error ("%s of read-only member `%s'", _(msgid),
+              IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (arg, 1))));
     }
   else if (TREE_CODE (arg) == VAR_DECL)
-    pedwarn ("%s of read-only variable `%s'", _(msgid),
-            IDENTIFIER_POINTER (DECL_NAME (arg)));
+    error ("%s of read-only variable `%s'", _(msgid),
+          IDENTIFIER_POINTER (DECL_NAME (arg)));
   else
-    pedwarn ("%s of read-only location", _(msgid));
+    error ("%s of read-only location", _(msgid));
 }
 \f
 /* Mark EXP saying that we need to be able to take the
@@ -3218,10 +2604,10 @@ c_mark_addressable (tree exp)
       case CONST_DECL:
       case PARM_DECL:
       case RESULT_DECL:
-       if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+       if (C_DECL_REGISTER (x)
            && DECL_NONLOCAL (x))
          {
-           if (TREE_PUBLIC (x))
+           if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
              {
                error ("global register variable `%s' used in nested function",
                       IDENTIFIER_POINTER (DECL_NAME (x)));
@@ -3230,26 +2616,15 @@ c_mark_addressable (tree exp)
            pedwarn ("register variable `%s' used in nested function",
                     IDENTIFIER_POINTER (DECL_NAME (x)));
          }
-       else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x))
+       else if (C_DECL_REGISTER (x))
          {
-           if (TREE_PUBLIC (x))
+           if (TREE_PUBLIC (x) || TREE_STATIC (x) || DECL_EXTERNAL (x))
              {
                error ("address of global register variable `%s' requested",
                       IDENTIFIER_POINTER (DECL_NAME (x)));
                return false;
              }
 
-           /* 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 false;
-             }
-
            pedwarn ("address of register variable `%s' requested",
                     IDENTIFIER_POINTER (DECL_NAME (x)));
          }
@@ -3258,6 +2633,7 @@ c_mark_addressable (tree exp)
        /* drops in */
       case FUNCTION_DECL:
        TREE_ADDRESSABLE (x) = 1;
+       /* drops out */
       default:
        return true;
     }
@@ -3275,7 +2651,7 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
   tree result_type = NULL;
   tree orig_op1 = op1, orig_op2 = op2;
 
-  ifexp = c_common_truthvalue_conversion (default_conversion (ifexp));
+  ifexp = lang_hooks.truthvalue_conversion (default_conversion (ifexp));
 
   /* Promote both alternatives.  */
 
@@ -3294,6 +2670,14 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
   type2 = TREE_TYPE (op2);
   code2 = TREE_CODE (type2);
 
+  /* C90 does not permit non-lvalue arrays in conditional expressions.
+     In C99 they will be pointers by now.  */
+  if (code1 == ARRAY_TYPE || code2 == ARRAY_TYPE)
+    {
+      error ("non-lvalue array in conditional expression");
+      return error_mark_node;
+    }
+
   /* Quickly detect the usual case where op1 and op2 have the same type
      after promotion.  */
   if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
@@ -3317,15 +2701,15 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
         will be considered, but default promotions won't.  */
       if (warn_sign_compare && !skip_evaluation)
        {
-         int unsigned_op1 = TREE_UNSIGNED (TREE_TYPE (orig_op1));
-         int unsigned_op2 = TREE_UNSIGNED (TREE_TYPE (orig_op2));
+         int unsigned_op1 = TYPE_UNSIGNED (TREE_TYPE (orig_op1));
+         int unsigned_op2 = TYPE_UNSIGNED (TREE_TYPE (orig_op2));
 
          if (unsigned_op1 ^ unsigned_op2)
            {
              /* Do not warn if the result type is signed, since the
                 signed type will only be chosen if it can represent
                 all the values of the unsigned type.  */
-             if (! TREE_UNSIGNED (result_type))
+             if (! TYPE_UNSIGNED (result_type))
                /* OK */;
              /* Do not warn if the signed quantity is an unsuffixed
                 integer literal (or some static constant expression
@@ -3395,3637 +2779,4322 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
       result_type = type2;
     }
 
-  if (!result_type)
-    {
-      if (flag_cond_mismatch)
-       result_type = void_type_node;
-      else
+  if (!result_type)
+    {
+      if (flag_cond_mismatch)
+       result_type = void_type_node;
+      else
+       {
+         error ("type mismatch in conditional expression");
+         return error_mark_node;
+       }
+    }
+
+  /* Merge const and volatile flags of the incoming types.  */
+  result_type
+    = build_type_variant (result_type,
+                         TREE_READONLY (op1) || TREE_READONLY (op2),
+                         TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
+
+  if (result_type != TREE_TYPE (op1))
+    op1 = convert_and_check (result_type, op1);
+  if (result_type != TREE_TYPE (op2))
+    op2 = convert_and_check (result_type, op2);
+
+  if (TREE_CODE (ifexp) == INTEGER_CST)
+    return non_lvalue (integer_zerop (ifexp) ? op2 : op1);
+
+  return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
+}
+\f
+/* Given a list of expressions, return a compound expression
+   that performs them all and returns the value of the last of them.  */
+
+tree
+build_compound_expr (tree list)
+{
+  return internal_build_compound_expr (list, TRUE);
+}
+
+static tree
+internal_build_compound_expr (tree list, int first_p)
+{
+  tree rest;
+
+  if (TREE_CHAIN (list) == 0)
+    {
+      /* Convert arrays and functions to pointers when there
+        really is a comma operator.  */
+      if (!first_p)
+       TREE_VALUE (list)
+         = default_function_array_conversion (TREE_VALUE (list));
+
+      /* Don't let (0, 0) be null pointer constant.  */
+      if (!first_p && integer_zerop (TREE_VALUE (list)))
+       return non_lvalue (TREE_VALUE (list));
+      return TREE_VALUE (list);
+    }
+
+  rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
+
+  if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+    {
+      /* The left-hand operand of a comma expression is like an expression
+         statement: with -Wextra or -Wunused, we should warn if it doesn't have
+        any side-effects, unless it was explicitly cast to (void).  */
+      if (warn_unused_value
+           && ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR
+                && VOID_TYPE_P (TREE_TYPE (TREE_VALUE (list)))))
+        warning ("left-hand operand of comma expression has no effect");
+    }
+
+  /* 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_value)
+    warn_if_unused_value (TREE_VALUE (list));
+
+  return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
+}
+
+/* Build an expression representing a cast to type TYPE of expression EXPR.  */
+
+tree
+build_c_cast (tree type, tree expr)
+{
+  tree value = expr;
+
+  if (type == error_mark_node || expr == error_mark_node)
+    return error_mark_node;
+
+  /* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing
+     only in <protocol> qualifications.  But when constructing cast expressions,
+     the protocols do matter and must be kept around.  */
+  if (!c_dialect_objc () || !objc_is_object_ptr (type))
+    type = TYPE_MAIN_VARIANT (type);
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      error ("cast specifies array type");
+      return error_mark_node;
+    }
+
+  if (TREE_CODE (type) == FUNCTION_TYPE)
+    {
+      error ("cast specifies function type");
+      return error_mark_node;
+    }
+
+  if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
+    {
+      if (pedantic)
+       {
+         if (TREE_CODE (type) == RECORD_TYPE
+             || TREE_CODE (type) == UNION_TYPE)
+           pedwarn ("ISO C forbids casting nonscalar to the same type");
+       }
+    }
+  else if (TREE_CODE (type) == UNION_TYPE)
+    {
+      tree field;
+      value = default_function_array_conversion (value);
+
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+       if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
+                      TYPE_MAIN_VARIANT (TREE_TYPE (value)), COMPARE_STRICT))
+         break;
+
+      if (field)
+       {
+         tree t;
+
+         if (pedantic)
+           pedwarn ("ISO C forbids casts to union type");
+         t = digest_init (type,
+                          build_constructor (type,
+                                             build_tree_list (field, value)),
+                          0);
+         TREE_CONSTANT (t) = TREE_CONSTANT (value);
+         return t;
+       }
+      error ("cast to union type from type not present in union");
+      return error_mark_node;
+    }
+  else
+    {
+      tree otype, ovalue;
+
+      /* If casting to void, avoid the error that would come
+        from default_conversion in the case of a non-lvalue array.  */
+      if (type == void_type_node)
+       return build1 (CONVERT_EXPR, type, value);
+
+      /* Convert functions and arrays to pointers,
+        but don't convert any other types.  */
+      value = default_function_array_conversion (value);
+      otype = TREE_TYPE (value);
+
+      /* Optionally warn about potentially worrisome casts.  */
+
+      if (warn_cast_qual
+         && TREE_CODE (type) == POINTER_TYPE
+         && TREE_CODE (otype) == POINTER_TYPE)
+       {
+         tree in_type = type;
+         tree in_otype = otype;
+         int added = 0;
+         int discarded = 0;
+
+         /* Check that the qualifiers on IN_TYPE are a superset of
+            the qualifiers of IN_OTYPE.  The outermost level of
+            POINTER_TYPE nodes is uninteresting and we stop as soon
+            as we hit a non-POINTER_TYPE node on either type.  */
+         do
+           {
+             in_otype = TREE_TYPE (in_otype);
+             in_type = TREE_TYPE (in_type);
+
+             /* GNU C allows cv-qualified function types.  'const'
+                means the function is very pure, 'volatile' means it
+                can't return.  We need to warn when such qualifiers
+                are added, not when they're taken away.  */
+             if (TREE_CODE (in_otype) == FUNCTION_TYPE
+                 && TREE_CODE (in_type) == FUNCTION_TYPE)
+               added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
+             else
+               discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
+           }
+         while (TREE_CODE (in_type) == POINTER_TYPE
+                && TREE_CODE (in_otype) == POINTER_TYPE);
+
+         if (added)
+           warning ("cast adds new qualifiers to function type");
+
+         if (discarded)
+           /* There are qualifiers present in IN_OTYPE that are not
+              present in IN_TYPE.  */
+           warning ("cast discards qualifiers from pointer target type");
+       }
+
+      /* Warn about possible alignment problems.  */
+      if (STRICT_ALIGNMENT && warn_cast_align
+         && TREE_CODE (type) == POINTER_TYPE
+         && TREE_CODE (otype) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
+         && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
+         /* Don't warn about opaque types, where the actual alignment
+            restriction is unknown.  */
+         && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE
+               || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
+              && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
+         && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
+       warning ("cast increases required alignment of target type");
+
+      if (TREE_CODE (type) == INTEGER_TYPE
+         && TREE_CODE (otype) == POINTER_TYPE
+         && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
+         && !TREE_CONSTANT (value))
+       warning ("cast from pointer to integer of different size");
+
+      if (warn_bad_function_cast
+         && TREE_CODE (value) == CALL_EXPR
+         && TREE_CODE (type) != TREE_CODE (otype))
+       warning ("cast does not match function type");
+
+      if (TREE_CODE (type) == POINTER_TYPE
+         && TREE_CODE (otype) == INTEGER_TYPE
+         && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
+         /* Don't warn about converting any constant.  */
+         && !TREE_CONSTANT (value))
+       warning ("cast to pointer from integer of different size");
+
+      if (TREE_CODE (type) == POINTER_TYPE
+         && TREE_CODE (otype) == POINTER_TYPE
+         && TREE_CODE (expr) == ADDR_EXPR
+         && DECL_P (TREE_OPERAND (expr, 0))
+         && flag_strict_aliasing && warn_strict_aliasing
+         && !VOID_TYPE_P (TREE_TYPE (type)))
+       {
+         /* Casting the address of a decl to non void pointer. Warn
+            if the cast breaks type based aliasing.  */
+         if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
+           warning ("type-punning to incomplete type might break strict-aliasing rules");
+         else
+           {
+             HOST_WIDE_INT set1 = get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0)));
+             HOST_WIDE_INT set2 = get_alias_set (TREE_TYPE (type));
+
+             if (!alias_sets_conflict_p (set1, set2))
+               warning ("dereferencing type-punned pointer will break strict-aliasing rules");
+             else if (warn_strict_aliasing > 1
+                      && !alias_sets_might_conflict_p (set1, set2))
+               warning ("dereferencing type-punned pointer might break strict-aliasing rules");
+           }
+       }
+
+      /* If pedantic, warn for conversions between function and object
+        pointer types, except for converting a null pointer constant
+        to function pointer type.  */
+      if (pedantic
+         && TREE_CODE (type) == POINTER_TYPE
+         && TREE_CODE (otype) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (otype)) == FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
+       pedwarn ("ISO C forbids conversion of function pointer to object pointer type");
+
+      if (pedantic
+         && TREE_CODE (type) == POINTER_TYPE
+         && TREE_CODE (otype) == POINTER_TYPE
+         && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+         && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
+         && !(integer_zerop (value) && TREE_TYPE (otype) == void_type_node
+              && TREE_CODE (expr) != NOP_EXPR))
+       pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
+
+      ovalue = value;
+      /* Replace a nonvolatile const static variable with its value.  */
+      if (optimize && TREE_CODE (value) == VAR_DECL)
+       value = decl_constant_value (value);
+      value = convert (type, value);
+
+      /* Ignore any integer overflow caused by the cast.  */
+      if (TREE_CODE (value) == INTEGER_CST)
        {
-         error ("type mismatch in conditional expression");
-         return error_mark_node;
+         TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
+
+         if (TREE_CODE_CLASS (TREE_CODE (ovalue)) == 'c')
+           TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
        }
     }
 
-  /* Merge const and volatile flags of the incoming types.  */
-  result_type
-    = build_type_variant (result_type,
-                         TREE_READONLY (op1) || TREE_READONLY (op2),
-                         TREE_THIS_VOLATILE (op1) || TREE_THIS_VOLATILE (op2));
-
-  if (result_type != TREE_TYPE (op1))
-    op1 = convert_and_check (result_type, op1);
-  if (result_type != TREE_TYPE (op2))
-    op2 = convert_and_check (result_type, op2);
+  /* Don't let (void *) (FOO *) 0 be a null pointer constant.  */
+  if (TREE_CODE (value) == INTEGER_CST
+      && TREE_CODE (expr) == INTEGER_CST
+      && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
+    value = non_lvalue (value);
 
-  if (TREE_CODE (ifexp) == INTEGER_CST)
-    return pedantic_non_lvalue (integer_zerop (ifexp) ? op2 : op1);
+  /* Don't let a cast be an lvalue.  */
+  if (value == expr)
+    value = non_lvalue (value);
 
-  return fold (build (COND_EXPR, result_type, ifexp, op1, op2));
+  return value;
 }
-\f
-/* Given a list of expressions, return a compound expression
-   that performs them all and returns the value of the last of them.  */
 
+/* Interpret a cast of expression EXPR to type TYPE.  */
 tree
-build_compound_expr (tree list)
+c_cast_expr (tree type, tree expr)
 {
-  return internal_build_compound_expr (list, TRUE);
+  int saved_wsp = warn_strict_prototypes;
+
+  /* This avoids warnings about unprototyped casts on
+     integers.  E.g. "#define SIG_DFL (void(*)())0".  */
+  if (TREE_CODE (expr) == INTEGER_CST)
+    warn_strict_prototypes = 0;
+  type = groktypename (type);
+  warn_strict_prototypes = saved_wsp;
+
+  return build_c_cast (type, expr);
 }
 
-static tree
-internal_build_compound_expr (tree list, int first_p)
+\f
+/* Build an assignment expression of lvalue LHS from value RHS.
+   MODIFYCODE is the code for a binary operator that we use
+   to combine the old value of LHS with RHS to get the new value.
+   Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.  */
+
+tree
+build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
 {
-  tree rest;
+  tree result;
+  tree newrhs;
+  tree lhstype = TREE_TYPE (lhs);
+  tree olhstype = lhstype;
 
-  if (TREE_CHAIN (list) == 0)
-    {
-      /* Convert arrays and functions to pointers when there
-        really is a comma operator.  */
-      if (!first_p)
-       TREE_VALUE (list)
-         = default_function_array_conversion (TREE_VALUE (list));
+  /* Types that aren't fully specified cannot be used in assignments.  */
+  lhs = require_complete_type (lhs);
 
-      /* Don't let (0, 0) be null pointer constant.  */
-      if (!first_p && integer_zerop (TREE_VALUE (list)))
-       return non_lvalue (TREE_VALUE (list));
-      return TREE_VALUE (list);
-    }
+  /* Avoid duplicate error messages from operands that had errors.  */
+  if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
+    return error_mark_node;
 
-  rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE);
+  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
+  /* Do not use STRIP_NOPS here.  We do not want an enumerator
+     whose value is 0 to count as a null pointer constant.  */
+  if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
+    rhs = TREE_OPERAND (rhs, 0);
 
-  if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
+  newrhs = rhs;
+
+  /* If a binary op has been requested, combine the old LHS value with the RHS
+     producing the value we should actually store into the LHS.  */
+
+  if (modifycode != NOP_EXPR)
     {
-      /* The left-hand operand of a comma expression is like an expression
-         statement: with -Wextra or -Wunused, we should warn if it doesn't have
-        any side-effects, unless it was explicitly cast to (void).  */
-      if (warn_unused_value
-           && ! (TREE_CODE (TREE_VALUE (list)) == CONVERT_EXPR
-                && VOID_TYPE_P (TREE_TYPE (TREE_VALUE (list)))))
-        warning ("left-hand operand of comma expression has no effect");
+      lhs = stabilize_reference (lhs);
+      newrhs = build_binary_op (modifycode, lhs, rhs, 1);
+    }
+
+  if (!lvalue_or_else (lhs, "invalid lvalue in assignment"))
+    return error_mark_node;
+
+  /* Warn about storing in something that is `const'.  */
+
+  if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
+      || ((TREE_CODE (lhstype) == RECORD_TYPE
+          || TREE_CODE (lhstype) == UNION_TYPE)
+         && C_TYPE_FIELDS_READONLY (lhstype)))
+    readonly_error (lhs, "assignment");
+
+  /* If storing into a structure or union member,
+     it has probably been given type `int'.
+     Compute the type that would go with
+     the actual amount of storage the member occupies.  */
+
+  if (TREE_CODE (lhs) == COMPONENT_REF
+      && (TREE_CODE (lhstype) == INTEGER_TYPE
+         || TREE_CODE (lhstype) == BOOLEAN_TYPE
+         || TREE_CODE (lhstype) == REAL_TYPE
+         || TREE_CODE (lhstype) == ENUMERAL_TYPE))
+    lhstype = TREE_TYPE (get_unwidened (lhs, 0));
 
-      /* When pedantic, a compound expression can be neither an lvalue
-         nor an integer constant expression.  */
-      if (! pedantic)
-        return rest;
+  /* If storing in a field that is in actuality a short or narrower than one,
+     we must store in the field in its actual type.  */
+
+  if (lhstype != TREE_TYPE (lhs))
+    {
+      lhs = copy_node (lhs);
+      TREE_TYPE (lhs) = lhstype;
     }
 
-  /* 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_value)
-    warn_if_unused_value (TREE_VALUE (list));
+  /* Convert new value to destination type.  */
 
-  return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest);
+  newrhs = convert_for_assignment (lhstype, newrhs, _("assignment"),
+                                  NULL_TREE, NULL_TREE, 0);
+  if (TREE_CODE (newrhs) == ERROR_MARK)
+    return error_mark_node;
+
+  /* Scan operands */
+
+  result = build (MODIFY_EXPR, lhstype, lhs, newrhs);
+  TREE_SIDE_EFFECTS (result) = 1;
+
+  /* If we got the LHS in a different type for storing in,
+     convert the result back to the nominal type of LHS
+     so that the value we return always has the same type
+     as the LHS argument.  */
+
+  if (olhstype == TREE_TYPE (result))
+    return result;
+  return convert_for_assignment (olhstype, result, _("assignment"),
+                                NULL_TREE, NULL_TREE, 0);
 }
+\f
+/* Convert value RHS to type TYPE as preparation for an assignment
+   to an lvalue of type TYPE.
+   The real work of conversion is done by `convert'.
+   The purpose of this function is to generate error messages
+   for assignments that are not allowed in C.
+   ERRTYPE is a string to use in error messages:
+   "assignment", "return", etc.  If it is null, this is parameter passing
+   for a function call (and different error messages are output).
 
-/* Build an expression representing a cast to type TYPE of expression EXPR.  */
+   FUNNAME is the name of the function being called,
+   as an IDENTIFIER_NODE, or null.
+   PARMNUM is the number of the argument, for printing in error messages.  */
 
-tree
-build_c_cast (tree type, tree expr)
+static tree
+convert_for_assignment (tree type, tree rhs, const char *errtype,
+                       tree fundecl, tree funname, int parmnum)
 {
-  tree value = expr;
+  enum tree_code codel = TREE_CODE (type);
+  tree rhstype;
+  enum tree_code coder;
 
-  if (type == error_mark_node || expr == error_mark_node)
+  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
+  /* Do not use STRIP_NOPS here.  We do not want an enumerator
+     whose value is 0 to count as a null pointer constant.  */
+  if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
+    rhs = TREE_OPERAND (rhs, 0);
+
+  if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
+      || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
+    rhs = default_conversion (rhs);
+  else if (optimize && TREE_CODE (rhs) == VAR_DECL)
+    rhs = decl_constant_value_for_broken_optimization (rhs);
+
+  rhstype = TREE_TYPE (rhs);
+  coder = TREE_CODE (rhstype);
+
+  if (coder == ERROR_MARK)
     return error_mark_node;
 
-  /* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing
-     only in <protocol> qualifications.  But when constructing cast expressions,
-     the protocols do matter and must be kept around.  */
-  if (!c_dialect_objc () || !objc_is_id (type))
-    type = TYPE_MAIN_VARIANT (type);
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
+    {
+      overflow_warning (rhs);
+      /* Check for Objective-C protocols.  This will automatically
+        issue a warning if there are protocol violations.  No need to
+        use the return value.  */
+      if (c_dialect_objc ())
+       objc_comptypes (type, rhstype, 0);
+      return rhs;
+    }
 
-  if (TREE_CODE (type) == ARRAY_TYPE)
+  if (coder == VOID_TYPE)
     {
-      error ("cast specifies array type");
+      error ("void value not ignored as it ought to be");
       return error_mark_node;
     }
+  /* A type converts to a reference to it.
+     This code doesn't fully support references, it's just for the
+     special case of va_start and va_copy.  */
+  if (codel == REFERENCE_TYPE
+      && comptypes (TREE_TYPE (type), TREE_TYPE (rhs), COMPARE_STRICT) == 1)
+    {
+      if (!lvalue_p (rhs))
+       {
+         error ("cannot pass rvalue to reference parameter");
+         return error_mark_node;
+       }
+      if (!c_mark_addressable (rhs))
+       return error_mark_node;
+      rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs);
+
+      /* We already know that these two types are compatible, but they
+        may not be exactly identical.  In fact, `TREE_TYPE (type)' is
+        likely to be __builtin_va_list and `TREE_TYPE (rhs)' is
+        likely to be va_list, a typedef to __builtin_va_list, which
+        is different enough that it will cause problems later.  */
+      if (TREE_TYPE (TREE_TYPE (rhs)) != TREE_TYPE (type))
+       rhs = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), rhs);
+
+      rhs = build1 (NOP_EXPR, type, rhs);
+      return rhs;
+    }
+  /* Some types can interconvert without explicit casts.  */
+  else if (codel == VECTOR_TYPE
+           && comptypes (type, TREE_TYPE (rhs), COMPARE_STRICT) == 1)
+    return convert (type, rhs);
+  /* Arithmetic types all interconvert, and enum is treated like int.  */
+  else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
+           || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
+           || codel == BOOLEAN_TYPE)
+          && (coder == INTEGER_TYPE || coder == REAL_TYPE
+              || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
+              || coder == BOOLEAN_TYPE))
+    return convert_and_check (type, rhs);
 
-  if (TREE_CODE (type) == FUNCTION_TYPE)
+  /* Conversion to a transparent union from its member types.
+     This applies only to function arguments.  */
+  else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype)
     {
-      error ("cast specifies function type");
-      return error_mark_node;
-    }
+      tree memb_types;
+      tree marginal_memb_type = 0;
 
-  if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
-    {
-      if (pedantic)
+      for (memb_types = TYPE_FIELDS (type); memb_types;
+          memb_types = TREE_CHAIN (memb_types))
        {
-         if (TREE_CODE (type) == RECORD_TYPE
-             || TREE_CODE (type) == UNION_TYPE)
-           pedwarn ("ISO C forbids casting nonscalar to the same type");
-       }
-    }
-  else if (TREE_CODE (type) == UNION_TYPE)
-    {
-      tree field;
-      value = default_function_array_conversion (value);
+         tree memb_type = TREE_TYPE (memb_types);
 
-      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-       if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
-                      TYPE_MAIN_VARIANT (TREE_TYPE (value))))
-         break;
+         if (comptypes (TYPE_MAIN_VARIANT (memb_type),
+                        TYPE_MAIN_VARIANT (rhstype), COMPARE_STRICT))
+           break;
 
-      if (field)
-       {
-         tree t;
+         if (TREE_CODE (memb_type) != POINTER_TYPE)
+           continue;
 
-         if (pedantic)
-           pedwarn ("ISO C forbids casts to union type");
-         t = digest_init (type,
-                          build_constructor (type,
-                                             build_tree_list (field, value)),
-                          0);
-         TREE_CONSTANT (t) = TREE_CONSTANT (value);
-         return t;
-       }
-      error ("cast to union type from type not present in union");
-      return error_mark_node;
-    }
-  else
-    {
-      tree otype, ovalue;
+         if (coder == POINTER_TYPE)
+           {
+             tree ttl = TREE_TYPE (memb_type);
+             tree ttr = TREE_TYPE (rhstype);
 
-      /* If casting to void, avoid the error that would come
-        from default_conversion in the case of a non-lvalue array.  */
-      if (type == void_type_node)
-       return build1 (CONVERT_EXPR, type, value);
+             /* 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.  */
+             if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+                 || comp_target_types (memb_type, rhstype, 0))
+               {
+                 /* If this type won't generate any warnings, use it.  */
+                 if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
+                     || ((TREE_CODE (ttr) == FUNCTION_TYPE
+                          && TREE_CODE (ttl) == FUNCTION_TYPE)
+                         ? ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
+                            == TYPE_QUALS (ttr))
+                         : ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
+                            == TYPE_QUALS (ttl))))
+                   break;
 
-      /* Convert functions and arrays to pointers,
-        but don't convert any other types.  */
-      value = default_function_array_conversion (value);
-      otype = TREE_TYPE (value);
+                 /* Keep looking for a better type, but remember this one.  */
+                 if (! marginal_memb_type)
+                   marginal_memb_type = memb_type;
+               }
+           }
 
-      /* Optionally warn about potentially worrisome casts.  */
+         /* Can convert integer zero to any pointer type.  */
+         if (integer_zerop (rhs)
+             || (TREE_CODE (rhs) == NOP_EXPR
+                 && integer_zerop (TREE_OPERAND (rhs, 0))))
+           {
+             rhs = null_pointer_node;
+             break;
+           }
+       }
 
-      if (warn_cast_qual
-         && TREE_CODE (type) == POINTER_TYPE
-         && TREE_CODE (otype) == POINTER_TYPE)
+      if (memb_types || marginal_memb_type)
        {
-         tree in_type = type;
-         tree in_otype = otype;
-         int added = 0;
-         int discarded = 0;
-
-         /* Check that the qualifiers on IN_TYPE are a superset of
-            the qualifiers of IN_OTYPE.  The outermost level of
-            POINTER_TYPE nodes is uninteresting and we stop as soon
-            as we hit a non-POINTER_TYPE node on either type.  */
-         do
+         if (! memb_types)
            {
-             in_otype = TREE_TYPE (in_otype);
-             in_type = TREE_TYPE (in_type);
+             /* We have only a marginally acceptable member type;
+                it needs a warning.  */
+             tree ttl = TREE_TYPE (marginal_memb_type);
+             tree ttr = TREE_TYPE (rhstype);
 
-             /* GNU C allows cv-qualified function types.  'const'
-                means the function is very pure, 'volatile' means it
-                can't return.  We need to warn when such qualifiers
-                are added, not when they're taken away.  */
-             if (TREE_CODE (in_otype) == FUNCTION_TYPE
-                 && TREE_CODE (in_type) == FUNCTION_TYPE)
-               added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype));
-             else
-               discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type));
+             /* 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)
+               {
+                 /* 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_QUALS (ttl) & ~TYPE_QUALS (ttr))
+                   warn_for_assignment ("%s makes qualified function pointer from unqualified",
+                                        errtype, funname, parmnum);
+               }
+             else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+               warn_for_assignment ("%s discards qualifiers from pointer target type",
+                                    errtype, funname,
+                                    parmnum);
            }
-         while (TREE_CODE (in_type) == POINTER_TYPE
-                && TREE_CODE (in_otype) == POINTER_TYPE);
 
-         if (added)
-           warning ("cast adds new qualifiers to function type");
+         if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl))
+           pedwarn ("ISO C prohibits argument conversion to union type");
 
-         if (discarded)
-           /* There are qualifiers present in IN_OTYPE that are not
-              present in IN_TYPE.  */
-           warning ("cast discards qualifiers from pointer target type");
+         return build1 (NOP_EXPR, type, rhs);
        }
+    }
 
-      /* Warn about possible alignment problems.  */
-      if (STRICT_ALIGNMENT && warn_cast_align
-         && TREE_CODE (type) == POINTER_TYPE
-         && TREE_CODE (otype) == POINTER_TYPE
-         && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
-         && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
-         /* Don't warn about opaque types, where the actual alignment
-            restriction is unknown.  */
-         && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE
-               || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
-              && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
-         && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
-       warning ("cast increases required alignment of target type");
+  /* Conversions among pointers */
+  else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
+          && (coder == codel))
+    {
+      tree ttl = TREE_TYPE (type);
+      tree ttr = TREE_TYPE (rhstype);
+      bool is_opaque_pointer;
+      int target_cmp = 0;   /* Cache comp_target_types () result.  */
 
-      if (TREE_CODE (type) == INTEGER_TYPE
-         && TREE_CODE (otype) == POINTER_TYPE
-         && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
-         && !TREE_CONSTANT (value))
-       warning ("cast from pointer to integer of different size");
+      /* Opaque pointers are treated like void pointers.  */
+      is_opaque_pointer = (targetm.vector_opaque_p (type)
+                           || targetm.vector_opaque_p (rhstype))
+        && TREE_CODE (ttl) == VECTOR_TYPE
+        && TREE_CODE (ttr) == VECTOR_TYPE;
 
-      if (warn_bad_function_cast
-         && TREE_CODE (value) == CALL_EXPR
-         && TREE_CODE (type) != TREE_CODE (otype))
-       warning ("cast does not match function type");
+      /* 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.  */
+      if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+         || (target_cmp = comp_target_types (type, rhstype, 0))
+         || is_opaque_pointer
+         || (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl))
+             == c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr))))
+       {
+         if (pedantic
+             && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
+                 ||
+                 (VOID_TYPE_P (ttr)
+                  /* Check TREE_CODE to catch cases like (void *) (char *) 0
+                     which are not ANSI null ptr constants.  */
+                  && (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
+                  && TREE_CODE (ttl) == FUNCTION_TYPE)))
+           warn_for_assignment ("ISO C forbids %s between function pointer and `void *'",
+                                errtype, 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)
+           {
+             if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+               warn_for_assignment ("%s discards qualifiers from pointer target type",
+                                    errtype, funname, parmnum);
+             /* If this is not a case of ignoring a mismatch in signedness,
+                no warning.  */
+             else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
+                      || target_cmp)
+               ;
+             /* If there is a mismatch, do warn.  */
+             else if (pedantic)
+               warn_for_assignment ("pointer targets in %s differ in signedness",
+                                    errtype, funname, parmnum);
+           }
+         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,
+                it is okay to use a const or volatile function
+                where an ordinary one is wanted, but not vice-versa.  */
+             if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr))
+               warn_for_assignment ("%s makes qualified function pointer from unqualified",
+                                    errtype, funname, parmnum);
+           }
+       }
+      else
+       warn_for_assignment ("%s from incompatible pointer type",
+                            errtype, funname, parmnum);
+      return convert (type, rhs);
+    }
+  else if (codel == POINTER_TYPE && coder == ARRAY_TYPE)
+    {
+      error ("invalid use of non-lvalue array");
+      return error_mark_node;
+    }
+  else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
+    {
+      /* An explicit constant 0 can convert to a pointer,
+        or one that results from arithmetic, even including
+        a cast to integer type.  */
+      if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
+         &&
+         ! (TREE_CODE (rhs) == NOP_EXPR
+            && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
+            && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
+            && integer_zerop (TREE_OPERAND (rhs, 0))))
+         warn_for_assignment ("%s makes pointer from integer without a cast",
+                              errtype, funname, parmnum);
 
-      if (TREE_CODE (type) == POINTER_TYPE
-         && TREE_CODE (otype) == INTEGER_TYPE
-         && TYPE_PRECISION (type) != TYPE_PRECISION (otype)
-         /* Don't warn about converting any constant.  */
-         && !TREE_CONSTANT (value))
-       warning ("cast to pointer from integer of different size");
+      return convert (type, rhs);
+    }
+  else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
+    {
+      warn_for_assignment ("%s makes integer from pointer without a cast",
+                          errtype, funname, parmnum);
+      return convert (type, rhs);
+    }
+  else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
+    return convert (type, rhs);
 
-      if (TREE_CODE (type) == POINTER_TYPE
-         && TREE_CODE (otype) == POINTER_TYPE
-         && TREE_CODE (expr) == ADDR_EXPR
-         && DECL_P (TREE_OPERAND (expr, 0))
-         && flag_strict_aliasing && warn_strict_aliasing
-         && !VOID_TYPE_P (TREE_TYPE (type)))
+  if (!errtype)
+    {
+      if (funname)
        {
-         /* Casting the address of a decl to non void pointer. Warn
-            if the cast breaks type based aliasing.  */
-         if (!COMPLETE_TYPE_P (TREE_TYPE (type)))
-           warning ("type-punning to incomplete type might break strict-aliasing rules");
-         else if (!alias_sets_conflict_p
-                  (get_alias_set (TREE_TYPE (TREE_OPERAND (expr, 0))),
-                   get_alias_set (TREE_TYPE (type))))
-           warning ("dereferencing type-punned pointer will break strict-aliasing rules");
-       }
-
-      ovalue = value;
-      /* Replace a nonvolatile const static variable with its value.  */
-      if (optimize && TREE_CODE (value) == VAR_DECL)
-       value = decl_constant_value (value);
-      value = convert (type, value);
+         tree selector = objc_message_selector ();
 
-      /* Ignore any integer overflow caused by the cast.  */
-      if (TREE_CODE (value) == INTEGER_CST)
-       {
-         TREE_OVERFLOW (value) = TREE_OVERFLOW (ovalue);
-         TREE_CONSTANT_OVERFLOW (value) = TREE_CONSTANT_OVERFLOW (ovalue);
+         if (selector && parmnum > 2)
+           error ("incompatible type for argument %d of `%s'",
+                  parmnum - 2, IDENTIFIER_POINTER (selector));
+         else
+           error ("incompatible type for argument %d of `%s'",
+                  parmnum, IDENTIFIER_POINTER (funname));
        }
+      else
+       error ("incompatible type for argument %d of indirect function call",
+              parmnum);
     }
+  else
+    error ("incompatible types in %s", errtype);
 
-  /* Pedantically, don't let (void *) (FOO *) 0 be a null pointer constant.  */
-  if (pedantic && TREE_CODE (value) == INTEGER_CST
-      && TREE_CODE (expr) == INTEGER_CST
-      && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)
-    value = non_lvalue (value);
-
-  /* If pedantic, don't let a cast be an lvalue.  */
-  if (value == expr && pedantic)
-    value = non_lvalue (value);
-
-  return value;
+  return error_mark_node;
 }
 
-/* Interpret a cast of expression EXPR to type TYPE.  */
+/* Convert VALUE for assignment into inlined parameter PARM.  ARGNUM
+   is used for error and waring reporting and indicates which argument
+   is being processed.  */
+
 tree
-c_cast_expr (tree type, tree expr)
+c_convert_parm_for_inlining (tree parm, tree value, tree fn, int argnum)
 {
-  int saved_wsp = warn_strict_prototypes;
+  tree ret, type;
 
-  /* This avoids warnings about unprototyped casts on
-     integers.  E.g. "#define SIG_DFL (void(*)())0".  */
-  if (TREE_CODE (expr) == INTEGER_CST)
-    warn_strict_prototypes = 0;
-  type = groktypename (type);
-  warn_strict_prototypes = saved_wsp;
+  /* If FN was prototyped, the value has been converted already
+     in convert_arguments.  */
+  if (! value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
+    return value;
 
-  return build_c_cast (type, expr);
+  type = TREE_TYPE (parm);
+  ret = convert_for_assignment (type, value,
+                               (char *) 0 /* arg passing  */, fn,
+                               DECL_NAME (fn), argnum);
+  if (targetm.calls.promote_prototypes (TREE_TYPE (fn))
+      && INTEGRAL_TYPE_P (type)
+      && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+    ret = default_conversion (ret);
+  return ret;
 }
 
-\f
-/* Build an assignment expression of lvalue LHS from value RHS.
-   MODIFYCODE is the code for a binary operator that we use
-   to combine the old value of LHS with RHS to get the new value.
-   Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.  */
+/* Print a warning using MSGID.
+   It gets OPNAME as its one parameter.
+   if OPNAME is null and ARGNUM is 0, it is replaced by "passing arg of `FUNCTION'".
+   Otherwise if OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'".
+   FUNCTION and ARGNUM are handled specially if we are building an
+   Objective-C selector.  */
 
-tree
-build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
+static void
+warn_for_assignment (const char *msgid, const char *opname, tree function,
+                    int argnum)
 {
-  tree result;
-  tree newrhs;
-  tree lhstype = TREE_TYPE (lhs);
-  tree olhstype = lhstype;
-
-  /* Types that aren't fully specified cannot be used in assignments.  */
-  lhs = require_complete_type (lhs);
-
-  /* Avoid duplicate error messages from operands that had errors.  */
-  if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
-    return error_mark_node;
-
-  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-  /* Do not use STRIP_NOPS here.  We do not want an enumerator
-     whose value is 0 to count as a null pointer constant.  */
-  if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
-    rhs = TREE_OPERAND (rhs, 0);
+  if (opname == 0)
+    {
+      tree selector = objc_message_selector ();
+      char * new_opname;
 
-  newrhs = rhs;
+      if (selector && argnum > 2)
+       {
+         function = selector;
+         argnum -= 2;
+       }
+      if (argnum == 0)
+       {
+         if (function)
+           {
+             /* Function name is known; supply it.  */
+             const char *const argstring = _("passing arg of `%s'");
+             new_opname = alloca (IDENTIFIER_LENGTH (function)
+                                  + strlen (argstring) + 1 + 1);
+             sprintf (new_opname, argstring,
+                      IDENTIFIER_POINTER (function));
+           }
+         else
+           {
+             /* Function name unknown (call through ptr).  */
+             const char *const argnofun = _("passing arg of pointer to function");
+             new_opname = alloca (strlen (argnofun) + 1 + 1);
+             sprintf (new_opname, argnofun);
+           }
+       }
+      else if (function)
+       {
+         /* Function name is known; supply it.  */
+         const char *const argstring = _("passing arg %d of `%s'");
+         new_opname = alloca (IDENTIFIER_LENGTH (function)
+                              + strlen (argstring) + 1 + 25 /*%d*/ + 1);
+         sprintf (new_opname, argstring, argnum,
+                  IDENTIFIER_POINTER (function));
+       }
+      else
+       {
+         /* Function name unknown (call through ptr); just give arg number.  */
+         const char *const argnofun = _("passing arg %d of pointer to function");
+         new_opname = alloca (strlen (argnofun) + 1 + 25 /*%d*/ + 1);
+         sprintf (new_opname, argnofun, argnum);
+       }
+      opname = new_opname;
+    }
+  pedwarn (msgid, opname);
+}
+\f
+/* If VALUE is a compound expr all of whose expressions are constant, then
+   return its value.  Otherwise, return error_mark_node.
 
-  /* Handle control structure constructs used as "lvalues".  */
+   This is for handling COMPOUND_EXPRs as initializer elements
+   which is allowed with a warning when -pedantic is specified.  */
 
-  switch (TREE_CODE (lhs))
+static tree
+valid_compound_expr_initializer (tree value, tree endtype)
+{
+  if (TREE_CODE (value) == COMPOUND_EXPR)
     {
-      /* Handle (a, b) used as an "lvalue".  */
-    case COMPOUND_EXPR:
-      pedantic_lvalue_warning (COMPOUND_EXPR);
-      newrhs = build_modify_expr (TREE_OPERAND (lhs, 1), modifycode, rhs);
-      if (TREE_CODE (newrhs) == ERROR_MARK)
+      if (valid_compound_expr_initializer (TREE_OPERAND (value, 0), endtype)
+         == error_mark_node)
        return error_mark_node;
-      return build (COMPOUND_EXPR, lhstype,
-                   TREE_OPERAND (lhs, 0), newrhs);
-
-      /* Handle (a ? b : c) used as an "lvalue".  */
-    case COND_EXPR:
-      pedantic_lvalue_warning (COND_EXPR);
-      rhs = save_expr (rhs);
-      {
-       /* Produce (a ? (b = rhs) : (c = rhs))
-          except that the RHS goes through a save-expr
-          so the code to compute it is only emitted once.  */
-       tree cond
-         = build_conditional_expr (TREE_OPERAND (lhs, 0),
-                                   build_modify_expr (TREE_OPERAND (lhs, 1),
-                                                      modifycode, rhs),
-                                   build_modify_expr (TREE_OPERAND (lhs, 2),
-                                                      modifycode, rhs));
-       if (TREE_CODE (cond) == ERROR_MARK)
-         return cond;
-       /* Make sure the code to compute the rhs comes out
-          before the split.  */
-       return build (COMPOUND_EXPR, TREE_TYPE (lhs),
-                     /* But cast it to void to avoid an "unused" error.  */
-                     convert (void_type_node, rhs), cond);
-      }
-    default:
-      break;
+      return valid_compound_expr_initializer (TREE_OPERAND (value, 1),
+                                             endtype);
     }
+  else if (! TREE_CONSTANT (value)
+          && ! initializer_constant_valid_p (value, endtype))
+    return error_mark_node;
+  else
+    return value;
+}
+\f
+/* Perform appropriate conversions on the initial value of a variable,
+   store it in the declaration DECL,
+   and print any error messages that are appropriate.
+   If the init is invalid, store an ERROR_MARK.  */
 
-  /* If a binary op has been requested, combine the old LHS value with the RHS
-     producing the value we should actually store into the LHS.  */
+void
+store_init_value (tree decl, tree init)
+{
+  tree value, type;
 
-  if (modifycode != NOP_EXPR)
-    {
-      lhs = stabilize_reference (lhs);
-      newrhs = build_binary_op (modifycode, lhs, rhs, 1);
-    }
+  /* If variable's type was invalidly declared, just ignore it.  */
 
-  /* Handle a cast used as an "lvalue".
-     We have already performed any binary operator using the value as cast.
-     Now convert the result to the cast type of the lhs,
-     and then true type of the lhs and store it there;
-     then convert result back to the cast type to be the value
-     of the assignment.  */
+  type = TREE_TYPE (decl);
+  if (TREE_CODE (type) == ERROR_MARK)
+    return;
 
-  switch (TREE_CODE (lhs))
-    {
-    case NOP_EXPR:
-    case CONVERT_EXPR:
-    case FLOAT_EXPR:
-    case FIX_TRUNC_EXPR:
-    case FIX_FLOOR_EXPR:
-    case FIX_ROUND_EXPR:
-    case FIX_CEIL_EXPR:
-      newrhs = default_function_array_conversion (newrhs);
-      {
-       tree inner_lhs = TREE_OPERAND (lhs, 0);
-       tree result;
-       result = build_modify_expr (inner_lhs, NOP_EXPR,
-                                   convert (TREE_TYPE (inner_lhs),
-                                            convert (lhstype, newrhs)));
-       if (TREE_CODE (result) == ERROR_MARK)
-         return result;
-       pedantic_lvalue_warning (CONVERT_EXPR);
-       return convert (TREE_TYPE (lhs), result);
-      }
+  /* Digest the specified initializer into an expression.  */
 
-    default:
-      break;
-    }
+  value = digest_init (type, init, TREE_STATIC (decl));
 
-  /* Now we have handled acceptable kinds of LHS that are not truly lvalues.
-     Reject anything strange now.  */
+  /* Store the expression if valid; else report error.  */
 
-  if (!lvalue_or_else (lhs, "invalid lvalue in assignment"))
-    return error_mark_node;
+  if (warn_traditional && !in_system_header
+      && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && ! TREE_STATIC (decl))
+    warning ("traditional C rejects automatic aggregate initialization");
 
-  /* Warn about storing in something that is `const'.  */
+  DECL_INITIAL (decl) = value;
 
-  if (TREE_READONLY (lhs) || TYPE_READONLY (lhstype)
-      || ((TREE_CODE (lhstype) == RECORD_TYPE
-          || TREE_CODE (lhstype) == UNION_TYPE)
-         && C_TYPE_FIELDS_READONLY (lhstype)))
-    readonly_warning (lhs, "assignment");
+  /* ANSI wants warnings about out-of-range constant initializers.  */
+  STRIP_TYPE_NOPS (value);
+  constant_expression_warning (value);
 
-  /* If storing into a structure or union member,
-     it has probably been given type `int'.
-     Compute the type that would go with
-     the actual amount of storage the member occupies.  */
+  /* Check if we need to set array size from compound literal size.  */
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_DOMAIN (type) == 0
+      && value != error_mark_node)
+    {
+      tree inside_init = init;
 
-  if (TREE_CODE (lhs) == COMPONENT_REF
-      && (TREE_CODE (lhstype) == INTEGER_TYPE
-         || TREE_CODE (lhstype) == BOOLEAN_TYPE
-         || TREE_CODE (lhstype) == REAL_TYPE
-         || TREE_CODE (lhstype) == ENUMERAL_TYPE))
-    lhstype = TREE_TYPE (get_unwidened (lhs, 0));
+      if (TREE_CODE (init) == NON_LVALUE_EXPR)
+       inside_init = TREE_OPERAND (init, 0);
+      inside_init = fold (inside_init);
+
+      if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
+       {
+         tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
+
+         if (TYPE_DOMAIN (TREE_TYPE (decl)))
+           {
+             /* For int foo[] = (int [3]){1}; we need to set array size
+                now since later on array initializer will be just the
+                brace enclosed list of the compound literal.  */
+             TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (decl));
+             layout_type (type);
+             layout_decl (decl, 0);
+           }
+       }
+    }
+}
+\f
+/* Methods for storing and printing names for error messages.  */
 
-  /* If storing in a field that is in actuality a short or narrower than one,
-     we must store in the field in its actual type.  */
+/* Implement a spelling stack that allows components of a name to be pushed
+   and popped.  Each element on the stack is this structure.  */
 
-  if (lhstype != TREE_TYPE (lhs))
+struct spelling
+{
+  int kind;
+  union
     {
-      lhs = copy_node (lhs);
-      TREE_TYPE (lhs) = lhstype;
-    }
+      int i;
+      const char *s;
+    } u;
+};
 
-  /* Convert new value to destination type.  */
+#define SPELLING_STRING 1
+#define SPELLING_MEMBER 2
+#define SPELLING_BOUNDS 3
 
-  newrhs = convert_for_assignment (lhstype, newrhs, _("assignment"),
-                                  NULL_TREE, NULL_TREE, 0);
-  if (TREE_CODE (newrhs) == ERROR_MARK)
-    return error_mark_node;
+static struct spelling *spelling;      /* Next stack element (unused).  */
+static struct spelling *spelling_base; /* Spelling stack base.  */
+static int spelling_size;              /* Size of the spelling stack.  */
 
-  /* Scan operands */
+/* Macros to save and restore the spelling stack around push_... functions.
+   Alternative to SAVE_SPELLING_STACK.  */
 
-  result = build (MODIFY_EXPR, lhstype, lhs, newrhs);
-  TREE_SIDE_EFFECTS (result) = 1;
+#define SPELLING_DEPTH() (spelling - spelling_base)
+#define RESTORE_SPELLING_DEPTH(DEPTH) (spelling = spelling_base + (DEPTH))
 
-  /* If we got the LHS in a different type for storing in,
-     convert the result back to the nominal type of LHS
-     so that the value we return always has the same type
-     as the LHS argument.  */
+/* Push an element on the spelling stack with type KIND and assign VALUE
+   to MEMBER.  */
 
-  if (olhstype == TREE_TYPE (result))
-    return result;
-  return convert_for_assignment (olhstype, result, _("assignment"),
-                                NULL_TREE, NULL_TREE, 0);
+#define PUSH_SPELLING(KIND, VALUE, MEMBER)                             \
+{                                                                      \
+  int depth = SPELLING_DEPTH ();                                       \
+                                                                       \
+  if (depth >= spelling_size)                                          \
+    {                                                                  \
+      spelling_size += 10;                                             \
+      if (spelling_base == 0)                                          \
+       spelling_base = xmalloc (spelling_size * sizeof (struct spelling)); \
+      else                                                             \
+        spelling_base = xrealloc (spelling_base,               \
+                                 spelling_size * sizeof (struct spelling)); \
+      RESTORE_SPELLING_DEPTH (depth);                                  \
+    }                                                                  \
+                                                                       \
+  spelling->kind = (KIND);                                             \
+  spelling->MEMBER = (VALUE);                                          \
+  spelling++;                                                          \
 }
-\f
-/* Convert value RHS to type TYPE as preparation for an assignment
-   to an lvalue of type TYPE.
-   The real work of conversion is done by `convert'.
-   The purpose of this function is to generate error messages
-   for assignments that are not allowed in C.
-   ERRTYPE is a string to use in error messages:
-   "assignment", "return", etc.  If it is null, this is parameter passing
-   for a function call (and different error messages are output).
 
-   FUNNAME is the name of the function being called,
-   as an IDENTIFIER_NODE, or null.
-   PARMNUM is the number of the argument, for printing in error messages.  */
+/* Push STRING on the stack.  Printed literally.  */
 
-static tree
-convert_for_assignment (tree type, tree rhs, const char *errtype, tree fundecl, tree funname, int parmnum)
+static void
+push_string (const char *string)
 {
-  enum tree_code codel = TREE_CODE (type);
-  tree rhstype;
-  enum tree_code coder;
+  PUSH_SPELLING (SPELLING_STRING, string, u.s);
+}
 
-  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-  /* Do not use STRIP_NOPS here.  We do not want an enumerator
-     whose value is 0 to count as a null pointer constant.  */
-  if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
-    rhs = TREE_OPERAND (rhs, 0);
+/* Push a member name on the stack.  Printed as '.' STRING.  */
 
-  if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
-      || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
-    rhs = default_conversion (rhs);
-  else if (optimize && TREE_CODE (rhs) == VAR_DECL)
-    rhs = decl_constant_value_for_broken_optimization (rhs);
+static void
+push_member_name (tree decl)
+{
+  const char *const string
+    = DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : "<anonymous>";
+  PUSH_SPELLING (SPELLING_MEMBER, string, u.s);
+}
 
-  rhstype = TREE_TYPE (rhs);
-  coder = TREE_CODE (rhstype);
+/* Push an array bounds on the stack.  Printed as [BOUNDS].  */
 
-  if (coder == ERROR_MARK)
-    return error_mark_node;
+static void
+push_array_bounds (int bounds)
+{
+  PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i);
+}
 
-  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
-    {
-      overflow_warning (rhs);
-      /* Check for Objective-C protocols.  This will automatically
-        issue a warning if there are protocol violations.  No need to
-        use the return value.  */
-      if (c_dialect_objc ())
-       objc_comptypes (type, rhstype, 0);
-      return rhs;
-    }
+/* Compute the maximum size in bytes of the printed spelling.  */
 
-  if (coder == VOID_TYPE)
+static int
+spelling_length (void)
+{
+  int size = 0;
+  struct spelling *p;
+
+  for (p = spelling_base; p < spelling; p++)
     {
-      error ("void value not ignored as it ought to be");
-      return error_mark_node;
+      if (p->kind == SPELLING_BOUNDS)
+       size += 25;
+      else
+       size += strlen (p->u.s) + 1;
     }
-  /* A type converts to a reference to it.
-     This code doesn't fully support references, it's just for the
-     special case of va_start and va_copy.  */
-  if (codel == REFERENCE_TYPE
-      && comptypes (TREE_TYPE (type), TREE_TYPE (rhs)) == 1)
-    {
-      if (!lvalue_p (rhs))
-       {
-         error ("cannot pass rvalue to reference parameter");
-         return error_mark_node;
-       }
-      if (!c_mark_addressable (rhs))
-       return error_mark_node;
-      rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs);
 
-      /* We already know that these two types are compatible, but they
-        may not be exactly identical.  In fact, `TREE_TYPE (type)' is
-        likely to be __builtin_va_list and `TREE_TYPE (rhs)' is
-        likely to be va_list, a typedef to __builtin_va_list, which
-        is different enough that it will cause problems later.  */
-      if (TREE_TYPE (TREE_TYPE (rhs)) != TREE_TYPE (type))
-       rhs = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (type)), rhs);
+  return size;
+}
 
-      rhs = build1 (NOP_EXPR, type, rhs);
-      return rhs;
-    }
-  /* Some types can interconvert without explicit casts.  */
-  else if (codel == VECTOR_TYPE && coder == VECTOR_TYPE
-          && ((*targetm.vector_opaque_p) (type)
-              || (*targetm.vector_opaque_p) (rhstype)))
-    return convert (type, rhs);
-  /* Arithmetic types all interconvert, and enum is treated like int.  */
-  else if ((codel == INTEGER_TYPE || codel == REAL_TYPE
-           || codel == ENUMERAL_TYPE || codel == COMPLEX_TYPE
-           || codel == BOOLEAN_TYPE)
-          && (coder == INTEGER_TYPE || coder == REAL_TYPE
-              || coder == ENUMERAL_TYPE || coder == COMPLEX_TYPE
-              || coder == BOOLEAN_TYPE))
-    return convert_and_check (type, rhs);
+/* Print the spelling to BUFFER and return it.  */
 
-  /* Conversion to a transparent union from its member types.
-     This applies only to function arguments.  */
-  else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype)
-    {
-      tree memb_types;
-      tree marginal_memb_type = 0;
+static char *
+print_spelling (char *buffer)
+{
+  char *d = buffer;
+  struct spelling *p;
 
-      for (memb_types = TYPE_FIELDS (type); memb_types;
-          memb_types = TREE_CHAIN (memb_types))
-       {
-         tree memb_type = TREE_TYPE (memb_types);
+  for (p = spelling_base; p < spelling; p++)
+    if (p->kind == SPELLING_BOUNDS)
+      {
+       sprintf (d, "[%d]", p->u.i);
+       d += strlen (d);
+      }
+    else
+      {
+       const char *s;
+       if (p->kind == SPELLING_MEMBER)
+         *d++ = '.';
+       for (s = p->u.s; (*d = *s++); d++)
+         ;
+      }
+  *d++ = '\0';
+  return buffer;
+}
 
-         if (comptypes (TYPE_MAIN_VARIANT (memb_type),
-                        TYPE_MAIN_VARIANT (rhstype)))
-           break;
+/* Issue an error message for a bad initializer component.
+   MSGID identifies the message.
+   The component name is taken from the spelling stack.  */
 
-         if (TREE_CODE (memb_type) != POINTER_TYPE)
-           continue;
+void
+error_init (const char *msgid)
+{
+  char *ofwhat;
 
-         if (coder == POINTER_TYPE)
-           {
-             tree ttl = TREE_TYPE (memb_type);
-             tree ttr = TREE_TYPE (rhstype);
+  error ("%s", _(msgid));
+  ofwhat = print_spelling (alloca (spelling_length () + 1));
+  if (*ofwhat)
+    error ("(near initialization for `%s')", ofwhat);
+}
 
-             /* 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.  */
-             if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
-                 || comp_target_types (memb_type, rhstype, 0))
-               {
-                 /* If this type won't generate any warnings, use it.  */
-                 if (TYPE_QUALS (ttl) == TYPE_QUALS (ttr)
-                     || ((TREE_CODE (ttr) == FUNCTION_TYPE
-                          && TREE_CODE (ttl) == FUNCTION_TYPE)
-                         ? ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
-                            == TYPE_QUALS (ttr))
-                         : ((TYPE_QUALS (ttl) | TYPE_QUALS (ttr))
-                            == TYPE_QUALS (ttl))))
-                   break;
+/* Issue a pedantic warning for a bad initializer component.
+   MSGID identifies the message.
+   The component name is taken from the spelling stack.  */
+
+void
+pedwarn_init (const char *msgid)
+{
+  char *ofwhat;
+
+  pedwarn ("%s", _(msgid));
+  ofwhat = print_spelling (alloca (spelling_length () + 1));
+  if (*ofwhat)
+    pedwarn ("(near initialization for `%s')", ofwhat);
+}
 
-                 /* Keep looking for a better type, but remember this one.  */
-                 if (! marginal_memb_type)
-                   marginal_memb_type = memb_type;
-               }
-           }
+/* Issue a warning for a bad initializer component.
+   MSGID identifies the message.
+   The component name is taken from the spelling stack.  */
 
-         /* Can convert integer zero to any pointer type.  */
-         if (integer_zerop (rhs)
-             || (TREE_CODE (rhs) == NOP_EXPR
-                 && integer_zerop (TREE_OPERAND (rhs, 0))))
-           {
-             rhs = null_pointer_node;
-             break;
-           }
-       }
+static void
+warning_init (const char *msgid)
+{
+  char *ofwhat;
 
-      if (memb_types || marginal_memb_type)
-       {
-         if (! memb_types)
-           {
-             /* We have only a marginally acceptable member type;
-                it needs a warning.  */
-             tree ttl = TREE_TYPE (marginal_memb_type);
-             tree ttr = TREE_TYPE (rhstype);
+  warning ("%s", _(msgid));
+  ofwhat = print_spelling (alloca (spelling_length () + 1));
+  if (*ofwhat)
+    warning ("(near initialization for `%s')", ofwhat);
+}
+\f
+/* Digest the parser output INIT as an initializer for type TYPE.
+   Return a C expression of type TYPE to represent the initial value.
 
-             /* 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)
-               {
-                 /* 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_QUALS (ttl) & ~TYPE_QUALS (ttr))
-                   warn_for_assignment ("%s makes qualified function pointer from unqualified",
-                                        errtype, funname, parmnum);
-               }
-             else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
-               warn_for_assignment ("%s discards qualifiers from pointer target type",
-                                    errtype, funname,
-                                    parmnum);
-           }
+   REQUIRE_CONSTANT requests an error if non-constant initializers or
+   elements are seen.  */
 
-         if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl))
-           pedwarn ("ISO C prohibits argument conversion to union type");
+static tree
+digest_init (tree type, tree init, int require_constant)
+{
+  enum tree_code code = TREE_CODE (type);
+  tree inside_init = init;
 
-         return build1 (NOP_EXPR, type, rhs);
-       }
-    }
+  if (type == error_mark_node
+      || init == error_mark_node
+      || TREE_TYPE (init) == error_mark_node)
+    return error_mark_node;
 
-  /* Conversions among pointers */
-  else if ((codel == POINTER_TYPE || codel == REFERENCE_TYPE)
-          && (coder == codel))
-    {
-      tree ttl = TREE_TYPE (type);
-      tree ttr = TREE_TYPE (rhstype);
-      bool is_opaque_pointer;
+  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
+  /* Do not use STRIP_NOPS here.  We do not want an enumerator
+     whose value is 0 to count as a null pointer constant.  */
+  if (TREE_CODE (init) == NON_LVALUE_EXPR)
+    inside_init = TREE_OPERAND (init, 0);
 
-      /* Opaque pointers are treated like void pointers.  */
-      is_opaque_pointer = ((*targetm.vector_opaque_p) (type)
-                           || (*targetm.vector_opaque_p) (rhstype))
-        && TREE_CODE (ttl) == VECTOR_TYPE
-        && TREE_CODE (ttr) == VECTOR_TYPE;
+  inside_init = fold (inside_init);
 
-      /* 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.  */
-      if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
-         || comp_target_types (type, rhstype, 0)
-         || is_opaque_pointer
-         || (c_common_unsigned_type (TYPE_MAIN_VARIANT (ttl))
-             == c_common_unsigned_type (TYPE_MAIN_VARIANT (ttr))))
+  /* Initialization of an array of chars from a string constant
+     optionally enclosed in braces.  */
+
+  if (code == ARRAY_TYPE)
+    {
+      tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+      if ((typ1 == char_type_node
+          || typ1 == signed_char_type_node
+          || typ1 == unsigned_char_type_node
+          || typ1 == unsigned_wchar_type_node
+          || typ1 == signed_wchar_type_node)
+         && ((inside_init && TREE_CODE (inside_init) == STRING_CST)))
        {
-         if (pedantic
-             && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
-                 ||
-                 (VOID_TYPE_P (ttr)
-                  /* Check TREE_CODE to catch cases like (void *) (char *) 0
-                     which are not ANSI null ptr constants.  */
-                  && (!integer_zerop (rhs) || TREE_CODE (rhs) == NOP_EXPR)
-                  && TREE_CODE (ttl) == FUNCTION_TYPE)))
-           warn_for_assignment ("ISO C forbids %s between function pointer and `void *'",
-                                errtype, 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)
+         if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+                        TYPE_MAIN_VARIANT (type), COMPARE_STRICT))
+           return inside_init;
+
+         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
+              != char_type_node)
+             && TYPE_PRECISION (typ1) == TYPE_PRECISION (char_type_node))
            {
-             if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
-               warn_for_assignment ("%s discards qualifiers from pointer target type",
-                                    errtype, funname, parmnum);
-             /* If this is not a case of ignoring a mismatch in signedness,
-                no warning.  */
-             else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
-                      || comp_target_types (type, rhstype, 0))
-               ;
-             /* If there is a mismatch, do warn.  */
-             else if (pedantic)
-               warn_for_assignment ("pointer targets in %s differ in signedness",
-                                    errtype, funname, parmnum);
+             error_init ("char-array initialized from wide string");
+             return error_mark_node;
            }
-         else if (TREE_CODE (ttl) == FUNCTION_TYPE
-                  && TREE_CODE (ttr) == FUNCTION_TYPE)
+         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
+              == char_type_node)
+             && TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node))
            {
-             /* 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_QUALS (ttl) & ~TYPE_QUALS (ttr))
-               warn_for_assignment ("%s makes qualified function pointer from unqualified",
-                                    errtype, funname, parmnum);
+             error_init ("int-array initialized from non-wide string");
+             return error_mark_node;
            }
-       }
-      else
-       warn_for_assignment ("%s from incompatible pointer type",
-                            errtype, funname, parmnum);
-      return convert (type, rhs);
-    }
-  else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
-    {
-      /* An explicit constant 0 can convert to a pointer,
-        or one that results from arithmetic, even including
-        a cast to integer type.  */
-      if (! (TREE_CODE (rhs) == INTEGER_CST && integer_zerop (rhs))
-         &&
-         ! (TREE_CODE (rhs) == NOP_EXPR
-            && TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE
-            && TREE_CODE (TREE_OPERAND (rhs, 0)) == INTEGER_CST
-            && integer_zerop (TREE_OPERAND (rhs, 0))))
-       {
-         warn_for_assignment ("%s makes pointer from integer without a cast",
-                              errtype, funname, parmnum);
-         return convert (type, rhs);
-       }
-      return null_pointer_node;
-    }
-  else if (codel == INTEGER_TYPE && coder == POINTER_TYPE)
-    {
-      warn_for_assignment ("%s makes integer from pointer without a cast",
-                          errtype, funname, parmnum);
-      return convert (type, rhs);
-    }
-  else if (codel == BOOLEAN_TYPE && coder == POINTER_TYPE)
-    return convert (type, rhs);
 
-  if (!errtype)
-    {
-      if (funname)
-       {
-         tree selector = objc_message_selector ();
+         TREE_TYPE (inside_init) = type;
+         if (TYPE_DOMAIN (type) != 0
+             && TYPE_SIZE (type) != 0
+             && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+             /* Subtract 1 (or sizeof (wchar_t))
+                because it's ok to ignore the terminating null char
+                that is counted in the length of the constant.  */
+             && 0 > compare_tree_int (TYPE_SIZE_UNIT (type),
+                                      TREE_STRING_LENGTH (inside_init)
+                                      - ((TYPE_PRECISION (typ1)
+                                          != TYPE_PRECISION (char_type_node))
+                                         ? (TYPE_PRECISION (wchar_type_node)
+                                            / BITS_PER_UNIT)
+                                         : 1)))
+           pedwarn_init ("initializer-string for array of chars is too long");
 
-         if (selector && parmnum > 2)
-           error ("incompatible type for argument %d of `%s'",
-                  parmnum - 2, IDENTIFIER_POINTER (selector));
-         else
-           error ("incompatible type for argument %d of `%s'",
-                  parmnum, IDENTIFIER_POINTER (funname));
+         return inside_init;
        }
-      else
-       error ("incompatible type for argument %d of indirect function call",
-              parmnum);
     }
-  else
-    error ("incompatible types in %s", errtype);
-
-  return error_mark_node;
-}
-
-/* Convert VALUE for assignment into inlined parameter PARM.  */
-
-tree
-c_convert_parm_for_inlining (tree parm, tree value, tree fn)
-{
-  tree ret, type;
-
-  /* If FN was prototyped, the value has been converted already
-     in convert_arguments.  */
-  if (! value || TYPE_ARG_TYPES (TREE_TYPE (fn)))
-    return value;
 
-  type = TREE_TYPE (parm);
-  ret = convert_for_assignment (type, value,
-                               (char *) 0 /* arg passing  */, fn,
-                               DECL_NAME (fn), 0);
-  if (PROMOTE_PROTOTYPES
-      && INTEGRAL_TYPE_P (type)
-      && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
-    ret = default_conversion (ret);
-  return ret;
-}
+  /* Build a VECTOR_CST from a *constant* vector constructor.  If the
+     vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
+     below and handle as a constructor.  */
+    if (code == VECTOR_TYPE
+        && comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT)
+        && TREE_CONSTANT (inside_init))
+      {
+       if (TREE_CODE (inside_init) == VECTOR_CST
+           && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+                         TYPE_MAIN_VARIANT (type),
+                         COMPARE_STRICT))
+         return inside_init;
+       else
+         return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
+      }
 
-/* Print a warning using MSGID.
-   It gets OPNAME as its one parameter.
-   if OPNAME is null and ARGNUM is 0, it is replaced by "passing arg of `FUNCTION'".
-   Otherwise if OPNAME is null, it is replaced by "passing arg ARGNUM of `FUNCTION'".
-   FUNCTION and ARGNUM are handled specially if we are building an
-   Objective-C selector.  */
+  /* Any type can be initialized
+     from an expression of the same type, optionally with braces.  */
 
-static void
-warn_for_assignment (const char *msgid, const char *opname, tree function, int argnum)
-{
-  if (opname == 0)
+  if (inside_init && TREE_TYPE (inside_init) != 0
+      && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
+                    TYPE_MAIN_VARIANT (type), COMPARE_STRICT)
+         || (code == ARRAY_TYPE
+             && comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT))
+         || (code == VECTOR_TYPE
+             && comptypes (TREE_TYPE (inside_init), type, COMPARE_STRICT))
+         || (code == POINTER_TYPE
+             && TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
+             && comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
+                           TREE_TYPE (type), COMPARE_STRICT))
+         || (code == POINTER_TYPE
+             && TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE
+             && comptypes (TREE_TYPE (inside_init),
+                           TREE_TYPE (type), COMPARE_STRICT))))
     {
-      tree selector = objc_message_selector ();
-      char * new_opname;
+      if (code == POINTER_TYPE)
+       {
+         inside_init = default_function_array_conversion (inside_init);
 
-      if (selector && argnum > 2)
+         if (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE)
+           {
+             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
+          conversion.  */
+       inside_init = convert (type, inside_init);
+
+      if (require_constant && !flag_isoc99
+         && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
        {
-         function = selector;
-         argnum -= 2;
+         /* As an extension, allow initializing objects with static storage
+            duration with compound literals (which are then treated just as
+            the brace enclosed list they contain).  */
+         tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
+         inside_init = DECL_INITIAL (decl);
        }
-      if (argnum == 0)
+
+      if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
+         && TREE_CODE (inside_init) != CONSTRUCTOR)
        {
-         if (function)
-           {
-             /* Function name is known; supply it.  */
-             const char *const argstring = _("passing arg of `%s'");
-             new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
-                                           + strlen (argstring) + 1
-                                           + 1);
-             sprintf (new_opname, argstring,
-                      IDENTIFIER_POINTER (function));
-           }
-         else
-           {
-             /* Function name unknown (call through ptr).  */
-             const char *const argnofun = _("passing arg of pointer to function");
-             new_opname = (char *) alloca (strlen (argnofun) + 1 + 1);
-             sprintf (new_opname, argnofun);
-           }
+         error_init ("array initialized from non-constant array expression");
+         return error_mark_node;
        }
-      else if (function)
+
+      if (optimize && TREE_CODE (inside_init) == VAR_DECL)
+       inside_init = decl_constant_value_for_broken_optimization (inside_init);
+
+      /* Compound expressions can only occur here if -pedantic or
+        -pedantic-errors is specified.  In the later case, we always want
+        an error.  In the former case, we simply want a warning.  */
+      if (require_constant && pedantic
+         && TREE_CODE (inside_init) == COMPOUND_EXPR)
        {
-         /* Function name is known; supply it.  */
-         const char *const argstring = _("passing arg %d of `%s'");
-         new_opname = (char *) alloca (IDENTIFIER_LENGTH (function)
-                                       + strlen (argstring) + 1 + 25
-                                       /*%d*/ + 1);
-         sprintf (new_opname, argstring, argnum,
-                  IDENTIFIER_POINTER (function));
+         inside_init
+           = valid_compound_expr_initializer (inside_init,
+                                              TREE_TYPE (inside_init));
+         if (inside_init == error_mark_node)
+           error_init ("initializer element is not constant");
+         else
+           pedwarn_init ("initializer element is not constant");
+         if (flag_pedantic_errors)
+           inside_init = error_mark_node;
        }
-      else
+      else if (require_constant
+              && (!TREE_CONSTANT (inside_init)
+                  /* This test catches things like `7 / 0' which
+                     result in an expression for which TREE_CONSTANT
+                     is true, but which is not actually something
+                     that is a legal constant.  We really should not
+                     be using this function, because it is a part of
+                     the back-end.  Instead, the expression should
+                     already have been turned into ERROR_MARK_NODE.  */
+                  || !initializer_constant_valid_p (inside_init,
+                                                    TREE_TYPE (inside_init))))
        {
-         /* Function name unknown (call through ptr); just give arg number.  */
-         const char *const argnofun = _("passing arg %d of pointer to function");
-         new_opname = (char *) alloca (strlen (argnofun) + 1 + 25 /*%d*/ + 1);
-         sprintf (new_opname, argnofun, argnum);
+         error_init ("initializer element is not constant");
+         inside_init = error_mark_node;
        }
-      opname = new_opname;
-    }
-  pedwarn (msgid, opname);
-}
-\f
-/* If VALUE is a compound expr all of whose expressions are constant, then
-   return its value.  Otherwise, return error_mark_node.
-
-   This is for handling COMPOUND_EXPRs as initializer elements
-   which is allowed with a warning when -pedantic is specified.  */
 
-static tree
-valid_compound_expr_initializer (tree value, tree endtype)
-{
-  if (TREE_CODE (value) == COMPOUND_EXPR)
-    {
-      if (valid_compound_expr_initializer (TREE_OPERAND (value, 0), endtype)
-         == error_mark_node)
-       return error_mark_node;
-      return valid_compound_expr_initializer (TREE_OPERAND (value, 1),
-                                             endtype);
+      return inside_init;
     }
-  else if (! TREE_CONSTANT (value)
-          && ! initializer_constant_valid_p (value, endtype))
-    return error_mark_node;
-  else
-    return value;
-}
-\f
-/* Perform appropriate conversions on the initial value of a variable,
-   store it in the declaration DECL,
-   and print any error messages that are appropriate.
-   If the init is invalid, store an ERROR_MARK.  */
-
-void
-store_init_value (tree decl, tree init)
-{
-  tree value, type;
 
-  /* If variable's type was invalidly declared, just ignore it.  */
-
-  type = TREE_TYPE (decl);
-  if (TREE_CODE (type) == ERROR_MARK)
-    return;
+  /* Handle scalar types, including conversions.  */
 
-  /* Digest the specified initializer into an expression.  */
+  if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
+      || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE)
+    {
+      /* Note that convert_for_assignment calls default_conversion
+        for arrays and functions.  We must not call it in the
+        case where inside_init is a null pointer constant.  */
+      inside_init
+       = convert_for_assignment (type, init, _("initialization"),
+                                 NULL_TREE, NULL_TREE, 0);
 
-  value = digest_init (type, init, TREE_STATIC (decl));
+      if (require_constant && ! TREE_CONSTANT (inside_init))
+       {
+         error_init ("initializer element is not constant");
+         inside_init = error_mark_node;
+       }
+      else if (require_constant
+              && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
+       {
+         error_init ("initializer element is not computable at load time");
+         inside_init = error_mark_node;
+       }
 
-  /* Store the expression if valid; else report error.  */
+      return inside_init;
+    }
 
-  if (warn_traditional && !in_system_header
-      && AGGREGATE_TYPE_P (TREE_TYPE (decl)) && ! TREE_STATIC (decl))
-    warning ("traditional C rejects automatic aggregate initialization");
+  /* Come here only for records and arrays.  */
 
-  DECL_INITIAL (decl) = value;
+  if (COMPLETE_TYPE_P (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+    {
+      error_init ("variable-sized object may not be initialized");
+      return error_mark_node;
+    }
 
-  /* ANSI wants warnings about out-of-range constant initializers.  */
-  STRIP_TYPE_NOPS (value);
-  constant_expression_warning (value);
+  error_init ("invalid initializer");
+  return error_mark_node;
+}
+\f
+/* Handle initializers that use braces.  */
 
-  /* Check if we need to set array size from compound literal size.  */
-  if (TREE_CODE (type) == ARRAY_TYPE
-      && TYPE_DOMAIN (type) == 0
-      && value != error_mark_node)
-    {
-      tree inside_init = init;
+/* Type of object we are accumulating a constructor for.
+   This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE.  */
+static tree constructor_type;
 
-      if (TREE_CODE (init) == NON_LVALUE_EXPR)
-       inside_init = TREE_OPERAND (init, 0);
-      inside_init = fold (inside_init);
+/* For a RECORD_TYPE or UNION_TYPE, this is the chain of fields
+   left to fill.  */
+static tree constructor_fields;
 
-      if (TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
-       {
-         tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
+/* For an ARRAY_TYPE, this is the specified index
+   at which to store the next element we get.  */
+static tree constructor_index;
 
-         if (TYPE_DOMAIN (TREE_TYPE (decl)))
-           {
-             /* For int foo[] = (int [3]){1}; we need to set array size
-                now since later on array initializer will be just the
-                brace enclosed list of the compound literal.  */
-             TYPE_DOMAIN (type) = TYPE_DOMAIN (TREE_TYPE (decl));
-             layout_type (type);
-             layout_decl (decl, 0);
-           }
-       }
-    }
-}
-\f
-/* Methods for storing and printing names for error messages.  */
+/* For an ARRAY_TYPE, this is the maximum index.  */
+static tree constructor_max_index;
 
-/* Implement a spelling stack that allows components of a name to be pushed
-   and popped.  Each element on the stack is this structure.  */
+/* For a RECORD_TYPE, this is the first field not yet written out.  */
+static tree constructor_unfilled_fields;
 
-struct spelling
-{
-  int kind;
-  union
-    {
-      int i;
-      const char *s;
-    } u;
-};
+/* For an ARRAY_TYPE, this is the index of the first element
+   not yet written out.  */
+static tree constructor_unfilled_index;
 
-#define SPELLING_STRING 1
-#define SPELLING_MEMBER 2
-#define SPELLING_BOUNDS 3
+/* In a RECORD_TYPE, the byte index of the next consecutive field.
+   This is so we can generate gaps between fields, when appropriate.  */
+static tree constructor_bit_index;
 
-static struct spelling *spelling;      /* Next stack element (unused).  */
-static struct spelling *spelling_base; /* Spelling stack base.  */
-static int spelling_size;              /* Size of the spelling stack.  */
+/* 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;
 
-/* Macros to save and restore the spelling stack around push_... functions.
-   Alternative to SAVE_SPELLING_STACK.  */
+/* 1 if constructor should be incrementally stored into a constructor chain,
+   0 if all the elements should be kept in AVL tree.  */
+static int constructor_incremental;
 
-#define SPELLING_DEPTH() (spelling - spelling_base)
-#define RESTORE_SPELLING_DEPTH(DEPTH) (spelling = spelling_base + (DEPTH))
+/* 1 if so far this constructor's elements are all compile-time constants.  */
+static int constructor_constant;
 
-/* Push an element on the spelling stack with type KIND and assign VALUE
-   to MEMBER.  */
+/* 1 if so far this constructor's elements are all valid address constants.  */
+static int constructor_simple;
 
-#define PUSH_SPELLING(KIND, VALUE, MEMBER)                             \
-{                                                                      \
-  int depth = SPELLING_DEPTH ();                                       \
-                                                                       \
-  if (depth >= spelling_size)                                          \
-    {                                                                  \
-      spelling_size += 10;                                             \
-      if (spelling_base == 0)                                          \
-       spelling_base                                                   \
-         = (struct spelling *) xmalloc (spelling_size * sizeof (struct spelling));     \
-      else                                                             \
-        spelling_base                                                  \
-         = (struct spelling *) xrealloc (spelling_base,                \
-                                         spelling_size * sizeof (struct spelling));    \
-      RESTORE_SPELLING_DEPTH (depth);                                  \
-    }                                                                  \
-                                                                       \
-  spelling->kind = (KIND);                                             \
-  spelling->MEMBER = (VALUE);                                          \
-  spelling++;                                                          \
-}
+/* 1 if this constructor is erroneous so far.  */
+static int constructor_erroneous;
 
-/* Push STRING on the stack.  Printed literally.  */
+/* Structure for managing pending initializer elements, organized as an
+   AVL tree.  */
 
-static void
-push_string (const char *string)
+struct init_node
 {
-  PUSH_SPELLING (SPELLING_STRING, string, u.s);
-}
+  struct init_node *left, *right;
+  struct init_node *parent;
+  int balance;
+  tree purpose;
+  tree value;
+};
 
-/* Push a member name on the stack.  Printed as '.' STRING.  */
+/* Tree of pending elements at this constructor level.
+   These are elements encountered out of order
+   which belong at places we haven't reached yet in actually
+   writing the output.
+   Will never hold tree nodes across GC runs.  */
+static struct init_node *constructor_pending_elts;
 
-static void
-push_member_name (tree decl)
-{
-  const char *const string
-    = DECL_NAME (decl) ? IDENTIFIER_POINTER (DECL_NAME (decl)) : "<anonymous>";
-  PUSH_SPELLING (SPELLING_MEMBER, string, u.s);
-}
+/* The SPELLING_DEPTH of this constructor.  */
+static int constructor_depth;
 
-/* Push an array bounds on the stack.  Printed as [BOUNDS].  */
+/* 0 if implicitly pushing constructor levels is allowed.  */
+int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages.  */
 
-static void
-push_array_bounds (int bounds)
-{
-  PUSH_SPELLING (SPELLING_BOUNDS, bounds, u.i);
-}
+static int require_constant_value;
+static int require_constant_elements;
 
-/* Compute the maximum size in bytes of the printed spelling.  */
+/* DECL node for which an initializer is being read.
+   0 means we are reading a constructor expression
+   such as (struct foo) {...}.  */
+static tree constructor_decl;
 
-static int
-spelling_length (void)
-{
-  int size = 0;
-  struct spelling *p;
+/* start_init saves the ASMSPEC arg here for really_start_incremental_init.  */
+static const char *constructor_asmspec;
 
-  for (p = spelling_base; p < spelling; p++)
-    {
-      if (p->kind == SPELLING_BOUNDS)
-       size += 25;
-      else
-       size += strlen (p->u.s) + 1;
-    }
+/* Nonzero if this is an initializer for a top-level decl.  */
+static int constructor_top_level;
 
-  return size;
-}
+/* Nonzero if there were any member designators in this initializer.  */
+static int constructor_designated;
 
-/* Print the spelling to BUFFER and return it.  */
+/* Nesting depth of designator list.  */
+static int designator_depth;
 
-static char *
-print_spelling (char *buffer)
-{
-  char *d = buffer;
-  struct spelling *p;
+/* Nonzero if there were diagnosed errors in this designator list.  */
+static int designator_errorneous;
 
-  for (p = spelling_base; p < spelling; p++)
-    if (p->kind == SPELLING_BOUNDS)
-      {
-       sprintf (d, "[%d]", p->u.i);
-       d += strlen (d);
-      }
-    else
-      {
-       const char *s;
-       if (p->kind == SPELLING_MEMBER)
-         *d++ = '.';
-       for (s = p->u.s; (*d = *s++); d++)
-         ;
-      }
-  *d++ = '\0';
-  return buffer;
-}
+\f
+/* This stack has a level for each implicit or explicit level of
+   structuring in the initializer, including the outermost one.  It
+   saves the values of most of the variables above.  */
 
-/* Issue an error message for a bad initializer component.
-   MSGID identifies the message.
-   The component name is taken from the spelling stack.  */
+struct constructor_range_stack;
 
-void
-error_init (const char *msgid)
+struct constructor_stack
 {
-  char *ofwhat;
+  struct constructor_stack *next;
+  tree type;
+  tree fields;
+  tree index;
+  tree max_index;
+  tree unfilled_index;
+  tree unfilled_fields;
+  tree bit_index;
+  tree elements;
+  struct init_node *pending_elts;
+  int offset;
+  int depth;
+  /* If nonzero, this value should replace the entire
+     constructor at this level.  */
+  tree replacement_value;
+  struct constructor_range_stack *range_stack;
+  char constant;
+  char simple;
+  char implicit;
+  char erroneous;
+  char outer;
+  char incremental;
+  char designated;
+};
 
-  error ("%s", _(msgid));
-  ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
-  if (*ofwhat)
-    error ("(near initialization for `%s')", ofwhat);
-}
+struct constructor_stack *constructor_stack;
 
-/* Issue a pedantic warning for a bad initializer component.
-   MSGID identifies the message.
-   The component name is taken from the spelling stack.  */
+/* This stack represents designators from some range designator up to
+   the last designator in the list.  */
 
-void
-pedwarn_init (const char *msgid)
+struct constructor_range_stack
 {
-  char *ofwhat;
+  struct constructor_range_stack *next, *prev;
+  struct constructor_stack *stack;
+  tree range_start;
+  tree index;
+  tree range_end;
+  tree fields;
+};
 
-  pedwarn ("%s", _(msgid));
-  ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
-  if (*ofwhat)
-    pedwarn ("(near initialization for `%s')", ofwhat);
-}
+struct constructor_range_stack *constructor_range_stack;
 
-/* Issue a warning for a bad initializer component.
-   MSGID identifies the message.
-   The component name is taken from the spelling stack.  */
+/* This stack records separate initializers that are nested.
+   Nested initializers can't happen in ANSI C, but GNU C allows them
+   in cases like { ... (struct foo) { ... } ... }.  */
 
-static void
-warning_init (const char *msgid)
+struct initializer_stack
 {
-  char *ofwhat;
+  struct initializer_stack *next;
+  tree decl;
+  const char *asmspec;
+  struct constructor_stack *constructor_stack;
+  struct constructor_range_stack *constructor_range_stack;
+  tree elements;
+  struct spelling *spelling;
+  struct spelling *spelling_base;
+  int spelling_size;
+  char top_level;
+  char require_constant_value;
+  char require_constant_elements;
+};
 
-  warning ("%s", _(msgid));
-  ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
-  if (*ofwhat)
-    warning ("(near initialization for `%s')", ofwhat);
-}
+struct initializer_stack *initializer_stack;
 \f
-/* Digest the parser output INIT as an initializer for type TYPE.
-   Return a C expression of type TYPE to represent the initial value.
-
-   REQUIRE_CONSTANT requests an error if non-constant initializers or
-   elements are seen.  */
+/* Prepare to parse and output the initializer for variable DECL.  */
 
-static tree
-digest_init (tree type, tree init, int require_constant)
+void
+start_init (tree decl, tree asmspec_tree, int top_level)
 {
-  enum tree_code code = TREE_CODE (type);
-  tree inside_init = init;
+  const char *locus;
+  struct initializer_stack *p = xmalloc (sizeof (struct initializer_stack));
+  const char *asmspec = 0;
+
+  if (asmspec_tree)
+    asmspec = TREE_STRING_POINTER (asmspec_tree);
+
+  p->decl = constructor_decl;
+  p->asmspec = constructor_asmspec;
+  p->require_constant_value = require_constant_value;
+  p->require_constant_elements = require_constant_elements;
+  p->constructor_stack = constructor_stack;
+  p->constructor_range_stack = constructor_range_stack;
+  p->elements = constructor_elements;
+  p->spelling = spelling;
+  p->spelling_base = spelling_base;
+  p->spelling_size = spelling_size;
+  p->top_level = constructor_top_level;
+  p->next = initializer_stack;
+  initializer_stack = p;
+
+  constructor_decl = decl;
+  constructor_asmspec = asmspec;
+  constructor_designated = 0;
+  constructor_top_level = top_level;
+
+  if (decl != 0)
+    {
+      require_constant_value = TREE_STATIC (decl);
+      require_constant_elements
+       = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99))
+          /* For a scalar, you can always use any value to initialize,
+             even within braces.  */
+          && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
+              || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
+              || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
+              || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
+      locus = IDENTIFIER_POINTER (DECL_NAME (decl));
+    }
+  else
+    {
+      require_constant_value = 0;
+      require_constant_elements = 0;
+      locus = "(anonymous)";
+    }
 
-  if (type == error_mark_node
-      || init == error_mark_node
-      || TREE_TYPE (init) == error_mark_node)
-    return error_mark_node;
+  constructor_stack = 0;
+  constructor_range_stack = 0;
 
-  /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
-  /* Do not use STRIP_NOPS here.  We do not want an enumerator
-     whose value is 0 to count as a null pointer constant.  */
-  if (TREE_CODE (init) == NON_LVALUE_EXPR)
-    inside_init = TREE_OPERAND (init, 0);
+  missing_braces_mentioned = 0;
 
-  inside_init = fold (inside_init);
+  spelling_base = 0;
+  spelling_size = 0;
+  RESTORE_SPELLING_DEPTH (0);
 
-  /* Initialization of an array of chars from a string constant
-     optionally enclosed in braces.  */
+  if (locus)
+    push_string (locus);
+}
 
-  if (code == ARRAY_TYPE)
-    {
-      tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
-      if ((typ1 == char_type_node
-          || typ1 == signed_char_type_node
-          || typ1 == unsigned_char_type_node
-          || typ1 == unsigned_wchar_type_node
-          || typ1 == signed_wchar_type_node)
-         && ((inside_init && TREE_CODE (inside_init) == STRING_CST)))
-       {
-         if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
-                        TYPE_MAIN_VARIANT (type)))
-           return inside_init;
+void
+finish_init (void)
+{
+  struct initializer_stack *p = initializer_stack;
 
-         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
-              != char_type_node)
-             && TYPE_PRECISION (typ1) == TYPE_PRECISION (char_type_node))
-           {
-             error_init ("char-array initialized from wide string");
-             return error_mark_node;
-           }
-         if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
-              == char_type_node)
-             && TYPE_PRECISION (typ1) != TYPE_PRECISION (char_type_node))
-           {
-             error_init ("int-array initialized from non-wide string");
-             return error_mark_node;
-           }
+  /* Free the whole constructor stack of this initializer.  */
+  while (constructor_stack)
+    {
+      struct constructor_stack *q = constructor_stack;
+      constructor_stack = q->next;
+      free (q);
+    }
 
-         TREE_TYPE (inside_init) = type;
-         if (TYPE_DOMAIN (type) != 0
-             && TYPE_SIZE (type) != 0
-             && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
-             /* Subtract 1 (or sizeof (wchar_t))
-                because it's ok to ignore the terminating null char
-                that is counted in the length of the constant.  */
-             && 0 > compare_tree_int (TYPE_SIZE_UNIT (type),
-                                      TREE_STRING_LENGTH (inside_init)
-                                      - ((TYPE_PRECISION (typ1)
-                                          != TYPE_PRECISION (char_type_node))
-                                         ? (TYPE_PRECISION (wchar_type_node)
-                                            / BITS_PER_UNIT)
-                                         : 1)))
-           pedwarn_init ("initializer-string for array of chars is too long");
+  if (constructor_range_stack)
+    abort ();
 
-         return inside_init;
-       }
-    }
+  /* Pop back to the data of the outer initializer (if any).  */
+  free (spelling_base);
+  
+  constructor_decl = p->decl;
+  constructor_asmspec = p->asmspec;
+  require_constant_value = p->require_constant_value;
+  require_constant_elements = p->require_constant_elements;
+  constructor_stack = p->constructor_stack;
+  constructor_range_stack = p->constructor_range_stack;
+  constructor_elements = p->elements;
+  spelling = p->spelling;
+  spelling_base = p->spelling_base;
+  spelling_size = p->spelling_size;
+  constructor_top_level = p->top_level;
+  initializer_stack = p->next;
+  free (p);
+}
+\f
+/* Call here when we see the initializer is surrounded by braces.
+   This is instead of a call to push_init_level;
+   it is matched by a call to pop_init_level.
 
-  /* Build a VECTOR_CST from a *constant* vector constructor.  If the
-     vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
-     below and handle as a constructor.  */
-    if (code == VECTOR_TYPE
-        && comptypes (TREE_TYPE (inside_init), type)
-        && TREE_CONSTANT (inside_init))
-      {
-       if (TREE_CODE (inside_init) == VECTOR_CST
-           && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
-                         TYPE_MAIN_VARIANT (type)))
-         return inside_init;
-       else
-         return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
-      }
+   TYPE is the type to initialize, for a constructor expression.
+   For an initializer for a decl, TYPE is zero.  */
 
-  /* Any type can be initialized
-     from an expression of the same type, optionally with braces.  */
+void
+really_start_incremental_init (tree type)
+{
+  struct constructor_stack *p = xmalloc (sizeof (struct constructor_stack));
 
-  if (inside_init && TREE_TYPE (inside_init) != 0
-      && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
-                    TYPE_MAIN_VARIANT (type))
-         || (code == ARRAY_TYPE
-             && comptypes (TREE_TYPE (inside_init), type))
-         || (code == VECTOR_TYPE
-             && comptypes (TREE_TYPE (inside_init), type))
-         || (code == POINTER_TYPE
-             && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
-                 || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE)
-             && comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
-                           TREE_TYPE (type)))))
-    {
-      if (code == POINTER_TYPE)
-       inside_init = default_function_array_conversion (inside_init);
+  if (type == 0)
+    type = TREE_TYPE (constructor_decl);
 
-      if (require_constant && !flag_isoc99
-         && TREE_CODE (inside_init) == COMPOUND_LITERAL_EXPR)
-       {
-         /* As an extension, allow initializing objects with static storage
-            duration with compound literals (which are then treated just as
-            the brace enclosed list they contain).  */
-         tree decl = COMPOUND_LITERAL_EXPR_DECL (inside_init);
-         inside_init = DECL_INITIAL (decl);
-       }
+  if (targetm.vector_opaque_p (type))
+    error ("opaque vector types cannot be initialized");
 
-      if (code == ARRAY_TYPE && TREE_CODE (inside_init) != STRING_CST
-         && TREE_CODE (inside_init) != CONSTRUCTOR)
-       {
-         error_init ("array initialized from non-constant array expression");
-         return error_mark_node;
-       }
+  p->type = constructor_type;
+  p->fields = constructor_fields;
+  p->index = constructor_index;
+  p->max_index = constructor_max_index;
+  p->unfilled_index = constructor_unfilled_index;
+  p->unfilled_fields = constructor_unfilled_fields;
+  p->bit_index = constructor_bit_index;
+  p->elements = constructor_elements;
+  p->constant = constructor_constant;
+  p->simple = constructor_simple;
+  p->erroneous = constructor_erroneous;
+  p->pending_elts = constructor_pending_elts;
+  p->depth = constructor_depth;
+  p->replacement_value = 0;
+  p->implicit = 0;
+  p->range_stack = 0;
+  p->outer = 0;
+  p->incremental = constructor_incremental;
+  p->designated = constructor_designated;
+  p->next = 0;
+  constructor_stack = p;
 
-      if (optimize && TREE_CODE (inside_init) == VAR_DECL)
-       inside_init = decl_constant_value_for_broken_optimization (inside_init);
+  constructor_constant = 1;
+  constructor_simple = 1;
+  constructor_depth = SPELLING_DEPTH ();
+  constructor_elements = 0;
+  constructor_pending_elts = 0;
+  constructor_type = type;
+  constructor_incremental = 1;
+  constructor_designated = 0;
+  designator_depth = 0;
+  designator_errorneous = 0;
 
-      /* Compound expressions can only occur here if -pedantic or
-        -pedantic-errors is specified.  In the later case, we always want
-        an error.  In the former case, we simply want a warning.  */
-      if (require_constant && pedantic
-         && TREE_CODE (inside_init) == COMPOUND_EXPR)
-       {
-         inside_init
-           = valid_compound_expr_initializer (inside_init,
-                                              TREE_TYPE (inside_init));
-         if (inside_init == error_mark_node)
-           error_init ("initializer element is not constant");
-         else
-           pedwarn_init ("initializer element is not constant");
-         if (flag_pedantic_errors)
-           inside_init = error_mark_node;
-       }
-      else if (require_constant
-              && (!TREE_CONSTANT (inside_init)
-                  /* This test catches things like `7 / 0' which
-                     result in an expression for which TREE_CONSTANT
-                     is true, but which is not actually something
-                     that is a legal constant.  We really should not
-                     be using this function, because it is a part of
-                     the back-end.  Instead, the expression should
-                     already have been turned into ERROR_MARK_NODE.  */
-                  || !initializer_constant_valid_p (inside_init,
-                                                    TREE_TYPE (inside_init))))
-       {
-         error_init ("initializer element is not constant");
-         inside_init = error_mark_node;
-       }
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      constructor_fields = TYPE_FIELDS (constructor_type);
+      /* Skip any nameless bit fields at the beginning.  */
+      while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
+            && DECL_NAME (constructor_fields) == 0)
+       constructor_fields = TREE_CHAIN (constructor_fields);
 
-      return inside_init;
+      constructor_unfilled_fields = constructor_fields;
+      constructor_bit_index = bitsize_zero_node;
     }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      if (TYPE_DOMAIN (constructor_type))
+       {
+         constructor_max_index
+           = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
 
-  /* Handle scalar types, including conversions.  */
+         /* Detect non-empty initializations of zero-length arrays.  */
+         if (constructor_max_index == NULL_TREE
+             && TYPE_SIZE (constructor_type))
+           constructor_max_index = build_int_2 (-1, -1);
 
-  if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
-      || code == ENUMERAL_TYPE || code == BOOLEAN_TYPE || code == COMPLEX_TYPE)
-    {
-      /* Note that convert_for_assignment calls default_conversion
-        for arrays and functions.  We must not call it in the
-        case where inside_init is a null pointer constant.  */
-      inside_init
-       = convert_for_assignment (type, init, _("initialization"),
-                                 NULL_TREE, NULL_TREE, 0);
+         /* constructor_max_index needs to be an INTEGER_CST.  Attempts
+            to initialize VLAs will cause a proper error; avoid tree
+            checking errors as well by setting a safe value.  */
+         if (constructor_max_index
+             && TREE_CODE (constructor_max_index) != INTEGER_CST)
+           constructor_max_index = build_int_2 (-1, -1);
 
-      if (require_constant && ! TREE_CONSTANT (inside_init))
-       {
-         error_init ("initializer element is not constant");
-         inside_init = error_mark_node;
-       }
-      else if (require_constant
-              && initializer_constant_valid_p (inside_init, TREE_TYPE (inside_init)) == 0)
-       {
-         error_init ("initializer element is not computable at load time");
-         inside_init = error_mark_node;
+         constructor_index
+           = convert (bitsizetype,
+                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
        }
+      else
+       constructor_index = bitsize_zero_node;
 
-      return inside_init;
+      constructor_unfilled_index = constructor_index;
     }
-
-  /* Come here only for records and arrays.  */
-
-  if (COMPLETE_TYPE_P (type) && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+  else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
     {
-      error_init ("variable-sized object may not be initialized");
-      return error_mark_node;
+      /* Vectors are like simple fixed-size arrays.  */
+      constructor_max_index =
+       build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+      constructor_index = convert (bitsizetype, bitsize_zero_node);
+      constructor_unfilled_index = constructor_index;
+    }
+  else
+    {
+      /* Handle the case of int x = {5}; */
+      constructor_fields = constructor_type;
+      constructor_unfilled_fields = constructor_type;
     }
-
-  error_init ("invalid initializer");
-  return error_mark_node;
 }
 \f
-/* Handle initializers that use braces.  */
-
-/* Type of object we are accumulating a constructor for.
-   This type is always a RECORD_TYPE, UNION_TYPE or ARRAY_TYPE.  */
-static tree constructor_type;
-
-/* For a RECORD_TYPE or UNION_TYPE, this is the chain of fields
-   left to fill.  */
-static tree constructor_fields;
+/* Push down into a subobject, for initialization.
+   If this is for an explicit set of braces, IMPLICIT is 0.
+   If it is because the next element belongs at a lower level,
+   IMPLICIT is 1 (or 2 if the push is because of designator list).  */
 
-/* For an ARRAY_TYPE, this is the specified index
-   at which to store the next element we get.  */
-static tree constructor_index;
+void
+push_init_level (int implicit)
+{
+  struct constructor_stack *p;
+  tree value = NULL_TREE;
 
-/* For an ARRAY_TYPE, this is the maximum index.  */
-static tree constructor_max_index;
+  /* If we've exhausted any levels that didn't have braces,
+     pop them now.  */
+  while (constructor_stack->implicit)
+    {
+      if ((TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+         && constructor_fields == 0)
+       process_init_element (pop_init_level (1));
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE
+              && constructor_max_index
+              && tree_int_cst_lt (constructor_max_index, constructor_index))
+       process_init_element (pop_init_level (1));
+      else
+       break;
+    }
 
-/* For a RECORD_TYPE, this is the first field not yet written out.  */
-static tree constructor_unfilled_fields;
+  /* Unless this is an explicit brace, we need to preserve previous
+     content if any.  */
+  if (implicit)
+    {
+      if ((TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+         && constructor_fields)
+       value = find_init_member (constructor_fields);
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       value = find_init_member (constructor_index);
+    }
 
-/* For an ARRAY_TYPE, this is the index of the first element
-   not yet written out.  */
-static tree constructor_unfilled_index;
+  p = xmalloc (sizeof (struct constructor_stack));
+  p->type = constructor_type;
+  p->fields = constructor_fields;
+  p->index = constructor_index;
+  p->max_index = constructor_max_index;
+  p->unfilled_index = constructor_unfilled_index;
+  p->unfilled_fields = constructor_unfilled_fields;
+  p->bit_index = constructor_bit_index;
+  p->elements = constructor_elements;
+  p->constant = constructor_constant;
+  p->simple = constructor_simple;
+  p->erroneous = constructor_erroneous;
+  p->pending_elts = constructor_pending_elts;
+  p->depth = constructor_depth;
+  p->replacement_value = 0;
+  p->implicit = implicit;
+  p->outer = 0;
+  p->incremental = constructor_incremental;
+  p->designated = constructor_designated;
+  p->next = constructor_stack;
+  p->range_stack = 0;
+  constructor_stack = p;
 
-/* In a RECORD_TYPE, the byte index of the next consecutive field.
-   This is so we can generate gaps between fields, when appropriate.  */
-static tree constructor_bit_index;
+  constructor_constant = 1;
+  constructor_simple = 1;
+  constructor_depth = SPELLING_DEPTH ();
+  constructor_elements = 0;
+  constructor_incremental = 1;
+  constructor_designated = 0;
+  constructor_pending_elts = 0;
+  if (!implicit)
+    {
+      p->range_stack = constructor_range_stack;
+      constructor_range_stack = 0;
+      designator_depth = 0;
+      designator_errorneous = 0;
+    }
 
-/* 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;
+  /* Don't die if an entire brace-pair level is superfluous
+     in the containing level.  */
+  if (constructor_type == 0)
+    ;
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      /* Don't die if there are extra init elts at the end.  */
+      if (constructor_fields == 0)
+       constructor_type = 0;
+      else
+       {
+         constructor_type = TREE_TYPE (constructor_fields);
+         push_member_name (constructor_fields);
+         constructor_depth++;
+       }
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      constructor_type = TREE_TYPE (constructor_type);
+      push_array_bounds (tree_low_cst (constructor_index, 0));
+      constructor_depth++;
+    }
 
-/* 1 if constructor should be incrementally stored into a constructor chain,
-   0 if all the elements should be kept in AVL tree.  */
-static int constructor_incremental;
+  if (constructor_type == 0)
+    {
+      error_init ("extra brace group at end of initializer");
+      constructor_fields = 0;
+      constructor_unfilled_fields = 0;
+      return;
+    }
 
-/* 1 if so far this constructor's elements are all compile-time constants.  */
-static int constructor_constant;
+  if (value && TREE_CODE (value) == CONSTRUCTOR)
+    {
+      constructor_constant = TREE_CONSTANT (value);
+      constructor_simple = TREE_STATIC (value);
+      constructor_elements = CONSTRUCTOR_ELTS (value);
+      if (constructor_elements
+         && (TREE_CODE (constructor_type) == RECORD_TYPE
+             || TREE_CODE (constructor_type) == ARRAY_TYPE))
+       set_nonincremental_init ();
+    }
 
-/* 1 if so far this constructor's elements are all valid address constants.  */
-static int constructor_simple;
+  if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
+    {
+      missing_braces_mentioned = 1;
+      warning_init ("missing braces around initializer");
+    }
 
-/* 1 if this constructor is erroneous so far.  */
-static int constructor_erroneous;
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+    {
+      constructor_fields = TYPE_FIELDS (constructor_type);
+      /* Skip any nameless bit fields at the beginning.  */
+      while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
+            && DECL_NAME (constructor_fields) == 0)
+       constructor_fields = TREE_CHAIN (constructor_fields);
 
-/* Structure for managing pending initializer elements, organized as an
-   AVL tree.  */
+      constructor_unfilled_fields = constructor_fields;
+      constructor_bit_index = bitsize_zero_node;
+    }
+  else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
+    {
+      /* Vectors are like simple fixed-size arrays.  */
+      constructor_max_index =
+       build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
+      constructor_index = convert (bitsizetype, integer_zero_node);
+      constructor_unfilled_index = constructor_index;
+    }
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    {
+      if (TYPE_DOMAIN (constructor_type))
+       {
+         constructor_max_index
+           = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
 
-struct init_node
-{
-  struct init_node *left, *right;
-  struct init_node *parent;
-  int balance;
-  tree purpose;
-  tree value;
-};
+         /* Detect non-empty initializations of zero-length arrays.  */
+         if (constructor_max_index == NULL_TREE
+             && TYPE_SIZE (constructor_type))
+           constructor_max_index = build_int_2 (-1, -1);
 
-/* Tree of pending elements at this constructor level.
-   These are elements encountered out of order
-   which belong at places we haven't reached yet in actually
-   writing the output.
-   Will never hold tree nodes across GC runs.  */
-static struct init_node *constructor_pending_elts;
+         /* constructor_max_index needs to be an INTEGER_CST.  Attempts
+            to initialize VLAs will cause a proper error; avoid tree
+            checking errors as well by setting a safe value.  */
+         if (constructor_max_index
+             && TREE_CODE (constructor_max_index) != INTEGER_CST)
+           constructor_max_index = build_int_2 (-1, -1);
 
-/* The SPELLING_DEPTH of this constructor.  */
-static int constructor_depth;
+         constructor_index
+           = convert (bitsizetype,
+                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+       }
+      else
+       constructor_index = bitsize_zero_node;
 
-/* 0 if implicitly pushing constructor levels is allowed.  */
-int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages.  */
+      constructor_unfilled_index = constructor_index;
+      if (value && TREE_CODE (value) == STRING_CST)
+       {
+         /* We need to split the char/wchar array into individual
+            characters, so that we don't have to special case it
+            everywhere.  */
+         set_nonincremental_init_from_string (value);
+       }
+    }
+  else
+    {
+      warning_init ("braces around scalar initializer");
+      constructor_fields = constructor_type;
+      constructor_unfilled_fields = constructor_type;
+    }
+}
 
-static int require_constant_value;
-static int require_constant_elements;
+/* At the end of an implicit or explicit brace level,
+   finish up that level of constructor.
+   If we were outputting the elements as they are read, return 0
+   from inner levels (process_init_element ignores that),
+   but return error_mark_node from the outermost level
+   (that's what we want to put in DECL_INITIAL).
+   Otherwise, return a CONSTRUCTOR expression.  */
 
-/* DECL node for which an initializer is being read.
-   0 means we are reading a constructor expression
-   such as (struct foo) {...}.  */
-static tree constructor_decl;
+tree
+pop_init_level (int implicit)
+{
+  struct constructor_stack *p;
+  tree constructor = 0;
 
-/* start_init saves the ASMSPEC arg here for really_start_incremental_init.  */
-static const char *constructor_asmspec;
+  if (implicit == 0)
+    {
+      /* When we come to an explicit close brace,
+        pop any inner levels that didn't have explicit braces.  */
+      while (constructor_stack->implicit)
+       process_init_element (pop_init_level (1));
 
-/* Nonzero if this is an initializer for a top-level decl.  */
-static int constructor_top_level;
+      if (constructor_range_stack)
+       abort ();
+    }
 
-/* Nonzero if there were any member designators in this initializer.  */
-static int constructor_designated;
+  /* Now output all pending elements.  */
+  constructor_incremental = 1;
+  output_pending_init_elements (1);
 
-/* Nesting depth of designator list.  */
-static int designator_depth;
+  p = constructor_stack;
 
-/* Nonzero if there were diagnosed errors in this designator list.  */
-static int designator_errorneous;
+  /* Error for initializing a flexible array member, or a zero-length
+     array member in an inappropriate context.  */
+  if (constructor_type && constructor_fields
+      && TREE_CODE (constructor_type) == ARRAY_TYPE
+      && TYPE_DOMAIN (constructor_type)
+      && ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
+    {
+      /* Silently discard empty initializations.  The parser will
+        already have pedwarned for empty brackets.  */
+      if (integer_zerop (constructor_unfilled_index))
+       constructor_type = NULL_TREE;
+      else if (! TYPE_SIZE (constructor_type))
+       {
+         if (constructor_depth > 2)
+           error_init ("initialization of flexible array member in a nested context");
+         else if (pedantic)
+           pedwarn_init ("initialization of a flexible array member");
 
-\f
-/* This stack has a level for each implicit or explicit level of
-   structuring in the initializer, including the outermost one.  It
-   saves the values of most of the variables above.  */
+         /* We have already issued an error message for the existence
+            of a flexible array member not at the end of the structure.
+            Discard the initializer so that we do not abort later.  */
+         if (TREE_CHAIN (constructor_fields) != NULL_TREE)
+           constructor_type = NULL_TREE;
+       }
+      else
+       /* Zero-length arrays are no longer special, so we should no longer
+          get here.  */
+       abort ();
+    }
 
-struct constructor_range_stack;
+  /* Warn when some struct elements are implicitly initialized to zero.  */
+  if (extra_warnings
+      && constructor_type
+      && TREE_CODE (constructor_type) == RECORD_TYPE
+      && constructor_unfilled_fields)
+    {
+       /* Do not warn for flexible array members or zero-length arrays.  */
+       while (constructor_unfilled_fields
+              && (! DECL_SIZE (constructor_unfilled_fields)
+                  || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
+         constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
 
-struct constructor_stack
-{
-  struct constructor_stack *next;
-  tree type;
-  tree fields;
-  tree index;
-  tree max_index;
-  tree unfilled_index;
-  tree unfilled_fields;
-  tree bit_index;
-  tree elements;
-  struct init_node *pending_elts;
-  int offset;
-  int depth;
-  /* If nonzero, this value should replace the entire
-     constructor at this level.  */
-  tree replacement_value;
-  struct constructor_range_stack *range_stack;
-  char constant;
-  char simple;
-  char implicit;
-  char erroneous;
-  char outer;
-  char incremental;
-  char designated;
-};
+       /* Do not warn if this level of the initializer uses member
+          designators; it is likely to be deliberate.  */
+       if (constructor_unfilled_fields && !constructor_designated)
+         {
+           push_member_name (constructor_unfilled_fields);
+           warning_init ("missing initializer");
+           RESTORE_SPELLING_DEPTH (constructor_depth);
+         }
+    }
 
-struct constructor_stack *constructor_stack;
+  /* Pad out the end of the structure.  */
+  if (p->replacement_value)
+    /* If this closes a superfluous brace pair,
+       just pass out the element between them.  */
+    constructor = p->replacement_value;
+  else if (constructor_type == 0)
+    ;
+  else if (TREE_CODE (constructor_type) != RECORD_TYPE
+          && TREE_CODE (constructor_type) != UNION_TYPE
+          && TREE_CODE (constructor_type) != ARRAY_TYPE
+          && TREE_CODE (constructor_type) != VECTOR_TYPE)
+    {
+      /* A nonincremental scalar initializer--just return
+        the element, after verifying there is just one.  */
+      if (constructor_elements == 0)
+       {
+         if (!constructor_erroneous)
+           error_init ("empty scalar initializer");
+         constructor = error_mark_node;
+       }
+      else if (TREE_CHAIN (constructor_elements) != 0)
+       {
+         error_init ("extra elements in scalar initializer");
+         constructor = TREE_VALUE (constructor_elements);
+       }
+      else
+       constructor = TREE_VALUE (constructor_elements);
+    }
+  else
+    {
+      if (constructor_erroneous)
+       constructor = error_mark_node;
+      else
+       {
+         constructor = build_constructor (constructor_type,
+                                          nreverse (constructor_elements));
+         if (constructor_constant)
+           TREE_CONSTANT (constructor) = 1;
+         if (constructor_constant && constructor_simple)
+           TREE_STATIC (constructor) = 1;
+       }
+    }
 
-/* This stack represents designators from some range designator up to
-   the last designator in the list.  */
+  constructor_type = p->type;
+  constructor_fields = p->fields;
+  constructor_index = p->index;
+  constructor_max_index = p->max_index;
+  constructor_unfilled_index = p->unfilled_index;
+  constructor_unfilled_fields = p->unfilled_fields;
+  constructor_bit_index = p->bit_index;
+  constructor_elements = p->elements;
+  constructor_constant = p->constant;
+  constructor_simple = p->simple;
+  constructor_erroneous = p->erroneous;
+  constructor_incremental = p->incremental;
+  constructor_designated = p->designated;
+  constructor_pending_elts = p->pending_elts;
+  constructor_depth = p->depth;
+  if (!p->implicit)
+    constructor_range_stack = p->range_stack;
+  RESTORE_SPELLING_DEPTH (constructor_depth);
 
-struct constructor_range_stack
-{
-  struct constructor_range_stack *next, *prev;
-  struct constructor_stack *stack;
-  tree range_start;
-  tree index;
-  tree range_end;
-  tree fields;
-};
+  constructor_stack = p->next;
+  free (p);
 
-struct constructor_range_stack *constructor_range_stack;
+  if (constructor == 0)
+    {
+      if (constructor_stack == 0)
+       return error_mark_node;
+      return NULL_TREE;
+    }
+  return constructor;
+}
 
-/* This stack records separate initializers that are nested.
-   Nested initializers can't happen in ANSI C, but GNU C allows them
-   in cases like { ... (struct foo) { ... } ... }.  */
+/* Common handling for both array range and field name designators.
+   ARRAY argument is nonzero for array ranges.  Returns zero for success.  */
 
-struct initializer_stack
+static int
+set_designator (int array)
 {
-  struct initializer_stack *next;
-  tree decl;
-  const char *asmspec;
-  struct constructor_stack *constructor_stack;
-  struct constructor_range_stack *constructor_range_stack;
-  tree elements;
-  struct spelling *spelling;
-  struct spelling *spelling_base;
-  int spelling_size;
-  char top_level;
-  char require_constant_value;
-  char require_constant_elements;
-};
+  tree subtype;
+  enum tree_code subcode;
 
-struct initializer_stack *initializer_stack;
-\f
-/* Prepare to parse and output the initializer for variable DECL.  */
+  /* Don't die if an entire brace-pair level is superfluous
+     in the containing level.  */
+  if (constructor_type == 0)
+    return 1;
 
-void
-start_init (tree decl, tree asmspec_tree, int top_level)
-{
-  const char *locus;
-  struct initializer_stack *p
-    = (struct initializer_stack *) xmalloc (sizeof (struct initializer_stack));
-  const char *asmspec = 0;
+  /* If there were errors in this designator list already, bail out silently.  */
+  if (designator_errorneous)
+    return 1;
 
-  if (asmspec_tree)
-    asmspec = TREE_STRING_POINTER (asmspec_tree);
+  if (!designator_depth)
+    {
+      if (constructor_range_stack)
+       abort ();
 
-  p->decl = constructor_decl;
-  p->asmspec = constructor_asmspec;
-  p->require_constant_value = require_constant_value;
-  p->require_constant_elements = require_constant_elements;
-  p->constructor_stack = constructor_stack;
-  p->constructor_range_stack = constructor_range_stack;
-  p->elements = constructor_elements;
-  p->spelling = spelling;
-  p->spelling_base = spelling_base;
-  p->spelling_size = spelling_size;
-  p->top_level = constructor_top_level;
-  p->next = initializer_stack;
-  initializer_stack = p;
+      /* Designator list starts at the level of closest explicit
+        braces.  */
+      while (constructor_stack->implicit)
+       process_init_element (pop_init_level (1));
+      constructor_designated = 1;
+      return 0;
+    }
 
-  constructor_decl = decl;
-  constructor_asmspec = asmspec;
-  constructor_designated = 0;
-  constructor_top_level = top_level;
+  if (constructor_no_implicit)
+    {
+      error_init ("initialization designators may not nest");
+      return 1;
+    }
 
-  if (decl != 0)
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
     {
-      require_constant_value = TREE_STATIC (decl);
-      require_constant_elements
-       = ((TREE_STATIC (decl) || (pedantic && !flag_isoc99))
-          /* For a scalar, you can always use any value to initialize,
-             even within braces.  */
-          && (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
-              || TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE
-              || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
-              || TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
-      locus = IDENTIFIER_POINTER (DECL_NAME (decl));
+      subtype = TREE_TYPE (constructor_fields);
+      if (subtype != error_mark_node)
+       subtype = TYPE_MAIN_VARIANT (subtype);
     }
-  else
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
-      require_constant_value = 0;
-      require_constant_elements = 0;
-      locus = "(anonymous)";
+      subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
     }
+  else
+    abort ();
 
-  constructor_stack = 0;
-  constructor_range_stack = 0;
-
-  missing_braces_mentioned = 0;
-
-  spelling_base = 0;
-  spelling_size = 0;
-  RESTORE_SPELLING_DEPTH (0);
+  subcode = TREE_CODE (subtype);
+  if (array && subcode != ARRAY_TYPE)
+    {
+      error_init ("array index in non-array initializer");
+      return 1;
+    }
+  else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE)
+    {
+      error_init ("field name not in record or union initializer");
+      return 1;
+    }
 
-  if (locus)
-    push_string (locus);
+  constructor_designated = 1;
+  push_init_level (2);
+  return 0;
 }
 
-void
-finish_init (void)
-{
-  struct initializer_stack *p = initializer_stack;
+/* If there are range designators in designator list, push a new designator
+   to constructor_range_stack.  RANGE_END is end of such stack range or
+   NULL_TREE if there is no range designator at this level.  */
 
-  /* Free the whole constructor stack of this initializer.  */
-  while (constructor_stack)
-    {
-      struct constructor_stack *q = constructor_stack;
-      constructor_stack = q->next;
-      free (q);
-    }
+static void
+push_range_stack (tree range_end)
+{
+  struct constructor_range_stack *p;
 
+  p = ggc_alloc (sizeof (struct constructor_range_stack));
+  p->prev = constructor_range_stack;
+  p->next = 0;
+  p->fields = constructor_fields;
+  p->range_start = constructor_index;
+  p->index = constructor_index;
+  p->stack = constructor_stack;
+  p->range_end = range_end;
   if (constructor_range_stack)
-    abort ();
-
-  /* Pop back to the data of the outer initializer (if any).  */
-  constructor_decl = p->decl;
-  constructor_asmspec = p->asmspec;
-  require_constant_value = p->require_constant_value;
-  require_constant_elements = p->require_constant_elements;
-  constructor_stack = p->constructor_stack;
-  constructor_range_stack = p->constructor_range_stack;
-  constructor_elements = p->elements;
-  spelling = p->spelling;
-  spelling_base = p->spelling_base;
-  spelling_size = p->spelling_size;
-  constructor_top_level = p->top_level;
-  initializer_stack = p->next;
-  free (p);
+    constructor_range_stack->next = p;
+  constructor_range_stack = p;
 }
-\f
-/* Call here when we see the initializer is surrounded by braces.
-   This is instead of a call to push_init_level;
-   it is matched by a call to pop_init_level.
 
-   TYPE is the type to initialize, for a constructor expression.
-   For an initializer for a decl, TYPE is zero.  */
+/* Within an array initializer, specify the next index to be initialized.
+   FIRST is that index.  If LAST is nonzero, then initialize a range
+   of indices, running from FIRST through LAST.  */
 
 void
-really_start_incremental_init (tree type)
+set_init_index (tree first, tree last)
 {
-  struct constructor_stack *p
-    = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
-
-  if (type == 0)
-    type = TREE_TYPE (constructor_decl);
+  if (set_designator (1))
+    return;
 
-  if ((*targetm.vector_opaque_p) (type))
-    error ("opaque vector types cannot be initialized");
+  designator_errorneous = 1;
 
-  p->type = constructor_type;
-  p->fields = constructor_fields;
-  p->index = constructor_index;
-  p->max_index = constructor_max_index;
-  p->unfilled_index = constructor_unfilled_index;
-  p->unfilled_fields = constructor_unfilled_fields;
-  p->bit_index = constructor_bit_index;
-  p->elements = constructor_elements;
-  p->constant = constructor_constant;
-  p->simple = constructor_simple;
-  p->erroneous = constructor_erroneous;
-  p->pending_elts = constructor_pending_elts;
-  p->depth = constructor_depth;
-  p->replacement_value = 0;
-  p->implicit = 0;
-  p->range_stack = 0;
-  p->outer = 0;
-  p->incremental = constructor_incremental;
-  p->designated = constructor_designated;
-  p->next = 0;
-  constructor_stack = p;
+  while ((TREE_CODE (first) == NOP_EXPR
+         || TREE_CODE (first) == CONVERT_EXPR
+         || TREE_CODE (first) == NON_LVALUE_EXPR)
+        && (TYPE_MODE (TREE_TYPE (first))
+            == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0)))))
+    first = TREE_OPERAND (first, 0);
 
-  constructor_constant = 1;
-  constructor_simple = 1;
-  constructor_depth = SPELLING_DEPTH ();
-  constructor_elements = 0;
-  constructor_pending_elts = 0;
-  constructor_type = type;
-  constructor_incremental = 1;
-  constructor_designated = 0;
-  designator_depth = 0;
-  designator_errorneous = 0;
+  if (last)
+    while ((TREE_CODE (last) == NOP_EXPR
+           || TREE_CODE (last) == CONVERT_EXPR
+           || TREE_CODE (last) == NON_LVALUE_EXPR)
+          && (TYPE_MODE (TREE_TYPE (last))
+              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0)))))
+      last = TREE_OPERAND (last, 0);
 
-  if (TREE_CODE (constructor_type) == RECORD_TYPE
-      || TREE_CODE (constructor_type) == UNION_TYPE)
+  if (TREE_CODE (first) != INTEGER_CST)
+    error_init ("nonconstant array index in initializer");
+  else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
+    error_init ("nonconstant array index in initializer");
+  else if (TREE_CODE (constructor_type) != ARRAY_TYPE)
+    error_init ("array index in non-array initializer");
+  else if (tree_int_cst_sgn (first) == -1)
+    error_init ("array index in initializer exceeds array bounds");
+  else if (constructor_max_index
+          && tree_int_cst_lt (constructor_max_index, first))
+    error_init ("array index in initializer exceeds array bounds");
+  else
     {
-      constructor_fields = TYPE_FIELDS (constructor_type);
-      /* Skip any nameless bit fields at the beginning.  */
-      while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
-            && DECL_NAME (constructor_fields) == 0)
-       constructor_fields = TREE_CHAIN (constructor_fields);
+      constructor_index = convert (bitsizetype, first);
 
-      constructor_unfilled_fields = constructor_fields;
-      constructor_bit_index = bitsize_zero_node;
-    }
-  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    {
-      if (TYPE_DOMAIN (constructor_type))
+      if (last)
        {
-         constructor_max_index
-           = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
+         if (tree_int_cst_equal (first, last))
+           last = 0;
+         else if (tree_int_cst_lt (last, first))
+           {
+             error_init ("empty index range in initializer");
+             last = 0;
+           }
+         else
+           {
+             last = convert (bitsizetype, last);
+             if (constructor_max_index != 0
+                 && tree_int_cst_lt (constructor_max_index, last))
+               {
+                 error_init ("array index range in initializer exceeds array bounds");
+                 last = 0;
+               }
+           }
+       }
 
-         /* Detect non-empty initializations of zero-length arrays.  */
-         if (constructor_max_index == NULL_TREE
-             && TYPE_SIZE (constructor_type))
-           constructor_max_index = build_int_2 (-1, -1);
+      designator_depth++;
+      designator_errorneous = 0;
+      if (constructor_range_stack || last)
+       push_range_stack (last);
+    }
+}
 
-         /* constructor_max_index needs to be an INTEGER_CST.  Attempts
-            to initialize VLAs will cause a proper error; avoid tree
-            checking errors as well by setting a safe value.  */
-         if (constructor_max_index
-             && TREE_CODE (constructor_max_index) != INTEGER_CST)
-           constructor_max_index = build_int_2 (-1, -1);
+/* Within a struct initializer, specify the next field to be initialized.  */
 
-         constructor_index
-           = convert (bitsizetype,
-                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
-       }
-      else
-       constructor_index = bitsize_zero_node;
+void
+set_init_label (tree fieldname)
+{
+  tree tail;
 
-      constructor_unfilled_index = constructor_index;
+  if (set_designator (0))
+    return;
+
+  designator_errorneous = 1;
+
+  if (TREE_CODE (constructor_type) != RECORD_TYPE
+      && TREE_CODE (constructor_type) != UNION_TYPE)
+    {
+      error_init ("field name not in record or union initializer");
+      return;
     }
-  else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
+
+  for (tail = TYPE_FIELDS (constructor_type); tail;
+       tail = TREE_CHAIN (tail))
     {
-      /* Vectors are like simple fixed-size arrays.  */
-      constructor_max_index =
-       build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
-      constructor_index = convert (bitsizetype, bitsize_zero_node);
-      constructor_unfilled_index = constructor_index;
+      if (DECL_NAME (tail) == fieldname)
+       break;
     }
+
+  if (tail == 0)
+    error ("unknown field `%s' specified in initializer",
+          IDENTIFIER_POINTER (fieldname));
   else
     {
-      /* Handle the case of int x = {5}; */
-      constructor_fields = constructor_type;
-      constructor_unfilled_fields = constructor_type;
+      constructor_fields = tail;
+      designator_depth++;
+      designator_errorneous = 0;
+      if (constructor_range_stack)
+       push_range_stack (NULL_TREE);
     }
 }
 \f
-/* Push down into a subobject, for initialization.
-   If this is for an explicit set of braces, IMPLICIT is 0.
-   If it is because the next element belongs at a lower level,
-   IMPLICIT is 1 (or 2 if the push is because of designator list).  */
+/* Add a new initializer to the tree of pending initializers.  PURPOSE
+   identifies the initializer, either array index or field in a structure.
+   VALUE is the value of that index or field.  */
 
-void
-push_init_level (int implicit)
+static void
+add_pending_init (tree purpose, tree value)
 {
-  struct constructor_stack *p;
-  tree value = NULL_TREE;
+  struct init_node *p, **q, *r;
 
-  /* If we've exhausted any levels that didn't have braces,
-     pop them now.  */
-  while (constructor_stack->implicit)
+  q = &constructor_pending_elts;
+  p = 0;
+
+  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
-      if ((TREE_CODE (constructor_type) == RECORD_TYPE
-          || TREE_CODE (constructor_type) == UNION_TYPE)
-         && constructor_fields == 0)
-       process_init_element (pop_init_level (1));
-      else if (TREE_CODE (constructor_type) == ARRAY_TYPE
-              && constructor_max_index
-              && tree_int_cst_lt (constructor_max_index, constructor_index))
-       process_init_element (pop_init_level (1));
-      else
-       break;
+      while (*q != 0)
+       {
+         p = *q;
+         if (tree_int_cst_lt (purpose, p->purpose))
+           q = &p->left;
+         else if (tree_int_cst_lt (p->purpose, purpose))
+           q = &p->right;
+         else
+           {
+             if (TREE_SIDE_EFFECTS (p->value))
+               warning_init ("initialized field with side-effects overwritten");
+             p->value = value;
+             return;
+           }
+       }
     }
-
-  /* Unless this is an explicit brace, we need to preserve previous
-     content if any.  */
-  if (implicit)
+  else
     {
-      if ((TREE_CODE (constructor_type) == RECORD_TYPE
-          || TREE_CODE (constructor_type) == UNION_TYPE)
-         && constructor_fields)
-       value = find_init_member (constructor_fields);
-      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-       value = find_init_member (constructor_index);
+      tree bitpos;
+
+      bitpos = bit_position (purpose);
+      while (*q != NULL)
+       {
+         p = *q;
+         if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
+           q = &p->left;
+         else if (p->purpose != purpose)
+           q = &p->right;
+         else
+           {
+             if (TREE_SIDE_EFFECTS (p->value))
+               warning_init ("initialized field with side-effects overwritten");
+             p->value = value;
+             return;
+           }
+       }
     }
 
-  p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
-  p->type = constructor_type;
-  p->fields = constructor_fields;
-  p->index = constructor_index;
-  p->max_index = constructor_max_index;
-  p->unfilled_index = constructor_unfilled_index;
-  p->unfilled_fields = constructor_unfilled_fields;
-  p->bit_index = constructor_bit_index;
-  p->elements = constructor_elements;
-  p->constant = constructor_constant;
-  p->simple = constructor_simple;
-  p->erroneous = constructor_erroneous;
-  p->pending_elts = constructor_pending_elts;
-  p->depth = constructor_depth;
-  p->replacement_value = 0;
-  p->implicit = implicit;
-  p->outer = 0;
-  p->incremental = constructor_incremental;
-  p->designated = constructor_designated;
-  p->next = constructor_stack;
-  p->range_stack = 0;
-  constructor_stack = p;
+  r = ggc_alloc (sizeof (struct init_node));
+  r->purpose = purpose;
+  r->value = value;
 
-  constructor_constant = 1;
-  constructor_simple = 1;
-  constructor_depth = SPELLING_DEPTH ();
-  constructor_elements = 0;
-  constructor_incremental = 1;
-  constructor_designated = 0;
-  constructor_pending_elts = 0;
-  if (!implicit)
+  *q = r;
+  r->parent = p;
+  r->left = 0;
+  r->right = 0;
+  r->balance = 0;
+
+  while (p)
     {
-      p->range_stack = constructor_range_stack;
-      constructor_range_stack = 0;
-      designator_depth = 0;
-      designator_errorneous = 0;
-    }
+      struct init_node *s;
+
+      if (r == p->left)
+       {
+         if (p->balance == 0)
+           p->balance = -1;
+         else if (p->balance < 0)
+           {
+             if (r->balance < 0)
+               {
+                 /* L rotation.  */
+                 p->left = r->right;
+                 if (p->left)
+                   p->left->parent = p;
+                 r->right = p;
+
+                 p->balance = 0;
+                 r->balance = 0;
+
+                 s = p->parent;
+                 p->parent = r;
+                 r->parent = s;
+                 if (s)
+                   {
+                     if (s->left == p)
+                       s->left = r;
+                     else
+                       s->right = r;
+                   }
+                 else
+                   constructor_pending_elts = r;
+               }
+             else
+               {
+                 /* LR rotation.  */
+                 struct init_node *t = r->right;
+
+                 r->right = t->left;
+                 if (r->right)
+                   r->right->parent = r;
+                 t->left = r;
+
+                 p->left = t->right;
+                 if (p->left)
+                   p->left->parent = p;
+                 t->right = p;
+
+                 p->balance = t->balance < 0;
+                 r->balance = -(t->balance > 0);
+                 t->balance = 0;
+
+                 s = p->parent;
+                 p->parent = t;
+                 r->parent = t;
+                 t->parent = s;
+                 if (s)
+                   {
+                     if (s->left == p)
+                       s->left = t;
+                     else
+                       s->right = t;
+                   }
+                 else
+                   constructor_pending_elts = t;
+               }
+             break;
+           }
+         else
+           {
+             /* p->balance == +1; growth of left side balances the node.  */
+             p->balance = 0;
+             break;
+           }
+       }
+      else /* r == p->right */
+       {
+         if (p->balance == 0)
+           /* Growth propagation from right side.  */
+           p->balance++;
+         else if (p->balance > 0)
+           {
+             if (r->balance > 0)
+               {
+                 /* R rotation.  */
+                 p->right = r->left;
+                 if (p->right)
+                   p->right->parent = p;
+                 r->left = p;
+
+                 p->balance = 0;
+                 r->balance = 0;
+
+                 s = p->parent;
+                 p->parent = r;
+                 r->parent = s;
+                 if (s)
+                   {
+                     if (s->left == p)
+                       s->left = r;
+                     else
+                       s->right = r;
+                   }
+                 else
+                   constructor_pending_elts = r;
+               }
+             else /* r->balance == -1 */
+               {
+                 /* RL rotation */
+                 struct init_node *t = r->left;
+
+                 r->left = t->right;
+                 if (r->left)
+                   r->left->parent = r;
+                 t->right = r;
+
+                 p->right = t->left;
+                 if (p->right)
+                   p->right->parent = p;
+                 t->left = p;
 
-  /* Don't die if an entire brace-pair level is superfluous
-     in the containing level.  */
-  if (constructor_type == 0)
-    ;
-  else if (TREE_CODE (constructor_type) == RECORD_TYPE
-          || TREE_CODE (constructor_type) == UNION_TYPE)
-    {
-      /* Don't die if there are extra init elts at the end.  */
-      if (constructor_fields == 0)
-       constructor_type = 0;
-      else
-       {
-         constructor_type = TREE_TYPE (constructor_fields);
-         push_member_name (constructor_fields);
-         constructor_depth++;
+                 r->balance = (t->balance < 0);
+                 p->balance = -(t->balance > 0);
+                 t->balance = 0;
+
+                 s = p->parent;
+                 p->parent = t;
+                 r->parent = t;
+                 t->parent = s;
+                 if (s)
+                   {
+                     if (s->left == p)
+                       s->left = t;
+                     else
+                       s->right = t;
+                   }
+                 else
+                   constructor_pending_elts = t;
+               }
+             break;
+           }
+         else
+           {
+             /* p->balance == -1; growth of right side balances the node.  */
+             p->balance = 0;
+             break;
+           }
        }
-    }
-  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    {
-      constructor_type = TREE_TYPE (constructor_type);
-      push_array_bounds (tree_low_cst (constructor_index, 0));
-      constructor_depth++;
-    }
 
-  if (constructor_type == 0)
-    {
-      error_init ("extra brace group at end of initializer");
-      constructor_fields = 0;
-      constructor_unfilled_fields = 0;
-      return;
+      r = p;
+      p = p->parent;
     }
+}
 
-  if (value && TREE_CODE (value) == CONSTRUCTOR)
-    {
-      constructor_constant = TREE_CONSTANT (value);
-      constructor_simple = TREE_STATIC (value);
-      constructor_elements = CONSTRUCTOR_ELTS (value);
-      if (constructor_elements
-         && (TREE_CODE (constructor_type) == RECORD_TYPE
-             || TREE_CODE (constructor_type) == ARRAY_TYPE))
-       set_nonincremental_init ();
-    }
+/* Build AVL tree from a sorted chain.  */
 
-  if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
-    {
-      missing_braces_mentioned = 1;
-      warning_init ("missing braces around initializer");
-    }
+static void
+set_nonincremental_init (void)
+{
+  tree chain;
 
-  if (TREE_CODE (constructor_type) == RECORD_TYPE
-          || TREE_CODE (constructor_type) == UNION_TYPE)
+  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));
+  constructor_elements = 0;
+  if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
-      constructor_fields = TYPE_FIELDS (constructor_type);
+      constructor_unfilled_fields = TYPE_FIELDS (constructor_type);
       /* Skip any nameless bit fields at the beginning.  */
-      while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
-            && DECL_NAME (constructor_fields) == 0)
-       constructor_fields = TREE_CHAIN (constructor_fields);
+      while (constructor_unfilled_fields != 0
+            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+            && DECL_NAME (constructor_unfilled_fields) == 0)
+       constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
 
-      constructor_unfilled_fields = constructor_fields;
-      constructor_bit_index = bitsize_zero_node;
-    }
-  else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
-    {
-      /* Vectors are like simple fixed-size arrays.  */
-      constructor_max_index =
-       build_int_2 (TYPE_VECTOR_SUBPARTS (constructor_type) - 1, 0);
-      constructor_index = convert (bitsizetype, integer_zero_node);
-      constructor_unfilled_index = constructor_index;
     }
   else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
       if (TYPE_DOMAIN (constructor_type))
-       {
-         constructor_max_index
-           = TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type));
-
-         /* Detect non-empty initializations of zero-length arrays.  */
-         if (constructor_max_index == NULL_TREE
-             && TYPE_SIZE (constructor_type))
-           constructor_max_index = build_int_2 (-1, -1);
-
-         /* constructor_max_index needs to be an INTEGER_CST.  Attempts
-            to initialize VLAs will cause a proper error; avoid tree
-            checking errors as well by setting a safe value.  */
-         if (constructor_max_index
-             && TREE_CODE (constructor_max_index) != INTEGER_CST)
-           constructor_max_index = build_int_2 (-1, -1);
-
-         constructor_index
+       constructor_unfilled_index
            = convert (bitsizetype,
                       TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
-       }
       else
-       constructor_index = bitsize_zero_node;
-
-      constructor_unfilled_index = constructor_index;
-      if (value && TREE_CODE (value) == STRING_CST)
-       {
-         /* We need to split the char/wchar array into individual
-            characters, so that we don't have to special case it
-            everywhere.  */
-         set_nonincremental_init_from_string (value);
-       }
-    }
-  else
-    {
-      warning_init ("braces around scalar initializer");
-      constructor_fields = constructor_type;
-      constructor_unfilled_fields = constructor_type;
+       constructor_unfilled_index = bitsize_zero_node;
     }
+  constructor_incremental = 0;
 }
 
-/* At the end of an implicit or explicit brace level,
-   finish up that level of constructor.
-   If we were outputting the elements as they are read, return 0
-   from inner levels (process_init_element ignores that),
-   but return error_mark_node from the outermost level
-   (that's what we want to put in DECL_INITIAL).
-   Otherwise, return a CONSTRUCTOR expression.  */
+/* Build AVL tree from a string constant.  */
 
-tree
-pop_init_level (int implicit)
+static void
+set_nonincremental_init_from_string (tree str)
 {
-  struct constructor_stack *p;
-  tree constructor = 0;
+  tree value, purpose, type;
+  HOST_WIDE_INT val[2];
+  const char *p, *end;
+  int byte, wchar_bytes, charwidth, bitpos;
 
-  if (implicit == 0)
-    {
-      /* When we come to an explicit close brace,
-        pop any inner levels that didn't have explicit braces.  */
-      while (constructor_stack->implicit)
-       process_init_element (pop_init_level (1));
+  if (TREE_CODE (constructor_type) != ARRAY_TYPE)
+    abort ();
 
-      if (constructor_range_stack)
-       abort ();
-    }
+  if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+      == TYPE_PRECISION (char_type_node))
+    wchar_bytes = 1;
+  else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
+          == TYPE_PRECISION (wchar_type_node))
+    wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  else
+    abort ();
 
-  p = constructor_stack;
+  charwidth = TYPE_PRECISION (char_type_node);
+  type = TREE_TYPE (constructor_type);
+  p = TREE_STRING_POINTER (str);
+  end = p + TREE_STRING_LENGTH (str);
 
-  /* Error for initializing a flexible array member, or a zero-length
-     array member in an inappropriate context.  */
-  if (constructor_type && constructor_fields
-      && TREE_CODE (constructor_type) == ARRAY_TYPE
-      && TYPE_DOMAIN (constructor_type)
-      && ! TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
+  for (purpose = bitsize_zero_node;
+       p < end && !tree_int_cst_lt (constructor_max_index, purpose);
+       purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node))
     {
-      /* Silently discard empty initializations.  The parser will
-        already have pedwarned for empty brackets.  */
-      if (integer_zerop (constructor_unfilled_index))
-       constructor_type = NULL_TREE;
-      else if (! TYPE_SIZE (constructor_type))
+      if (wchar_bytes == 1)
        {
-         if (constructor_depth > 2)
-           error_init ("initialization of flexible array member in a nested context");
-         else if (pedantic)
-           pedwarn_init ("initialization of a flexible array member");
-
-         /* We have already issued an error message for the existence
-            of a flexible array member not at the end of the structure.
-            Discard the initializer so that we do not abort later.  */
-         if (TREE_CHAIN (constructor_fields) != NULL_TREE)
-           constructor_type = NULL_TREE;
+         val[1] = (unsigned char) *p++;
+         val[0] = 0;
        }
       else
-       /* Zero-length arrays are no longer special, so we should no longer
-          get here.  */
-       abort ();
-    }
+       {
+         val[0] = 0;
+         val[1] = 0;
+         for (byte = 0; byte < wchar_bytes; byte++)
+           {
+             if (BYTES_BIG_ENDIAN)
+               bitpos = (wchar_bytes - byte - 1) * charwidth;
+             else
+               bitpos = byte * charwidth;
+             val[bitpos < HOST_BITS_PER_WIDE_INT]
+               |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++))
+                  << (bitpos % HOST_BITS_PER_WIDE_INT);
+           }
+       }
 
-  /* Warn when some struct elements are implicitly initialized to zero.  */
-  if (extra_warnings
-      && constructor_type
-      && TREE_CODE (constructor_type) == RECORD_TYPE
-      && constructor_unfilled_fields)
-    {
-       /* Do not warn for flexible array members or zero-length arrays.  */
-       while (constructor_unfilled_fields
-              && (! DECL_SIZE (constructor_unfilled_fields)
-                  || integer_zerop (DECL_SIZE (constructor_unfilled_fields))))
-         constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+      if (!TYPE_UNSIGNED (type))
+       {
+         bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR;
+         if (bitpos < HOST_BITS_PER_WIDE_INT)
+           {
+             if (val[1] & (((HOST_WIDE_INT) 1) << (bitpos - 1)))
+               {
+                 val[1] |= ((HOST_WIDE_INT) -1) << bitpos;
+                 val[0] = -1;
+               }
+           }
+         else if (bitpos == HOST_BITS_PER_WIDE_INT)
+           {
+             if (val[1] < 0)
+               val[0] = -1;
+           }
+         else if (val[0] & (((HOST_WIDE_INT) 1)
+                            << (bitpos - 1 - HOST_BITS_PER_WIDE_INT)))
+           val[0] |= ((HOST_WIDE_INT) -1)
+                     << (bitpos - HOST_BITS_PER_WIDE_INT);
+       }
 
-       /* Do not warn if this level of the initializer uses member
-          designators; it is likely to be deliberate.  */
-       if (constructor_unfilled_fields && !constructor_designated)
-         {
-           push_member_name (constructor_unfilled_fields);
-           warning_init ("missing initializer");
-           RESTORE_SPELLING_DEPTH (constructor_depth);
-         }
+      value = build_int_2 (val[1], val[0]);
+      TREE_TYPE (value) = type;
+      add_pending_init (purpose, value);
     }
 
-  /* Now output all pending elements.  */
-  constructor_incremental = 1;
-  output_pending_init_elements (1);
+  constructor_incremental = 0;
+}
 
-  /* Pad out the end of the structure.  */
-  if (p->replacement_value)
-    /* If this closes a superfluous brace pair,
-       just pass out the element between them.  */
-    constructor = p->replacement_value;
-  else if (constructor_type == 0)
-    ;
-  else if (TREE_CODE (constructor_type) != RECORD_TYPE
-          && TREE_CODE (constructor_type) != UNION_TYPE
-          && TREE_CODE (constructor_type) != ARRAY_TYPE
-          && TREE_CODE (constructor_type) != VECTOR_TYPE)
+/* Return value of FIELD in pending initializer or zero if the field was
+   not initialized yet.  */
+
+static tree
+find_init_member (tree field)
+{
+  struct init_node *p;
+
+  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
-      /* A nonincremental scalar initializer--just return
-        the element, after verifying there is just one.  */
-      if (constructor_elements == 0)
-       {
-         if (!constructor_erroneous)
-           error_init ("empty scalar initializer");
-         constructor = error_mark_node;
-       }
-      else if (TREE_CHAIN (constructor_elements) != 0)
+      if (constructor_incremental
+         && tree_int_cst_lt (field, constructor_unfilled_index))
+       set_nonincremental_init ();
+
+      p = constructor_pending_elts;
+      while (p)
        {
-         error_init ("extra elements in scalar initializer");
-         constructor = TREE_VALUE (constructor_elements);
+         if (tree_int_cst_lt (field, p->purpose))
+           p = p->left;
+         else if (tree_int_cst_lt (p->purpose, field))
+           p = p->right;
+         else
+           return p->value;
        }
-      else
-       constructor = TREE_VALUE (constructor_elements);
     }
-  else
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
-      if (constructor_erroneous)
-       constructor = error_mark_node;
-      else
+      tree bitpos = bit_position (field);
+
+      if (constructor_incremental
+         && (!constructor_unfilled_fields
+             || tree_int_cst_lt (bitpos,
+                                 bit_position (constructor_unfilled_fields))))
+       set_nonincremental_init ();
+
+      p = constructor_pending_elts;
+      while (p)
        {
-         constructor = build_constructor (constructor_type,
-                                          nreverse (constructor_elements));
-         if (constructor_constant)
-           TREE_CONSTANT (constructor) = 1;
-         if (constructor_constant && constructor_simple)
-           TREE_STATIC (constructor) = 1;
+         if (field == p->purpose)
+           return p->value;
+         else if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
+           p = p->left;
+         else
+           p = p->right;
        }
     }
-
-  constructor_type = p->type;
-  constructor_fields = p->fields;
-  constructor_index = p->index;
-  constructor_max_index = p->max_index;
-  constructor_unfilled_index = p->unfilled_index;
-  constructor_unfilled_fields = p->unfilled_fields;
-  constructor_bit_index = p->bit_index;
-  constructor_elements = p->elements;
-  constructor_constant = p->constant;
-  constructor_simple = p->simple;
-  constructor_erroneous = p->erroneous;
-  constructor_incremental = p->incremental;
-  constructor_designated = p->designated;
-  constructor_pending_elts = p->pending_elts;
-  constructor_depth = p->depth;
-  if (!p->implicit)
-    constructor_range_stack = p->range_stack;
-  RESTORE_SPELLING_DEPTH (constructor_depth);
-
-  constructor_stack = p->next;
-  free (p);
-
-  if (constructor == 0)
+  else if (TREE_CODE (constructor_type) == UNION_TYPE)
     {
-      if (constructor_stack == 0)
-       return error_mark_node;
-      return NULL_TREE;
+      if (constructor_elements
+         && TREE_PURPOSE (constructor_elements) == field)
+       return TREE_VALUE (constructor_elements);
     }
-  return constructor;
+  return 0;
 }
 
-/* Common handling for both array range and field name designators.
-   ARRAY argument is nonzero for array ranges.  Returns zero for success.  */
+/* "Output" the next constructor element.
+   At top level, really output it to assembler code now.
+   Otherwise, collect it in a list from which we will make a CONSTRUCTOR.
+   TYPE is the data type that the containing data type wants here.
+   FIELD is the field (a FIELD_DECL) or the index that this element fills.
 
-static int
-set_designator (int array)
+   PENDING if non-nil means output pending elements that belong
+   right after this element.  (PENDING is normally 1;
+   it is 0 while outputting pending elements, to avoid recursion.)  */
+
+static void
+output_init_element (tree value, tree type, tree field, int pending)
 {
-  tree subtype;
-  enum tree_code subcode;
+  if (type == error_mark_node)
+    {
+      constructor_erroneous = 1;
+      return;
+    }
+  if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
+      || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
+         && !(TREE_CODE (value) == STRING_CST
+              && TREE_CODE (type) == ARRAY_TYPE
+              && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
+         && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
+                        TYPE_MAIN_VARIANT (type), COMPARE_STRICT)))
+    value = default_conversion (value);
 
-  /* Don't die if an entire brace-pair level is superfluous
-     in the containing level.  */
-  if (constructor_type == 0)
-    return 1;
+  if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
+      && require_constant_value && !flag_isoc99 && pending)
+    {
+      /* As an extension, allow initializing objects with static storage
+        duration with compound literals (which are then treated just as
+        the brace enclosed list they contain).  */
+      tree decl = COMPOUND_LITERAL_EXPR_DECL (value);
+      value = DECL_INITIAL (decl);
+    }
 
-  /* If there were errors in this designator list already, bail out silently.  */
-  if (designator_errorneous)
-    return 1;
+  if (value == error_mark_node)
+    constructor_erroneous = 1;
+  else if (!TREE_CONSTANT (value))
+    constructor_constant = 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_C_BIT_FIELD (field)
+              && TREE_CODE (value) != INTEGER_CST))
+    constructor_simple = 0;
 
-  if (!designator_depth)
+  if (require_constant_value && ! TREE_CONSTANT (value))
     {
-      if (constructor_range_stack)
-       abort ();
-
-      /* Designator list starts at the level of closest explicit
-        braces.  */
-      while (constructor_stack->implicit)
-       process_init_element (pop_init_level (1));
-      constructor_designated = 1;
-      return 0;
+      error_init ("initializer element is not constant");
+      value = error_mark_node;
     }
+  else if (require_constant_elements
+          && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
+    pedwarn ("initializer element is not computable at load time");
 
-  if (constructor_no_implicit)
+  /* If this field is empty (and not at the end of structure),
+     don't do anything other than checking the initializer.  */
+  if (field
+      && (TREE_TYPE (field) == error_mark_node
+         || (COMPLETE_TYPE_P (TREE_TYPE (field))
+             && integer_zerop (TYPE_SIZE (TREE_TYPE (field)))
+             && (TREE_CODE (constructor_type) == ARRAY_TYPE
+                 || TREE_CHAIN (field)))))
+    return;
+
+  value = digest_init (type, value, require_constant_value);
+  if (value == error_mark_node)
     {
-      error_init ("initialization designators may not nest");
-      return 1;
+      constructor_erroneous = 1;
+      return;
     }
 
-  if (TREE_CODE (constructor_type) == RECORD_TYPE
-      || TREE_CODE (constructor_type) == UNION_TYPE)
+  /* If this element doesn't come next in sequence,
+     put it on constructor_pending_elts.  */
+  if (TREE_CODE (constructor_type) == ARRAY_TYPE
+      && (!constructor_incremental
+         || !tree_int_cst_equal (field, constructor_unfilled_index)))
     {
-      subtype = TREE_TYPE (constructor_fields);
-      if (subtype != error_mark_node)
-       subtype = TYPE_MAIN_VARIANT (subtype);
+      if (constructor_incremental
+         && tree_int_cst_lt (field, constructor_unfilled_index))
+       set_nonincremental_init ();
+
+      add_pending_init (field, value);
+      return;
+    }
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE
+          && (!constructor_incremental
+              || field != constructor_unfilled_fields))
+    {
+      /* We do this for records but not for unions.  In a union,
+        no matter which field is specified, it can be initialized
+        right away since it starts at the beginning of the union.  */
+      if (constructor_incremental)
+       {
+         if (!constructor_unfilled_fields)
+           set_nonincremental_init ();
+         else
+           {
+             tree bitpos, unfillpos;
+
+             bitpos = bit_position (field);
+             unfillpos = bit_position (constructor_unfilled_fields);
+
+             if (tree_int_cst_lt (bitpos, unfillpos))
+               set_nonincremental_init ();
+           }
+       }
+
+      add_pending_init (field, value);
+      return;
     }
-  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+  else if (TREE_CODE (constructor_type) == UNION_TYPE
+          && constructor_elements)
     {
-      subtype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
-    }
-  else
-    abort ();
+      if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
+       warning_init ("initialized field with side-effects overwritten");
 
-  subcode = TREE_CODE (subtype);
-  if (array && subcode != ARRAY_TYPE)
-    {
-      error_init ("array index in non-array initializer");
-      return 1;
+      /* We can have just one union field set.  */
+      constructor_elements = 0;
     }
-  else if (!array && subcode != RECORD_TYPE && subcode != UNION_TYPE)
+
+  /* Otherwise, output this element either to
+     constructor_elements or to the assembler file.  */
+
+  if (field && TREE_CODE (field) == INTEGER_CST)
+    field = copy_node (field);
+  constructor_elements
+    = tree_cons (field, value, constructor_elements);
+
+  /* Advance the variable that indicates sequential elements output.  */
+  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    constructor_unfilled_index
+      = size_binop (PLUS_EXPR, constructor_unfilled_index,
+                   bitsize_one_node);
+  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
-      error_init ("field name not in record or union initializer");
-      return 1;
+      constructor_unfilled_fields
+       = TREE_CHAIN (constructor_unfilled_fields);
+
+      /* Skip any nameless bit fields.  */
+      while (constructor_unfilled_fields != 0
+            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+            && DECL_NAME (constructor_unfilled_fields) == 0)
+       constructor_unfilled_fields =
+         TREE_CHAIN (constructor_unfilled_fields);
     }
+  else if (TREE_CODE (constructor_type) == UNION_TYPE)
+    constructor_unfilled_fields = 0;
 
-  constructor_designated = 1;
-  push_init_level (2);
-  return 0;
+  /* Now output any pending elements which have become next.  */
+  if (pending)
+    output_pending_init_elements (0);
 }
 
-/* If there are range designators in designator list, push a new designator
-   to constructor_range_stack.  RANGE_END is end of such stack range or
-   NULL_TREE if there is no range designator at this level.  */
-
-static void
-push_range_stack (tree range_end)
-{
-  struct constructor_range_stack *p;
+/* Output any pending elements which have become next.
+   As we output elements, constructor_unfilled_{fields,index}
+   advances, which may cause other elements to become next;
+   if so, they too are output.
 
-  p = (struct constructor_range_stack *)
-      ggc_alloc (sizeof (struct constructor_range_stack));
-  p->prev = constructor_range_stack;
-  p->next = 0;
-  p->fields = constructor_fields;
-  p->range_start = constructor_index;
-  p->index = constructor_index;
-  p->stack = constructor_stack;
-  p->range_end = range_end;
-  if (constructor_range_stack)
-    constructor_range_stack->next = p;
-  constructor_range_stack = p;
-}
+   If ALL is 0, we return when there are
+   no more pending elements to output now.
 
-/* Within an array initializer, specify the next index to be initialized.
-   FIRST is that index.  If LAST is nonzero, then initialize a range
-   of indices, running from FIRST through LAST.  */
+   If ALL is 1, we output space as necessary so that
+   we can output all the pending elements.  */
 
-void
-set_init_index (tree first, tree last)
+static void
+output_pending_init_elements (int all)
 {
-  if (set_designator (1))
-    return;
-
-  designator_errorneous = 1;
+  struct init_node *elt = constructor_pending_elts;
+  tree next;
 
-  while ((TREE_CODE (first) == NOP_EXPR
-         || TREE_CODE (first) == CONVERT_EXPR
-         || TREE_CODE (first) == NON_LVALUE_EXPR)
-        && (TYPE_MODE (TREE_TYPE (first))
-            == TYPE_MODE (TREE_TYPE (TREE_OPERAND (first, 0)))))
-    first = TREE_OPERAND (first, 0);
+ retry:
 
-  if (last)
-    while ((TREE_CODE (last) == NOP_EXPR
-           || TREE_CODE (last) == CONVERT_EXPR
-           || TREE_CODE (last) == NON_LVALUE_EXPR)
-          && (TYPE_MODE (TREE_TYPE (last))
-              == TYPE_MODE (TREE_TYPE (TREE_OPERAND (last, 0)))))
-      last = TREE_OPERAND (last, 0);
+  /* Look through the whole pending tree.
+     If we find an element that should be output now,
+     output it.  Otherwise, set NEXT to the element
+     that comes first among those still pending.  */
 
-  if (TREE_CODE (first) != INTEGER_CST)
-    error_init ("nonconstant array index in initializer");
-  else if (last != 0 && TREE_CODE (last) != INTEGER_CST)
-    error_init ("nonconstant array index in initializer");
-  else if (TREE_CODE (constructor_type) != ARRAY_TYPE)
-    error_init ("array index in non-array initializer");
-  else if (constructor_max_index
-          && tree_int_cst_lt (constructor_max_index, first))
-    error_init ("array index in initializer exceeds array bounds");
-  else
+  next = 0;
+  while (elt)
     {
-      constructor_index = convert (bitsizetype, first);
-
-      if (last)
+      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
        {
-         if (tree_int_cst_equal (first, last))
-           last = 0;
-         else if (tree_int_cst_lt (last, first))
+         if (tree_int_cst_equal (elt->purpose,
+                                 constructor_unfilled_index))
+           output_init_element (elt->value,
+                                TREE_TYPE (constructor_type),
+                                constructor_unfilled_index, 0);
+         else if (tree_int_cst_lt (constructor_unfilled_index,
+                                   elt->purpose))
            {
-             error_init ("empty index range in initializer");
-             last = 0;
+             /* Advance to the next smaller node.  */
+             if (elt->left)
+               elt = elt->left;
+             else
+               {
+                 /* We have reached the smallest node bigger than the
+                    current unfilled index.  Fill the space first.  */
+                 next = elt->purpose;
+                 break;
+               }
            }
          else
            {
-             last = convert (bitsizetype, last);
-             if (constructor_max_index != 0
-                 && tree_int_cst_lt (constructor_max_index, last))
+             /* Advance to the next bigger node.  */
+             if (elt->right)
+               elt = elt->right;
+             else
                {
-                 error_init ("array index range in initializer exceeds array bounds");
-                 last = 0;
+                 /* We have reached the biggest node in a subtree.  Find
+                    the parent of it, which is the next bigger node.  */
+                 while (elt->parent && elt->parent->right == elt)
+                   elt = elt->parent;
+                 elt = elt->parent;
+                 if (elt && tree_int_cst_lt (constructor_unfilled_index,
+                                             elt->purpose))
+                   {
+                     next = elt->purpose;
+                     break;
+                   }
                }
            }
        }
+      else if (TREE_CODE (constructor_type) == RECORD_TYPE
+              || TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         tree ctor_unfilled_bitpos, elt_bitpos;
 
-      designator_depth++;
-      designator_errorneous = 0;
-      if (constructor_range_stack || last)
-       push_range_stack (last);
+         /* If the current record is complete we are done.  */
+         if (constructor_unfilled_fields == 0)
+           break;
+
+         ctor_unfilled_bitpos = bit_position (constructor_unfilled_fields);
+         elt_bitpos = bit_position (elt->purpose);
+         /* We can't compare fields here because there might be empty
+            fields in between.  */
+         if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
+           {
+             constructor_unfilled_fields = elt->purpose;
+             output_init_element (elt->value, TREE_TYPE (elt->purpose),
+                                  elt->purpose, 0);
+           }
+         else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
+           {
+             /* Advance to the next smaller node.  */
+             if (elt->left)
+               elt = elt->left;
+             else
+               {
+                 /* We have reached the smallest node bigger than the
+                    current unfilled field.  Fill the space first.  */
+                 next = elt->purpose;
+                 break;
+               }
+           }
+         else
+           {
+             /* Advance to the next bigger node.  */
+             if (elt->right)
+               elt = elt->right;
+             else
+               {
+                 /* We have reached the biggest node in a subtree.  Find
+                    the parent of it, which is the next bigger node.  */
+                 while (elt->parent && elt->parent->right == elt)
+                   elt = elt->parent;
+                 elt = elt->parent;
+                 if (elt
+                     && (tree_int_cst_lt (ctor_unfilled_bitpos,
+                                          bit_position (elt->purpose))))
+                   {
+                     next = elt->purpose;
+                     break;
+                   }
+               }
+           }
+       }
     }
+
+  /* Ordinarily return, but not if we want to output all
+     and there are elements left.  */
+  if (! (all && next != 0))
+    return;
+
+  /* If it's not incremental, just skip over the gap, so that after
+     jumping to retry we will output the next successive element.  */
+  if (TREE_CODE (constructor_type) == RECORD_TYPE
+      || TREE_CODE (constructor_type) == UNION_TYPE)
+    constructor_unfilled_fields = next;
+  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+    constructor_unfilled_index = next;
+
+  /* ELT now points to the node in the pending tree with the next
+     initializer to output.  */
+  goto retry;
 }
+\f
+/* Add one non-braced element to the current constructor level.
+   This adjusts the current position within the constructor's type.
+   This may also start or terminate implicit levels
+   to handle a partly-braced initializer.
 
-/* Within a struct initializer, specify the next field to be initialized.  */
+   Once this has found the correct level for the new element,
+   it calls output_init_element.  */
 
 void
-set_init_label (tree fieldname)
+process_init_element (tree value)
 {
-  tree tail;
+  tree orig_value = value;
+  int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
 
-  if (set_designator (0))
-    return;
+  designator_depth = 0;
+  designator_errorneous = 0;
 
-  designator_errorneous = 1;
+  /* Handle superfluous braces around string cst as in
+     char x[] = {"foo"}; */
+  if (string_flag
+      && constructor_type
+      && TREE_CODE (constructor_type) == ARRAY_TYPE
+      && TREE_CODE (TREE_TYPE (constructor_type)) == INTEGER_TYPE
+      && integer_zerop (constructor_unfilled_index))
+    {
+      if (constructor_stack->replacement_value)
+        error_init ("excess elements in char array initializer");
+      constructor_stack->replacement_value = value;
+      return;
+    }
 
-  if (TREE_CODE (constructor_type) != RECORD_TYPE
-      && TREE_CODE (constructor_type) != UNION_TYPE)
+  if (constructor_stack->replacement_value != 0)
     {
-      error_init ("field name not in record or union initializer");
+      error_init ("excess elements in struct initializer");
       return;
     }
 
-  for (tail = TYPE_FIELDS (constructor_type); tail;
-       tail = TREE_CHAIN (tail))
+  /* Ignore elements of a brace group if it is entirely superfluous
+     and has already been diagnosed.  */
+  if (constructor_type == 0)
+    return;
+
+  /* If we've exhausted any levels that didn't have braces,
+     pop them now.  */
+  while (constructor_stack->implicit)
     {
-      if (DECL_NAME (tail) == fieldname)
+      if ((TREE_CODE (constructor_type) == RECORD_TYPE
+          || TREE_CODE (constructor_type) == UNION_TYPE)
+         && constructor_fields == 0)
+       process_init_element (pop_init_level (1));
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE
+              && (constructor_max_index == 0
+                  || tree_int_cst_lt (constructor_max_index,
+                                      constructor_index)))
+       process_init_element (pop_init_level (1));
+      else
        break;
     }
 
-  if (tail == 0)
-    error ("unknown field `%s' specified in initializer",
-          IDENTIFIER_POINTER (fieldname));
-  else
+  /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once.  */
+  if (constructor_range_stack)
     {
-      constructor_fields = tail;
-      designator_depth++;
-      designator_errorneous = 0;
-      if (constructor_range_stack)
-       push_range_stack (NULL_TREE);
+      /* If value is a compound literal and we'll be just using its
+        content, don't put it into a SAVE_EXPR.  */
+      if (TREE_CODE (value) != COMPOUND_LITERAL_EXPR
+         || !require_constant_value
+         || flag_isoc99)
+       value = save_expr (value);
     }
-}
-\f
-/* Add a new initializer to the tree of pending initializers.  PURPOSE
-   identifies the initializer, either array index or field in a structure.
-   VALUE is the value of that index or field.  */
 
-static void
-add_pending_init (tree purpose, tree value)
-{
-  struct init_node *p, **q, *r;
-
-  q = &constructor_pending_elts;
-  p = 0;
-
-  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+  while (1)
     {
-      while (*q != 0)
+      if (TREE_CODE (constructor_type) == RECORD_TYPE)
        {
-         p = *q;
-         if (tree_int_cst_lt (purpose, p->purpose))
-           q = &p->left;
-         else if (tree_int_cst_lt (p->purpose, purpose))
-           q = &p->right;
-         else
-           {
-             if (TREE_SIDE_EFFECTS (p->value))
-               warning_init ("initialized field with side-effects overwritten");
-             p->value = value;
-             return;
-           }
-       }
-    }
-  else
-    {
-      tree bitpos;
+         tree fieldtype;
+         enum tree_code fieldcode;
 
-      bitpos = bit_position (purpose);
-      while (*q != NULL)
-       {
-         p = *q;
-         if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
-           q = &p->left;
-         else if (p->purpose != purpose)
-           q = &p->right;
-         else
+         if (constructor_fields == 0)
            {
-             if (TREE_SIDE_EFFECTS (p->value))
-               warning_init ("initialized field with side-effects overwritten");
-             p->value = value;
-             return;
+             pedwarn_init ("excess elements in struct initializer");
+             break;
            }
-       }
-    }
-
-  r = (struct init_node *) ggc_alloc (sizeof (struct init_node));
-  r->purpose = purpose;
-  r->value = value;
-
-  *q = r;
-  r->parent = p;
-  r->left = 0;
-  r->right = 0;
-  r->balance = 0;
 
-  while (p)
-    {
-      struct init_node *s;
+         fieldtype = TREE_TYPE (constructor_fields);
+         if (fieldtype != error_mark_node)
+           fieldtype = TYPE_MAIN_VARIANT (fieldtype);
+         fieldcode = TREE_CODE (fieldtype);
 
-      if (r == p->left)
-       {
-         if (p->balance == 0)
-           p->balance = -1;
-         else if (p->balance < 0)
+         /* Error for non-static initialization of a flexible array member.  */
+         if (fieldcode == ARRAY_TYPE
+             && !require_constant_value
+             && TYPE_SIZE (fieldtype) == NULL_TREE
+             && TREE_CHAIN (constructor_fields) == NULL_TREE)
            {
-             if (r->balance < 0)
-               {
-                 /* L rotation.  */
-                 p->left = r->right;
-                 if (p->left)
-                   p->left->parent = p;
-                 r->right = p;
-
-                 p->balance = 0;
-                 r->balance = 0;
-
-                 s = p->parent;
-                 p->parent = r;
-                 r->parent = s;
-                 if (s)
-                   {
-                     if (s->left == p)
-                       s->left = r;
-                     else
-                       s->right = r;
-                   }
-                 else
-                   constructor_pending_elts = r;
-               }
-             else
-               {
-                 /* LR rotation.  */
-                 struct init_node *t = r->right;
-
-                 r->right = t->left;
-                 if (r->right)
-                   r->right->parent = r;
-                 t->left = r;
-
-                 p->left = t->right;
-                 if (p->left)
-                   p->left->parent = p;
-                 t->right = p;
-
-                 p->balance = t->balance < 0;
-                 r->balance = -(t->balance > 0);
-                 t->balance = 0;
-
-                 s = p->parent;
-                 p->parent = t;
-                 r->parent = t;
-                 t->parent = s;
-                 if (s)
-                   {
-                     if (s->left == p)
-                       s->left = t;
-                     else
-                       s->right = t;
-                   }
-                 else
-                   constructor_pending_elts = t;
-               }
+             error_init ("non-static initialization of a flexible array member");
              break;
            }
-         else
+
+         /* Accept a string constant to initialize a subarray.  */
+         if (value != 0
+             && fieldcode == ARRAY_TYPE
+             && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
+             && string_flag)
+           value = orig_value;
+         /* Otherwise, if we have come to a subaggregate,
+            and we don't have an element of its type, push into it.  */
+         else if (value != 0 && !constructor_no_implicit
+                  && value != error_mark_node
+                  && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
+                  && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
+                      || fieldcode == UNION_TYPE))
            {
-             /* p->balance == +1; growth of left side balances the node.  */
-             p->balance = 0;
-             break;
+             push_init_level (1);
+             continue;
            }
-       }
-      else /* r == p->right */
-       {
-         if (p->balance == 0)
-           /* Growth propagation from right side.  */
-           p->balance++;
-         else if (p->balance > 0)
+
+         if (value)
            {
-             if (r->balance > 0)
+             push_member_name (constructor_fields);
+             output_init_element (value, fieldtype, constructor_fields, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
+           }
+         else
+           /* Do the bookkeeping for an element that was
+              directly output as a constructor.  */
+           {
+             /* For a record, keep track of end position of last field.  */
+             if (DECL_SIZE (constructor_fields))
+               constructor_bit_index
+                 = size_binop (PLUS_EXPR,
+                               bit_position (constructor_fields),
+                               DECL_SIZE (constructor_fields));
+
+             /* If the current field was the first one not yet written out,
+                it isn't now, so update.  */
+             if (constructor_unfilled_fields == constructor_fields)
                {
-                 /* R rotation.  */
-                 p->right = r->left;
-                 if (p->right)
-                   p->right->parent = p;
-                 r->left = p;
+                 constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+                 /* Skip any nameless bit fields.  */
+                 while (constructor_unfilled_fields != 0
+                        && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+                        && DECL_NAME (constructor_unfilled_fields) == 0)
+                   constructor_unfilled_fields =
+                     TREE_CHAIN (constructor_unfilled_fields);
+               }
+           }
 
-                 p->balance = 0;
-                 r->balance = 0;
+         constructor_fields = TREE_CHAIN (constructor_fields);
+         /* Skip any nameless bit fields at the beginning.  */
+         while (constructor_fields != 0
+                && DECL_C_BIT_FIELD (constructor_fields)
+                && DECL_NAME (constructor_fields) == 0)
+           constructor_fields = TREE_CHAIN (constructor_fields);
+       }
+      else if (TREE_CODE (constructor_type) == UNION_TYPE)
+       {
+         tree fieldtype;
+         enum tree_code fieldcode;
 
-                 s = p->parent;
-                 p->parent = r;
-                 r->parent = s;
-                 if (s)
-                   {
-                     if (s->left == p)
-                       s->left = r;
-                     else
-                       s->right = r;
-                   }
-                 else
-                   constructor_pending_elts = r;
-               }
-             else /* r->balance == -1 */
-               {
-                 /* RL rotation */
-                 struct init_node *t = r->left;
+         if (constructor_fields == 0)
+           {
+             pedwarn_init ("excess elements in union initializer");
+             break;
+           }
 
-                 r->left = t->right;
-                 if (r->left)
-                   r->left->parent = r;
-                 t->right = r;
+         fieldtype = TREE_TYPE (constructor_fields);
+         if (fieldtype != error_mark_node)
+           fieldtype = TYPE_MAIN_VARIANT (fieldtype);
+         fieldcode = TREE_CODE (fieldtype);
 
-                 p->right = t->left;
-                 if (p->right)
-                   p->right->parent = p;
-                 t->left = p;
+         /* Warn that traditional C rejects initialization of unions.
+            We skip the warning if the value is zero.  This is done
+            under the assumption that the zero initializer in user
+            code appears conditioned on e.g. __STDC__ to avoid
+            "missing initializer" warnings and relies on default
+            initialization to zero in the traditional C case.
+            We also skip the warning if the initializer is designated,
+            again on the assumption that this must be conditional on
+            __STDC__ anyway (and we've already complained about the
+            member-designator already).  */
+         if (warn_traditional && !in_system_header && !constructor_designated
+             && !(value && (integer_zerop (value) || real_zerop (value))))
+           warning ("traditional C rejects initialization of unions");
 
-                 r->balance = (t->balance < 0);
-                 p->balance = -(t->balance > 0);
-                 t->balance = 0;
+         /* Accept a string constant to initialize a subarray.  */
+         if (value != 0
+             && fieldcode == ARRAY_TYPE
+             && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
+             && string_flag)
+           value = orig_value;
+         /* Otherwise, if we have come to a subaggregate,
+            and we don't have an element of its type, push into it.  */
+         else if (value != 0 && !constructor_no_implicit
+                  && value != error_mark_node
+                  && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
+                  && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
+                      || fieldcode == UNION_TYPE))
+           {
+             push_init_level (1);
+             continue;
+           }
 
-                 s = p->parent;
-                 p->parent = t;
-                 r->parent = t;
-                 t->parent = s;
-                 if (s)
-                   {
-                     if (s->left == p)
-                       s->left = t;
-                     else
-                       s->right = t;
-                   }
-                 else
-                   constructor_pending_elts = t;
-               }
-             break;
+         if (value)
+           {
+             push_member_name (constructor_fields);
+             output_init_element (value, fieldtype, constructor_fields, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
            }
          else
+           /* Do the bookkeeping for an element that was
+              directly output as a constructor.  */
            {
-             /* p->balance == -1; growth of right side balances the node.  */
-             p->balance = 0;
-             break;
+             constructor_bit_index = DECL_SIZE (constructor_fields);
+             constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
            }
-       }
-
-      r = p;
-      p = p->parent;
-    }
-}
 
-/* Build AVL tree from a sorted chain.  */
+         constructor_fields = 0;
+       }
+      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+       {
+         tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+         enum tree_code eltcode = TREE_CODE (elttype);
 
-static void
-set_nonincremental_init (void)
-{
-  tree chain;
+         /* Accept a string constant to initialize a subarray.  */
+         if (value != 0
+             && eltcode == ARRAY_TYPE
+             && TREE_CODE (TREE_TYPE (elttype)) == INTEGER_TYPE
+             && string_flag)
+           value = orig_value;
+         /* Otherwise, if we have come to a subaggregate,
+            and we don't have an element of its type, push into it.  */
+         else if (value != 0 && !constructor_no_implicit
+                  && value != error_mark_node
+                  && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype
+                  && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
+                      || eltcode == UNION_TYPE))
+           {
+             push_init_level (1);
+             continue;
+           }
 
-  if (TREE_CODE (constructor_type) != RECORD_TYPE
-      && TREE_CODE (constructor_type) != ARRAY_TYPE)
-    return;
+         if (constructor_max_index != 0
+             && (tree_int_cst_lt (constructor_max_index, constructor_index)
+                 || integer_all_onesp (constructor_max_index)))
+           {
+             pedwarn_init ("excess elements in array initializer");
+             break;
+           }
 
-  for (chain = constructor_elements; chain; chain = TREE_CHAIN (chain))
-    add_pending_init (TREE_PURPOSE (chain), TREE_VALUE (chain));
-  constructor_elements = 0;
-  if (TREE_CODE (constructor_type) == RECORD_TYPE)
-    {
-      constructor_unfilled_fields = TYPE_FIELDS (constructor_type);
-      /* Skip any nameless bit fields at the beginning.  */
-      while (constructor_unfilled_fields != 0
-            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
-            && DECL_NAME (constructor_unfilled_fields) == 0)
-       constructor_unfilled_fields = TREE_CHAIN (constructor_unfilled_fields);
+         /* Now output the actual element.  */
+         if (value)
+           {
+             push_array_bounds (tree_low_cst (constructor_index, 0));
+             output_init_element (value, elttype, constructor_index, 1);
+             RESTORE_SPELLING_DEPTH (constructor_depth);
+           }
 
-    }
-  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    {
-      if (TYPE_DOMAIN (constructor_type))
-       constructor_unfilled_index
-           = convert (bitsizetype,
-                      TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
-      else
-       constructor_unfilled_index = bitsize_zero_node;
-    }
-  constructor_incremental = 0;
-}
+         constructor_index
+           = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
 
-/* Build AVL tree from a string constant.  */
+         if (! value)
+           /* If we are doing the bookkeeping for an element that was
+              directly output as a constructor, we must update
+              constructor_unfilled_index.  */
+           constructor_unfilled_index = constructor_index;
+       }
+      else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
+       {
+         tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
 
-static void
-set_nonincremental_init_from_string (tree str)
-{
-  tree value, purpose, type;
-  HOST_WIDE_INT val[2];
-  const char *p, *end;
-  int byte, wchar_bytes, charwidth, bitpos;
+         /* Do a basic check of initializer size.  Note that vectors
+            always have a fixed size derived from their type.  */
+         if (tree_int_cst_lt (constructor_max_index, constructor_index))
+           {
+             pedwarn_init ("excess elements in vector initializer");
+             break;
+           }
 
-  if (TREE_CODE (constructor_type) != ARRAY_TYPE)
-    abort ();
+         /* Now output the actual element.  */
+         if (value)
+           output_init_element (value, elttype, constructor_index, 1);
 
-  if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
-      == TYPE_PRECISION (char_type_node))
-    wchar_bytes = 1;
-  else if (TYPE_PRECISION (TREE_TYPE (TREE_TYPE (str)))
-          == TYPE_PRECISION (wchar_type_node))
-    wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
-  else
-    abort ();
+         constructor_index
+           = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
 
-  charwidth = TYPE_PRECISION (char_type_node);
-  type = TREE_TYPE (constructor_type);
-  p = TREE_STRING_POINTER (str);
-  end = p + TREE_STRING_LENGTH (str);
+         if (! value)
+           /* If we are doing the bookkeeping for an element that was
+              directly output as a constructor, we must update
+              constructor_unfilled_index.  */
+           constructor_unfilled_index = constructor_index;
+       }
 
-  for (purpose = bitsize_zero_node;
-       p < end && !tree_int_cst_lt (constructor_max_index, purpose);
-       purpose = size_binop (PLUS_EXPR, purpose, bitsize_one_node))
-    {
-      if (wchar_bytes == 1)
+      /* Handle the sole element allowed in a braced initializer
+        for a scalar variable.  */
+      else if (constructor_fields == 0)
        {
-         val[1] = (unsigned char) *p++;
-         val[0] = 0;
+         pedwarn_init ("excess elements in scalar initializer");
+         break;
        }
       else
        {
-         val[0] = 0;
-         val[1] = 0;
-         for (byte = 0; byte < wchar_bytes; byte++)
+         if (value)
+           output_init_element (value, constructor_type, NULL_TREE, 1);
+         constructor_fields = 0;
+       }
+
+      /* Handle range initializers either at this level or anywhere higher
+        in the designator stack.  */
+      if (constructor_range_stack)
+       {
+         struct constructor_range_stack *p, *range_stack;
+         int finish = 0;
+
+         range_stack = constructor_range_stack;
+         constructor_range_stack = 0;
+         while (constructor_stack != range_stack->stack)
            {
-             if (BYTES_BIG_ENDIAN)
-               bitpos = (wchar_bytes - byte - 1) * charwidth;
-             else
-               bitpos = byte * charwidth;
-             val[bitpos < HOST_BITS_PER_WIDE_INT]
-               |= ((unsigned HOST_WIDE_INT) ((unsigned char) *p++))
-                  << (bitpos % HOST_BITS_PER_WIDE_INT);
+             if (!constructor_stack->implicit)
+               abort ();
+             process_init_element (pop_init_level (1));
+           }
+         for (p = range_stack;
+              !p->range_end || tree_int_cst_equal (p->index, p->range_end);
+              p = p->prev)
+           {
+             if (!constructor_stack->implicit)
+               abort ();
+             process_init_element (pop_init_level (1));
            }
-       }
 
-      if (!TREE_UNSIGNED (type))
-       {
-         bitpos = ((wchar_bytes - 1) * charwidth) + HOST_BITS_PER_CHAR;
-         if (bitpos < HOST_BITS_PER_WIDE_INT)
+         p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
+         if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
+           finish = 1;
+
+         while (1)
            {
-             if (val[1] & (((HOST_WIDE_INT) 1) << (bitpos - 1)))
+             constructor_index = p->index;
+             constructor_fields = p->fields;
+             if (finish && p->range_end && p->index == p->range_start)
                {
-                 val[1] |= ((HOST_WIDE_INT) -1) << bitpos;
-                 val[0] = -1;
+                 finish = 0;
+                 p->prev = 0;
                }
+             p = p->next;
+             if (!p)
+               break;
+             push_init_level (2);
+             p->stack = constructor_stack;
+             if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
+               p->index = p->range_start;
            }
-         else if (bitpos == HOST_BITS_PER_WIDE_INT)
-           {
-             if (val[1] < 0)
-               val[0] = -1;
-           }
-         else if (val[0] & (((HOST_WIDE_INT) 1)
-                            << (bitpos - 1 - HOST_BITS_PER_WIDE_INT)))
-           val[0] |= ((HOST_WIDE_INT) -1)
-                     << (bitpos - HOST_BITS_PER_WIDE_INT);
+
+         if (!finish)
+           constructor_range_stack = range_stack;
+         continue;
        }
 
-      value = build_int_2 (val[1], val[0]);
-      TREE_TYPE (value) = type;
-      add_pending_init (purpose, value);
+      break;
     }
 
-  constructor_incremental = 0;
+  constructor_range_stack = 0;
+}
+\f
+/* Build a complete asm-statement, whose components are a CV_QUALIFIER
+   (guaranteed to be 'volatile' or null) and ARGS (represented using
+   an ASM_STMT node).  */
+tree
+build_asm_stmt (tree cv_qualifier, tree args)
+{
+  if (!TREE_OPERAND (args, 0))
+    TREE_OPERAND (args, 0) = cv_qualifier;
+  return add_stmt (args);
 }
 
-/* Return value of FIELD in pending initializer or zero if the field was
-   not initialized yet.  */
-
-static tree
-find_init_member (tree field)
+/* Build an asm-expr, whose components are a STRING, some OUTPUTS,
+   some INPUTS, and some CLOBBERS.  The latter three may be NULL.
+   SIMPLE indicates whether there was anything at all after the
+   string in the asm expression -- asm("blah") and asm("blah" : )
+   are subtly different.  We use a ASM_STMT node to represent this.  */
+tree
+build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
+               bool simple)
 {
-  struct init_node *p;
+  tree tail;
+  tree args;
 
-  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+  /* We can remove output conversions that change the type,
+     but not the mode.  */
+  for (tail = outputs; tail; tail = TREE_CHAIN (tail))
     {
-      if (constructor_incremental
-         && tree_int_cst_lt (field, constructor_unfilled_index))
-       set_nonincremental_init ();
+      tree output = TREE_VALUE (tail);
 
-      p = constructor_pending_elts;
-      while (p)
-       {
-         if (tree_int_cst_lt (field, p->purpose))
-           p = p->left;
-         else if (tree_int_cst_lt (p->purpose, field))
-           p = p->right;
-         else
-           return p->value;
-       }
+      STRIP_NOPS (output);
+      TREE_VALUE (tail) = output;
+
+      /* Allow conversions as LHS here.  build_modify_expr as called below
+        will do the right thing with them.  */
+      while (TREE_CODE (output) == NOP_EXPR
+            || TREE_CODE (output) == CONVERT_EXPR
+            || TREE_CODE (output) == FLOAT_EXPR
+            || TREE_CODE (output) == FIX_TRUNC_EXPR
+            || TREE_CODE (output) == FIX_FLOOR_EXPR
+            || TREE_CODE (output) == FIX_ROUND_EXPR
+            || TREE_CODE (output) == FIX_CEIL_EXPR)
+       output = TREE_OPERAND (output, 0);
+
+      lvalue_or_else (TREE_VALUE (tail), "invalid lvalue in asm statement");
     }
-  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
+
+  /* Remove output conversions that change the type but not the mode.  */
+  for (tail = outputs; tail; tail = TREE_CHAIN (tail))
     {
-      tree bitpos = bit_position (field);
+      tree output = TREE_VALUE (tail);
+      STRIP_NOPS (output);
+      TREE_VALUE (tail) = output;
+    }
 
-      if (constructor_incremental
-         && (!constructor_unfilled_fields
-             || tree_int_cst_lt (bitpos,
-                                 bit_position (constructor_unfilled_fields))))
-       set_nonincremental_init ();
+  /* Perform default conversions on array and function inputs.
+     Don't do this for other types as it would screw up operands
+     expected to be in memory.  */
+  for (tail = inputs; tail; tail = TREE_CHAIN (tail))
+    TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
 
-      p = constructor_pending_elts;
-      while (p)
-       {
-         if (field == p->purpose)
-           return p->value;
-         else if (tree_int_cst_lt (bitpos, bit_position (p->purpose)))
-           p = p->left;
-         else
-           p = p->right;
-       }
-    }
-  else if (TREE_CODE (constructor_type) == UNION_TYPE)
+  args = build_stmt (ASM_STMT, 0, string, outputs, inputs, clobbers);
+
+  /* Simple asm statements are treated as volatile.  */
+  if (simple)
     {
-      if (constructor_elements
-         && TREE_PURPOSE (constructor_elements) == field)
-       return TREE_VALUE (constructor_elements);
+      TREE_OPERAND (args, 0) = ridpointers[RID_VOLATILE];
+      ASM_INPUT_P (args) = 1;
     }
-  return 0;
+  return args;
 }
 
-/* "Output" the next constructor element.
-   At top level, really output it to assembler code now.
-   Otherwise, collect it in a list from which we will make a CONSTRUCTOR.
-   TYPE is the data type that the containing data type wants here.
-   FIELD is the field (a FIELD_DECL) or the index that this element fills.
+/* Expand an ASM statement with operands, handling output operands
+   that are not variables or INDIRECT_REFS by transforming such
+   cases into cases that expand_asm_operands can handle.
 
-   PENDING if non-nil means output pending elements that belong
-   right after this element.  (PENDING is normally 1;
-   it is 0 while outputting pending elements, to avoid recursion.)  */
+   Arguments are same as for expand_asm_operands.  */
 
-static void
-output_init_element (tree value, tree type, tree field, int pending)
+void
+c_expand_asm_operands (tree string, tree outputs, tree inputs,
+                      tree clobbers, int vol, location_t locus)
 {
-  if (type == error_mark_node)
-    {
-      constructor_erroneous = 1;
-      return;
-    }
-  if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
-      || (TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
-         && !(TREE_CODE (value) == STRING_CST
-              && TREE_CODE (type) == ARRAY_TYPE
-              && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
-         && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
-                        TYPE_MAIN_VARIANT (type))))
-    value = default_conversion (value);
+  int noutputs = list_length (outputs);
+  int i;
+  /* o[I] is the place that output number I should be written.  */
+  tree *o = alloca (noutputs * sizeof (tree));
+  tree tail;
 
-  if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
-      && require_constant_value && !flag_isoc99 && pending)
+  /* Record the contents of OUTPUTS before it is modified.  */
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
     {
-      /* As an extension, allow initializing objects with static storage
-        duration with compound literals (which are then treated just as
-        the brace enclosed list they contain).  */
-      tree decl = COMPOUND_LITERAL_EXPR_DECL (value);
-      value = DECL_INITIAL (decl);
+      o[i] = TREE_VALUE (tail);
+      if (o[i] == error_mark_node)
+       return;
     }
 
-  if (value == error_mark_node)
-    constructor_erroneous = 1;
-  else if (!TREE_CONSTANT (value))
-    constructor_constant = 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_C_BIT_FIELD (field)
-              && TREE_CODE (value) != INTEGER_CST))
-    constructor_simple = 0;
+  /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
+     OUTPUTS some trees for where the values were actually stored.  */
+  expand_asm_operands (string, outputs, inputs, clobbers, vol, locus);
 
-  if (require_constant_value && ! TREE_CONSTANT (value))
+  /* Copy all the intermediate outputs into the specified outputs.  */
+  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
     {
-      error_init ("initializer element is not constant");
-      value = error_mark_node;
+      if (o[i] != TREE_VALUE (tail))
+       {
+         expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
+                      NULL_RTX, VOIDmode, EXPAND_NORMAL);
+         free_temp_slots ();
+
+         /* Restore the original value so that it's correct the next
+            time we expand this function.  */
+         TREE_VALUE (tail) = o[i];
+       }
+      /* Detect modification of read-only values.
+        (Otherwise done by build_modify_expr.)  */
+      else
+       {
+         tree type = TREE_TYPE (o[i]);
+         if (TREE_READONLY (o[i])
+             || TYPE_READONLY (type)
+             || ((TREE_CODE (type) == RECORD_TYPE
+                  || TREE_CODE (type) == UNION_TYPE)
+                 && C_TYPE_FIELDS_READONLY (type)))
+           readonly_error (o[i], "modification by `asm'");
+       }
     }
-  else if (require_constant_elements
-          && initializer_constant_valid_p (value, TREE_TYPE (value)) == 0)
-    pedwarn ("initializer element is not computable at load time");
 
-  /* If this field is empty (and not at the end of structure),
-     don't do anything other than checking the initializer.  */
-  if (field
-      && (TREE_TYPE (field) == error_mark_node
-         || (COMPLETE_TYPE_P (TREE_TYPE (field))
-             && integer_zerop (TYPE_SIZE (TREE_TYPE (field)))
-             && (TREE_CODE (constructor_type) == ARRAY_TYPE
-                 || TREE_CHAIN (field)))))
-    return;
+  /* Those MODIFY_EXPRs could do autoincrements.  */
+  emit_queue ();
+}
+\f
+/* Expand a C `return' statement.
+   RETVAL is the expression for what to return,
+   or a null pointer for `return;' with no value.  */
+
+tree
+c_expand_return (tree retval)
+{
+  tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
 
-  value = digest_init (type, value, require_constant_value);
-  if (value == error_mark_node)
+  if (TREE_THIS_VOLATILE (current_function_decl))
+    warning ("function declared `noreturn' has a `return' statement");
+
+  if (!retval)
     {
-      constructor_erroneous = 1;
-      return;
+      current_function_returns_null = 1;
+      if ((warn_return_type || flag_isoc99)
+         && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
+       pedwarn_c99 ("`return' with no value, in function returning non-void");
     }
-
-  /* If this element doesn't come next in sequence,
-     put it on constructor_pending_elts.  */
-  if (TREE_CODE (constructor_type) == ARRAY_TYPE
-      && (!constructor_incremental
-         || !tree_int_cst_equal (field, constructor_unfilled_index)))
+  else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
     {
-      if (constructor_incremental
-         && tree_int_cst_lt (field, constructor_unfilled_index))
-       set_nonincremental_init ();
-
-      add_pending_init (field, value);
-      return;
+      current_function_returns_null = 1;
+      if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
+       pedwarn ("`return' with a value, in function returning void");
     }
-  else if (TREE_CODE (constructor_type) == RECORD_TYPE
-          && (!constructor_incremental
-              || field != constructor_unfilled_fields))
+  else
     {
-      /* We do this for records but not for unions.  In a union,
-        no matter which field is specified, it can be initialized
-        right away since it starts at the beginning of the union.  */
-      if (constructor_incremental)
+      tree t = convert_for_assignment (valtype, retval, _("return"),
+                                      NULL_TREE, NULL_TREE, 0);
+      tree res = DECL_RESULT (current_function_decl);
+      tree inner;
+
+      current_function_returns_value = 1;
+      if (t == error_mark_node)
+       return NULL_TREE;
+
+      inner = t = convert (TREE_TYPE (res), t);
+
+      /* Strip any conversions, additions, and subtractions, and see if
+        we are returning the address of a local variable.  Warn if so.  */
+      while (1)
        {
-         if (!constructor_unfilled_fields)
-           set_nonincremental_init ();
-         else
+         switch (TREE_CODE (inner))
            {
-             tree bitpos, unfillpos;
+           case NOP_EXPR:   case NON_LVALUE_EXPR:  case CONVERT_EXPR:
+           case PLUS_EXPR:
+             inner = TREE_OPERAND (inner, 0);
+             continue;
 
-             bitpos = bit_position (field);
-             unfillpos = bit_position (constructor_unfilled_fields);
+           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);
 
-             if (tree_int_cst_lt (bitpos, unfillpos))
-               set_nonincremental_init ();
-           }
-       }
+               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);
 
-      add_pending_init (field, value);
-      return;
-    }
-  else if (TREE_CODE (constructor_type) == UNION_TYPE
-          && constructor_elements)
-    {
-      if (TREE_SIDE_EFFECTS (TREE_VALUE (constructor_elements)))
-       warning_init ("initialized field with side-effects overwritten");
+               if (POINTER_TYPE_P (TREE_TYPE (op1)))
+                 break;
 
-      /* We can have just one union field set.  */
-      constructor_elements = 0;
-    }
+               inner = TREE_OPERAND (inner, 0);
+               continue;
+             }
 
-  /* Otherwise, output this element either to
-     constructor_elements or to the assembler file.  */
+           case ADDR_EXPR:
+             inner = TREE_OPERAND (inner, 0);
 
-  if (field && TREE_CODE (field) == INTEGER_CST)
-    field = copy_node (field);
-  constructor_elements
-    = tree_cons (field, value, constructor_elements);
+             while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
+               inner = TREE_OPERAND (inner, 0);
 
-  /* Advance the variable that indicates sequential elements output.  */
-  if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    constructor_unfilled_index
-      = size_binop (PLUS_EXPR, constructor_unfilled_index,
-                   bitsize_one_node);
-  else if (TREE_CODE (constructor_type) == RECORD_TYPE)
-    {
-      constructor_unfilled_fields
-       = TREE_CHAIN (constructor_unfilled_fields);
+             if (DECL_P (inner)
+                 && ! DECL_EXTERNAL (inner)
+                 && ! TREE_STATIC (inner)
+                 && DECL_CONTEXT (inner) == current_function_decl)
+               warning ("function returns address of local variable");
+             break;
 
-      /* Skip any nameless bit fields.  */
-      while (constructor_unfilled_fields != 0
-            && DECL_C_BIT_FIELD (constructor_unfilled_fields)
-            && DECL_NAME (constructor_unfilled_fields) == 0)
-       constructor_unfilled_fields =
-         TREE_CHAIN (constructor_unfilled_fields);
+           default:
+             break;
+           }
+
+         break;
+       }
+
+      retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
     }
-  else if (TREE_CODE (constructor_type) == UNION_TYPE)
-    constructor_unfilled_fields = 0;
 
-  /* Now output any pending elements which have become next.  */
-  if (pending)
-    output_pending_init_elements (0);
+ return add_stmt (build_return_stmt (retval));
 }
+\f
+struct c_switch {
+  /* The SWITCH_STMT being built.  */
+  tree switch_stmt;
+  /* A splay-tree mapping the low element of a case range to the high
+     element, or NULL_TREE if there is no high element.  Used to
+     determine whether or not a new case label duplicates an old case
+     label.  We need a tree, rather than simply a hash table, because
+     of the GNU case range extension.  */
+  splay_tree cases;
+  /* The next node on the stack.  */
+  struct c_switch *next;
+};
 
-/* Output any pending elements which have become next.
-   As we output elements, constructor_unfilled_{fields,index}
-   advances, which may cause other elements to become next;
-   if so, they too are output.
+/* A stack of the currently active switch statements.  The innermost
+   switch statement is on the top of the stack.  There is no need to
+   mark the stack for garbage collection because it is only active
+   during the processing of the body of a function, and we never
+   collect at that point.  */
 
-   If ALL is 0, we return when there are
-   no more pending elements to output now.
+static struct c_switch *switch_stack;
 
-   If ALL is 1, we output space as necessary so that
-   we can output all the pending elements.  */
+/* Start a C switch statement, testing expression EXP.  Return the new
+   SWITCH_STMT.  */
 
-static void
-output_pending_init_elements (int all)
+tree
+c_start_case (tree exp)
 {
-  struct init_node *elt = constructor_pending_elts;
-  tree next;
-
- retry:
-
-  /* Look thru the whole pending tree.
-     If we find an element that should be output now,
-     output it.  Otherwise, set NEXT to the element
-     that comes first among those still pending.  */
+  enum tree_code code;
+  tree type, orig_type = error_mark_node;
+  struct c_switch *cs;
 
-  next = 0;
-  while (elt)
+  if (exp != error_mark_node)
     {
-      if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+      code = TREE_CODE (TREE_TYPE (exp));
+      orig_type = TREE_TYPE (exp);
+
+      if (! INTEGRAL_TYPE_P (orig_type)
+         && code != ERROR_MARK)
        {
-         if (tree_int_cst_equal (elt->purpose,
-                                 constructor_unfilled_index))
-           output_init_element (elt->value,
-                                TREE_TYPE (constructor_type),
-                                constructor_unfilled_index, 0);
-         else if (tree_int_cst_lt (constructor_unfilled_index,
-                                   elt->purpose))
-           {
-             /* Advance to the next smaller node.  */
-             if (elt->left)
-               elt = elt->left;
-             else
-               {
-                 /* We have reached the smallest node bigger than the
-                    current unfilled index.  Fill the space first.  */
-                 next = elt->purpose;
-                 break;
-               }
-           }
-         else
-           {
-             /* Advance to the next bigger node.  */
-             if (elt->right)
-               elt = elt->right;
-             else
-               {
-                 /* We have reached the biggest node in a subtree.  Find
-                    the parent of it, which is the next bigger node.  */
-                 while (elt->parent && elt->parent->right == elt)
-                   elt = elt->parent;
-                 elt = elt->parent;
-                 if (elt && tree_int_cst_lt (constructor_unfilled_index,
-                                             elt->purpose))
-                   {
-                     next = elt->purpose;
-                     break;
-                   }
-               }
-           }
+         error ("switch quantity not an integer");
+         exp = integer_zero_node;
        }
-      else if (TREE_CODE (constructor_type) == RECORD_TYPE
-              || TREE_CODE (constructor_type) == UNION_TYPE)
+      else
        {
-         tree ctor_unfilled_bitpos, elt_bitpos;
+         type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+
+         if (warn_traditional && !in_system_header
+             && (type == long_integer_type_node
+                 || type == long_unsigned_type_node))
+           warning ("`long' switch expression not converted to `int' in ISO C");
+
+         exp = default_conversion (exp);
+         type = TREE_TYPE (exp);
+       }
+    }
+
+  /* Add this new SWITCH_STMT to the stack.  */
+  cs = xmalloc (sizeof (*cs));
+  cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
+  cs->cases = splay_tree_new (case_compare, NULL, NULL);
+  cs->next = switch_stack;
+  switch_stack = cs;
+
+  return add_stmt (switch_stack->switch_stmt);
+}
+
+/* Process a case label.  */
 
-         /* If the current record is complete we are done.  */
-         if (constructor_unfilled_fields == 0)
-           break;
+tree
+do_case (tree low_value, tree high_value)
+{
+  tree label = NULL_TREE;
 
-         ctor_unfilled_bitpos = bit_position (constructor_unfilled_fields);
-         elt_bitpos = bit_position (elt->purpose);
-         /* We can't compare fields here because there might be empty
-            fields in between.  */
-         if (tree_int_cst_equal (elt_bitpos, ctor_unfilled_bitpos))
-           {
-             constructor_unfilled_fields = elt->purpose;
-             output_init_element (elt->value, TREE_TYPE (elt->purpose),
-                                  elt->purpose, 0);
-           }
-         else if (tree_int_cst_lt (ctor_unfilled_bitpos, elt_bitpos))
-           {
-             /* Advance to the next smaller node.  */
-             if (elt->left)
-               elt = elt->left;
-             else
-               {
-                 /* We have reached the smallest node bigger than the
-                    current unfilled field.  Fill the space first.  */
-                 next = elt->purpose;
-                 break;
-               }
-           }
-         else
-           {
-             /* Advance to the next bigger node.  */
-             if (elt->right)
-               elt = elt->right;
-             else
-               {
-                 /* We have reached the biggest node in a subtree.  Find
-                    the parent of it, which is the next bigger node.  */
-                 while (elt->parent && elt->parent->right == elt)
-                   elt = elt->parent;
-                 elt = elt->parent;
-                 if (elt
-                     && (tree_int_cst_lt (ctor_unfilled_bitpos,
-                                          bit_position (elt->purpose))))
-                   {
-                     next = elt->purpose;
-                     break;
-                   }
-               }
-           }
+  if (switch_stack)
+    {
+      bool switch_was_empty_p = (SWITCH_BODY (switch_stack->switch_stmt) == NULL_TREE);
+
+      label = c_add_case_label (switch_stack->cases,
+                               SWITCH_COND (switch_stack->switch_stmt),
+                               low_value, high_value);
+      if (label == error_mark_node)
+       label = NULL_TREE;
+      else if (switch_was_empty_p)
+       {
+         /* Attach the first case label to the SWITCH_BODY.  */
+         SWITCH_BODY (switch_stack->switch_stmt) = TREE_CHAIN (switch_stack->switch_stmt);
+         TREE_CHAIN (switch_stack->switch_stmt) = NULL_TREE;
        }
     }
+  else if (low_value)
+    error ("case label not within a switch statement");
+  else
+    error ("`default' label not within a switch statement");
 
-  /* Ordinarily return, but not if we want to output all
-     and there are elements left.  */
-  if (! (all && next != 0))
-    return;
+  return label;
+}
 
-  /* If it's not incremental, just skip over the gap, so that after
-     jumping to retry we will output the next successive element.  */
-  if (TREE_CODE (constructor_type) == RECORD_TYPE
-      || TREE_CODE (constructor_type) == UNION_TYPE)
-    constructor_unfilled_fields = next;
-  else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    constructor_unfilled_index = next;
+/* Finish the switch statement.  */
 
-  /* ELT now points to the node in the pending tree with the next
-     initializer to output.  */
-  goto retry;
+void
+c_finish_case (void)
+{
+  struct c_switch *cs = switch_stack;
+
+  /* Rechain the next statements to the SWITCH_STMT.  */
+  last_tree = cs->switch_stmt;
+
+  /* Pop the stack.  */
+  switch_stack = switch_stack->next;
+  splay_tree_delete (cs->cases);
+  free (cs);
 }
-\f
-/* Add one non-braced element to the current constructor level.
-   This adjusts the current position within the constructor's type.
-   This may also start or terminate implicit levels
-   to handle a partly-braced initializer.
 
-   Once this has found the correct level for the new element,
-   it calls output_init_element.  */
+/* Build a binary-operation expression without default conversions.
+   CODE is the kind of expression to build.
+   This function differs from `build' in several ways:
+   the data type of the result is computed and recorded in it,
+   warnings are generated if arg data types are invalid,
+   special handling for addition and subtraction of pointers is known,
+   and some optimization is done (operations on narrow ints
+   are done in the narrower type when that gives the same result).
+   Constant folding is also done before the result is returned.
 
-void
-process_init_element (tree value)
+   Note that the operands will never have enumeral types, or function
+   or array types, because either they will have the default conversions
+   performed or they have both just been converted to some other type in which
+   the arithmetic is to be done.  */
+
+tree
+build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
+                int convert_p)
 {
-  tree orig_value = value;
-  int string_flag = value != 0 && TREE_CODE (value) == STRING_CST;
+  tree type0, type1;
+  enum tree_code code0, code1;
+  tree op0, op1;
 
-  designator_depth = 0;
-  designator_errorneous = 0;
+  /* Expression code to give to the expression when it is built.
+     Normally this is CODE, which is what the caller asked for,
+     but in some special cases we change it.  */
+  enum tree_code resultcode = code;
 
-  /* Handle superfluous braces around string cst as in
-     char x[] = {"foo"}; */
-  if (string_flag
-      && constructor_type
-      && TREE_CODE (constructor_type) == ARRAY_TYPE
-      && TREE_CODE (TREE_TYPE (constructor_type)) == INTEGER_TYPE
-      && integer_zerop (constructor_unfilled_index))
-    {
-      if (constructor_stack->replacement_value)
-        error_init ("excess elements in char array initializer");
-      constructor_stack->replacement_value = value;
-      return;
-    }
+  /* Data type in which the computation is to be performed.
+     In the simplest cases this is the common type of the arguments.  */
+  tree result_type = NULL;
 
-  if (constructor_stack->replacement_value != 0)
-    {
-      error_init ("excess elements in struct initializer");
-      return;
-    }
+  /* Nonzero means operands have already been type-converted
+     in whatever way is necessary.
+     Zero means they need to be converted to RESULT_TYPE.  */
+  int converted = 0;
 
-  /* Ignore elements of a brace group if it is entirely superfluous
-     and has already been diagnosed.  */
-  if (constructor_type == 0)
-    return;
+  /* Nonzero means create the expression with this type, rather than
+     RESULT_TYPE.  */
+  tree build_type = 0;
 
-  /* If we've exhausted any levels that didn't have braces,
-     pop them now.  */
-  while (constructor_stack->implicit)
+  /* Nonzero means after finally constructing the expression
+     convert it to this type.  */
+  tree final_type = 0;
+
+  /* Nonzero if this is an operation like MIN or MAX which can
+     safely be computed in short if both args are promoted shorts.
+     Also implies COMMON.
+     -1 indicates a bitwise operation; this makes a difference
+     in the exact conditions for when it is safe to do the operation
+     in a narrower mode.  */
+  int shorten = 0;
+
+  /* Nonzero if this is a comparison operation;
+     if both args are promoted shorts, compare the original shorts.
+     Also implies COMMON.  */
+  int short_compare = 0;
+
+  /* Nonzero if this is a right-shift operation, which can be computed on the
+     original short and then promoted if the operand is a promoted short.  */
+  int short_shift = 0;
+
+  /* Nonzero means set RESULT_TYPE to the common type of the args.  */
+  int common = 0;
+
+  if (convert_p)
     {
-      if ((TREE_CODE (constructor_type) == RECORD_TYPE
-          || TREE_CODE (constructor_type) == UNION_TYPE)
-         && constructor_fields == 0)
-       process_init_element (pop_init_level (1));
-      else if (TREE_CODE (constructor_type) == ARRAY_TYPE
-              && (constructor_max_index == 0
-                  || tree_int_cst_lt (constructor_max_index,
-                                      constructor_index)))
-       process_init_element (pop_init_level (1));
-      else
-       break;
+      op0 = default_conversion (orig_op0);
+      op1 = default_conversion (orig_op1);
     }
-
-  /* In the case of [LO ... HI] = VALUE, only evaluate VALUE once.  */
-  if (constructor_range_stack)
+  else
     {
-      /* If value is a compound literal and we'll be just using its
-        content, don't put it into a SAVE_EXPR.  */
-      if (TREE_CODE (value) != COMPOUND_LITERAL_EXPR
-         || !require_constant_value
-         || flag_isoc99)
-       value = save_expr (value);
+      op0 = orig_op0;
+      op1 = orig_op1;
     }
 
-  while (1)
-    {
-      if (TREE_CODE (constructor_type) == RECORD_TYPE)
-       {
-         tree fieldtype;
-         enum tree_code fieldcode;
+  type0 = TREE_TYPE (op0);
+  type1 = TREE_TYPE (op1);
 
-         if (constructor_fields == 0)
-           {
-             pedwarn_init ("excess elements in struct initializer");
-             break;
-           }
+  /* The expression codes of the data types of the arguments tell us
+     whether the arguments are integers, floating, pointers, etc.  */
+  code0 = TREE_CODE (type0);
+  code1 = TREE_CODE (type1);
+
+  /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
+  STRIP_TYPE_NOPS (op0);
+  STRIP_TYPE_NOPS (op1);
+
+  /* If an error was already reported for one of the arguments,
+     avoid reporting another error.  */
+
+  if (code0 == ERROR_MARK || code1 == ERROR_MARK)
+    return error_mark_node;
+
+  switch (code)
+    {
+    case PLUS_EXPR:
+      /* Handle the pointer + int case.  */
+      if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+       return pointer_int_sum (PLUS_EXPR, op0, op1);
+      else if (code1 == POINTER_TYPE && code0 == INTEGER_TYPE)
+       return pointer_int_sum (PLUS_EXPR, op1, op0);
+      else
+       common = 1;
+      break;
 
-         fieldtype = TREE_TYPE (constructor_fields);
-         if (fieldtype != error_mark_node)
-           fieldtype = TYPE_MAIN_VARIANT (fieldtype);
-         fieldcode = TREE_CODE (fieldtype);
+    case MINUS_EXPR:
+      /* Subtraction of two similar pointers.
+        We must subtract them as integers, then divide by object size.  */
+      if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
+         && comp_target_types (type0, type1, 1))
+       return pointer_diff (op0, op1);
+      /* Handle pointer minus int.  Just like pointer plus int.  */
+      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+       return pointer_int_sum (MINUS_EXPR, op0, op1);
+      else
+       common = 1;
+      break;
 
-         /* Error for non-static initialization of a flexible array member.  */
-         if (fieldcode == ARRAY_TYPE
-             && !require_constant_value
-             && TYPE_SIZE (fieldtype) == NULL_TREE
-             && TREE_CHAIN (constructor_fields) == NULL_TREE)
-           {
-             error_init ("non-static initialization of a flexible array member");
-             break;
-           }
+    case MULT_EXPR:
+      common = 1;
+      break;
 
-         /* Accept a string constant to initialize a subarray.  */
-         if (value != 0
-             && fieldcode == ARRAY_TYPE
-             && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
-             && string_flag)
-           value = orig_value;
-         /* Otherwise, if we have come to a subaggregate,
-            and we don't have an element of its type, push into it.  */
-         else if (value != 0 && !constructor_no_implicit
-                  && value != error_mark_node
-                  && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
-                  && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
-                      || fieldcode == UNION_TYPE))
-           {
-             push_init_level (1);
-             continue;
-           }
+    case TRUNC_DIV_EXPR:
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+    case EXACT_DIV_EXPR:
+      /* Floating point division by zero is a legitimate way to obtain
+        infinities and NaNs.  */
+      if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
+       warning ("division by zero");
 
-         if (value)
-           {
-             push_member_name (constructor_fields);
-             output_init_element (value, fieldtype, constructor_fields, 1);
-             RESTORE_SPELLING_DEPTH (constructor_depth);
-           }
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+          || code0 == COMPLEX_TYPE || code0 == VECTOR_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+             || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE))
+       {
+         if (!(code0 == INTEGER_TYPE && code1 == INTEGER_TYPE))
+           resultcode = RDIV_EXPR;
          else
-           /* Do the bookkeeping for an element that was
-              directly output as a constructor.  */
-           {
-             /* For a record, keep track of end position of last field.  */
-             if (DECL_SIZE (constructor_fields))
-               constructor_bit_index
-                 = size_binop (PLUS_EXPR,
-                               bit_position (constructor_fields),
-                               DECL_SIZE (constructor_fields));
+           /* Although it would be tempting to shorten always here, that
+              loses on some targets, since the modulo instruction is
+              undefined if the quotient can't be represented in the
+              computation mode.  We shorten only if unsigned or if
+              dividing by something we know != -1.  */
+           shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
+                      || (TREE_CODE (op1) == INTEGER_CST
+                          && ! integer_all_onesp (op1)));
+         common = 1;
+       }
+      break;
 
-             /* If the current field was the first one not yet written out,
-                it isn't now, so update.  */
-             if (constructor_unfilled_fields == constructor_fields)
-               {
-                 constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
-                 /* Skip any nameless bit fields.  */
-                 while (constructor_unfilled_fields != 0
-                        && DECL_C_BIT_FIELD (constructor_unfilled_fields)
-                        && DECL_NAME (constructor_unfilled_fields) == 0)
-                   constructor_unfilled_fields =
-                     TREE_CHAIN (constructor_unfilled_fields);
-               }
-           }
+    case BIT_AND_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+       shorten = -1;
+      else if (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE)
+       common = 1;
+      break;
 
-         constructor_fields = TREE_CHAIN (constructor_fields);
-         /* Skip any nameless bit fields at the beginning.  */
-         while (constructor_fields != 0
-                && DECL_C_BIT_FIELD (constructor_fields)
-                && DECL_NAME (constructor_fields) == 0)
-           constructor_fields = TREE_CHAIN (constructor_fields);
-       }
-      else if (TREE_CODE (constructor_type) == UNION_TYPE)
-       {
-         tree fieldtype;
-         enum tree_code fieldcode;
+    case TRUNC_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+      if (warn_div_by_zero && skip_evaluation == 0 && integer_zerop (op1))
+       warning ("division by zero");
 
-         if (constructor_fields == 0)
-           {
-             pedwarn_init ("excess elements in union initializer");
-             break;
-           }
+      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+       {
+         /* Although it would be tempting to shorten always here, that loses
+            on some targets, since the modulo instruction is undefined if the
+            quotient can't be represented in the computation mode.  We shorten
+            only if unsigned or if dividing by something we know != -1.  */
+         shorten = (TYPE_UNSIGNED (TREE_TYPE (orig_op0))
+                    || (TREE_CODE (op1) == INTEGER_CST
+                        && ! integer_all_onesp (op1)));
+         common = 1;
+       }
+      break;
 
-         fieldtype = TREE_TYPE (constructor_fields);
-         if (fieldtype != error_mark_node)
-           fieldtype = TYPE_MAIN_VARIANT (fieldtype);
-         fieldcode = TREE_CODE (fieldtype);
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+      if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
+          || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
+             || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
+       {
+         /* Result of these operations is always an int,
+            but that does not mean the operands should be
+            converted to ints!  */
+         result_type = integer_type_node;
+         op0 = lang_hooks.truthvalue_conversion (op0);
+         op1 = lang_hooks.truthvalue_conversion (op1);
+         converted = 1;
+       }
+      break;
 
-         /* Warn that traditional C rejects initialization of unions.
-            We skip the warning if the value is zero.  This is done
-            under the assumption that the zero initializer in user
-            code appears conditioned on e.g. __STDC__ to avoid
-            "missing initializer" warnings and relies on default
-            initialization to zero in the traditional C case.
-            We also skip the warning if the initializer is designated,
-            again on the assumption that this must be conditional on
-            __STDC__ anyway (and we've already complained about the
-            member-designator already).  */
-         if (warn_traditional && !in_system_header && !constructor_designated
-             && !(value && (integer_zerop (value) || real_zerop (value))))
-           warning ("traditional C rejects initialization of unions");
+      /* Shift operations: result has same type as first operand;
+        always convert second operand to int.
+        Also set SHORT_SHIFT if shifting rightward.  */
 
-         /* Accept a string constant to initialize a subarray.  */
-         if (value != 0
-             && fieldcode == ARRAY_TYPE
-             && TREE_CODE (TREE_TYPE (fieldtype)) == INTEGER_TYPE
-             && string_flag)
-           value = orig_value;
-         /* Otherwise, if we have come to a subaggregate,
-            and we don't have an element of its type, push into it.  */
-         else if (value != 0 && !constructor_no_implicit
-                  && value != error_mark_node
-                  && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != fieldtype
-                  && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
-                      || fieldcode == UNION_TYPE))
+    case RSHIFT_EXPR:
+      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+       {
+         if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
            {
-             push_init_level (1);
-             continue;
-           }
+             if (tree_int_cst_sgn (op1) < 0)
+               warning ("right shift count is negative");
+             else
+               {
+                 if (! integer_zerop (op1))
+                   short_shift = 1;
 
-         if (value)
-           {
-             push_member_name (constructor_fields);
-             output_init_element (value, fieldtype, constructor_fields, 1);
-             RESTORE_SPELLING_DEPTH (constructor_depth);
-           }
-         else
-           /* Do the bookkeeping for an element that was
-              directly output as a constructor.  */
-           {
-             constructor_bit_index = DECL_SIZE (constructor_fields);
-             constructor_unfilled_fields = TREE_CHAIN (constructor_fields);
+                 if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+                   warning ("right shift count >= width of type");
+               }
            }
 
-         constructor_fields = 0;
+         /* Use the type of the value to be shifted.  */
+         result_type = type0;
+         /* Convert the shift-count to an integer, regardless of size
+            of value being shifted.  */
+         if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+           op1 = convert (integer_type_node, op1);
+         /* Avoid converting op1 to result_type later.  */
+         converted = 1;
        }
-      else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-       {
-         tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
-         enum tree_code eltcode = TREE_CODE (elttype);
+      break;
 
-         /* Accept a string constant to initialize a subarray.  */
-         if (value != 0
-             && eltcode == ARRAY_TYPE
-             && TREE_CODE (TREE_TYPE (elttype)) == INTEGER_TYPE
-             && string_flag)
-           value = orig_value;
-         /* Otherwise, if we have come to a subaggregate,
-            and we don't have an element of its type, push into it.  */
-         else if (value != 0 && !constructor_no_implicit
-                  && value != error_mark_node
-                  && TYPE_MAIN_VARIANT (TREE_TYPE (value)) != elttype
-                  && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
-                      || eltcode == UNION_TYPE))
+    case LSHIFT_EXPR:
+      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+       {
+         if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
            {
-             push_init_level (1);
-             continue;
+             if (tree_int_cst_sgn (op1) < 0)
+               warning ("left shift count is negative");
+
+             else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+               warning ("left shift count >= width of type");
            }
 
-         if (constructor_max_index != 0
-             && (tree_int_cst_lt (constructor_max_index, constructor_index)
-                 || integer_all_onesp (constructor_max_index)))
-           {
-             pedwarn_init ("excess elements in array initializer");
-             break;
-           }
+         /* Use the type of the value to be shifted.  */
+         result_type = type0;
+         /* Convert the shift-count to an integer, regardless of size
+            of value being shifted.  */
+         if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+           op1 = convert (integer_type_node, op1);
+         /* Avoid converting op1 to result_type later.  */
+         converted = 1;
+       }
+      break;
 
-         /* Now output the actual element.  */
-         if (value)
+    case RROTATE_EXPR:
+    case LROTATE_EXPR:
+      if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
+       {
+         if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
            {
-             push_array_bounds (tree_low_cst (constructor_index, 0));
-             output_init_element (value, elttype, constructor_index, 1);
-             RESTORE_SPELLING_DEPTH (constructor_depth);
+             if (tree_int_cst_sgn (op1) < 0)
+               warning ("shift count is negative");
+             else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+               warning ("shift count >= width of type");
            }
 
-         constructor_index
-           = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
-
-         if (! value)
-           /* If we are doing the bookkeeping for an element that was
-              directly output as a constructor, we must update
-              constructor_unfilled_index.  */
-           constructor_unfilled_index = constructor_index;
+         /* Use the type of the value to be shifted.  */
+         result_type = type0;
+         /* Convert the shift-count to an integer, regardless of size
+            of value being shifted.  */
+         if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
+           op1 = convert (integer_type_node, op1);
+         /* Avoid converting op1 to result_type later.  */
+         converted = 1;
        }
-      else if (TREE_CODE (constructor_type) == VECTOR_TYPE)
-       {
-         tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+      break;
 
-         /* Do a basic check of initializer size.  Note that vectors
-            always have a fixed size derived from their type.  */
-         if (tree_int_cst_lt (constructor_max_index, constructor_index))
+    case EQ_EXPR:
+    case NE_EXPR:
+      if (warn_float_equal && (code0 == REAL_TYPE || code1 == REAL_TYPE))
+       warning ("comparing floating point with == or != is unsafe");
+      /* Result of comparison is always int,
+        but don't convert the args to int!  */
+      build_type = integer_type_node;
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+          || code0 == COMPLEX_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+             || code1 == COMPLEX_TYPE))
+       short_compare = 1;
+      else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
+       {
+         tree tt0 = TREE_TYPE (type0);
+         tree tt1 = TREE_TYPE (type1);
+         /* Anything compares with void *.  void * compares with anything.
+            Otherwise, the targets must be compatible
+            and both must be object or both incomplete.  */
+         if (comp_target_types (type0, type1, 1))
+           result_type = common_type (type0, type1);
+         else if (VOID_TYPE_P (tt0))
            {
-             pedwarn_init ("excess elements in vector initializer");
-             break;
+             /* op0 != orig_op0 detects the case of something
+                whose value is 0 but which isn't a valid null ptr const.  */
+             if (pedantic && (!integer_zerop (op0) || op0 != orig_op0)
+                 && TREE_CODE (tt1) == FUNCTION_TYPE)
+               pedwarn ("ISO C forbids comparison of `void *' with function pointer");
            }
+         else if (VOID_TYPE_P (tt1))
+           {
+             if (pedantic && (!integer_zerop (op1) || op1 != orig_op1)
+                 && TREE_CODE (tt0) == FUNCTION_TYPE)
+               pedwarn ("ISO C forbids comparison of `void *' with function pointer");
+           }
+         else
+           pedwarn ("comparison of distinct pointer types lacks a cast");
 
-         /* Now output the actual element.  */
-         if (value)
-           output_init_element (value, elttype, constructor_index, 1);
-
-         constructor_index
-           = size_binop (PLUS_EXPR, constructor_index, bitsize_one_node);
-
-         if (! value)
-           /* If we are doing the bookkeeping for an element that was
-              directly output as a constructor, we must update
-              constructor_unfilled_index.  */
-           constructor_unfilled_index = constructor_index;
+         if (result_type == NULL_TREE)
+           result_type = ptr_type_node;
        }
-
-      /* Handle the sole element allowed in a braced initializer
-        for a scalar variable.  */
-      else if (constructor_fields == 0)
+      else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
+              && integer_zerop (op1))
+       result_type = type0;
+      else if (code1 == POINTER_TYPE && TREE_CODE (op0) == INTEGER_CST
+              && integer_zerop (op0))
+       result_type = type1;
+      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
        {
-         pedwarn_init ("excess elements in scalar initializer");
-         break;
+         result_type = type0;
+         pedwarn ("comparison between pointer and integer");
        }
-      else
+      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
        {
-         if (value)
-           output_init_element (value, constructor_type, NULL_TREE, 1);
-         constructor_fields = 0;
+         result_type = type1;
+         pedwarn ("comparison between pointer and integer");
        }
+      break;
 
-      /* Handle range initializers either at this level or anywhere higher
-        in the designator stack.  */
-      if (constructor_range_stack)
+    case MAX_EXPR:
+    case MIN_EXPR:
+      if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+         && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+       shorten = 1;
+      else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
        {
-         struct constructor_range_stack *p, *range_stack;
-         int finish = 0;
-
-         range_stack = constructor_range_stack;
-         constructor_range_stack = 0;
-         while (constructor_stack != range_stack->stack)
+         if (comp_target_types (type0, type1, 1))
            {
-             if (!constructor_stack->implicit)
-               abort ();
-             process_init_element (pop_init_level (1));
+             result_type = common_type (type0, type1);
+             if (pedantic
+                 && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+               pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
            }
-         for (p = range_stack;
-              !p->range_end || tree_int_cst_equal (p->index, p->range_end);
-              p = p->prev)
+         else
            {
-             if (!constructor_stack->implicit)
-               abort ();
-             process_init_element (pop_init_level (1));
+             result_type = ptr_type_node;
+             pedwarn ("comparison of distinct pointer types lacks a cast");
            }
+       }
+      break;
 
-         p->index = size_binop (PLUS_EXPR, p->index, bitsize_one_node);
-         if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
-           finish = 1;
-
-         while (1)
+    case LE_EXPR:
+    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, 1))
            {
-             constructor_index = p->index;
-             constructor_fields = p->fields;
-             if (finish && p->range_end && p->index == p->range_start)
-               {
-                 finish = 0;
-                 p->prev = 0;
-               }
-             p = p->next;
-             if (!p)
-               break;
-             push_init_level (2);
-             p->stack = constructor_stack;
-             if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
-               p->index = p->range_start;
+             result_type = common_type (type0, type1);
+             if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
+                 != !COMPLETE_TYPE_P (TREE_TYPE (type1)))
+               pedwarn ("comparison of complete and incomplete pointers");
+             else if (pedantic
+                      && TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+               pedwarn ("ISO C forbids ordered comparisons of pointers to functions");
+           }
+         else
+           {
+             result_type = ptr_type_node;
+             pedwarn ("comparison of distinct pointer types lacks a cast");
            }
-
-         if (!finish)
-           constructor_range_stack = range_stack;
-         continue;
        }
-
+      else if (code0 == POINTER_TYPE && TREE_CODE (op1) == INTEGER_CST
+              && integer_zerop (op1))
+       {
+         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 = type1;
+         if (pedantic)
+           pedwarn ("ordered comparison of pointer with integer zero");
+       }
+      else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
+       {
+         result_type = type0;
+         pedwarn ("comparison between pointer and integer");
+       }
+      else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
+       {
+         result_type = type1;
+         pedwarn ("comparison between pointer and integer");
+       }
       break;
-    }
-
-  constructor_range_stack = 0;
-}
-\f
-/* Build a simple asm-statement, from one string literal.  */
-tree
-simple_asm_stmt (tree expr)
-{
-  STRIP_NOPS (expr);
-
-  if (TREE_CODE (expr) == ADDR_EXPR)
-    expr = TREE_OPERAND (expr, 0);
-
-  if (TREE_CODE (expr) == STRING_CST)
-    {
-      tree stmt;
-
-      /* Simple asm statements are treated as volatile.  */
-      stmt = add_stmt (build_stmt (ASM_STMT, ridpointers[(int) RID_VOLATILE],
-                                  expr, NULL_TREE, NULL_TREE, NULL_TREE));
-      ASM_INPUT_P (stmt) = 1;
-      return stmt;
-    }
-
-  error ("argument of `asm' is not a constant string");
-  return NULL_TREE;
-}
-
-/* Build an asm-statement, whose components are a CV_QUALIFIER, a
-   STRING, some OUTPUTS, some INPUTS, and some CLOBBERS.  */
 
-tree
-build_asm_stmt (tree cv_qualifier, tree string, tree outputs, tree inputs, tree clobbers)
-{
-  tree tail;
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+      build_type = integer_type_node;
+      if (code0 != REAL_TYPE || code1 != REAL_TYPE)
+       {
+         error ("unordered comparison on non-floating point argument");
+         return error_mark_node;
+       }
+      common = 1;
+      break;
 
-  if (TREE_CODE (string) != STRING_CST)
-    {
-      error ("asm template is not a string constant");
-      return NULL_TREE;
+    default:
+      break;
     }
 
-  if (cv_qualifier != NULL_TREE
-      && cv_qualifier != ridpointers[(int) RID_VOLATILE])
-    {
-      warning ("%s qualifier ignored on asm",
-              IDENTIFIER_POINTER (cv_qualifier));
-      cv_qualifier = NULL_TREE;
-    }
+  if (code0 == ERROR_MARK || code1 == ERROR_MARK)
+    return error_mark_node;
 
-  /* We can remove output conversions that change the type,
-     but not the mode.  */
-  for (tail = outputs; tail; tail = TREE_CHAIN (tail))
+  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
+       || code0 == VECTOR_TYPE)
+      &&
+      (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
+       || code1 == VECTOR_TYPE))
     {
-      tree output = TREE_VALUE (tail);
-
-      STRIP_NOPS (output);
-      TREE_VALUE (tail) = output;
-
-      /* Allow conversions as LHS here.  build_modify_expr as called below
-        will do the right thing with them.  */
-      while (TREE_CODE (output) == NOP_EXPR
-            || TREE_CODE (output) == CONVERT_EXPR
-            || TREE_CODE (output) == FLOAT_EXPR
-            || TREE_CODE (output) == FIX_TRUNC_EXPR
-            || TREE_CODE (output) == FIX_FLOOR_EXPR
-            || TREE_CODE (output) == FIX_ROUND_EXPR
-            || TREE_CODE (output) == FIX_CEIL_EXPR)
-       output = TREE_OPERAND (output, 0);
+      int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
 
-      lvalue_or_else (TREE_VALUE (tail), "invalid lvalue in asm statement");
-    }
+      if (shorten || common || short_compare)
+       result_type = common_type (type0, type1);
 
-  /* Remove output conversions that change the type but not the mode.  */
-  for (tail = outputs; tail; tail = TREE_CHAIN (tail))
-    {
-      tree output = TREE_VALUE (tail);
-      STRIP_NOPS (output);
-      TREE_VALUE (tail) = output;
-    }
+      /* For certain operations (which identify themselves by shorten != 0)
+        if both args were extended from the same smaller type,
+        do the arithmetic in that type and then extend.
 
-  /* Perform default conversions on array and function inputs.
-     Don't do this for other types as it would screw up operands
-     expected to be in memory.  */
-  for (tail = inputs; tail; tail = TREE_CHAIN (tail))
-    TREE_VALUE (tail) = default_function_array_conversion (TREE_VALUE (tail));
+        shorten !=0 and !=1 indicates a bitwise operation.
+        For them, this optimization is safe only if
+        both args are zero-extended or both are sign-extended.
+        Otherwise, we might change the result.
+        Eg, (short)-1 | (unsigned short)-1 is (int)-1
+        but calculated in (unsigned short) it would be (unsigned short)-1.  */
 
-  return add_stmt (build_stmt (ASM_STMT, cv_qualifier, string,
-                              outputs, inputs, clobbers));
-}
+      if (shorten && none_complex)
+       {
+         int unsigned0, unsigned1;
+         tree arg0 = get_narrower (op0, &unsigned0);
+         tree arg1 = get_narrower (op1, &unsigned1);
+         /* UNS is 1 if the operation to be done is an unsigned one.  */
+         int uns = TYPE_UNSIGNED (result_type);
+         tree type;
 
-/* Expand an ASM statement with operands, handling output operands
-   that are not variables or INDIRECT_REFS by transforming such
-   cases into cases that expand_asm_operands can handle.
+         final_type = result_type;
 
-   Arguments are same as for expand_asm_operands.  */
+         /* Handle the case that OP0 (or OP1) does not *contain* a conversion
+            but it *requires* conversion to FINAL_TYPE.  */
 
-void
-c_expand_asm_operands (tree string, tree outputs, tree inputs,
-                      tree clobbers, int vol, const char *filename,
-                      int line)
-{
-  int noutputs = list_length (outputs);
-  int i;
-  /* o[I] is the place that output number I should be written.  */
-  tree *o = (tree *) alloca (noutputs * sizeof (tree));
-  tree tail;
+         if ((TYPE_PRECISION (TREE_TYPE (op0))
+              == TYPE_PRECISION (TREE_TYPE (arg0)))
+             && TREE_TYPE (op0) != final_type)
+           unsigned0 = TYPE_UNSIGNED (TREE_TYPE (op0));
+         if ((TYPE_PRECISION (TREE_TYPE (op1))
+              == TYPE_PRECISION (TREE_TYPE (arg1)))
+             && TREE_TYPE (op1) != final_type)
+           unsigned1 = TYPE_UNSIGNED (TREE_TYPE (op1));
 
-  /* Record the contents of OUTPUTS before it is modified.  */
-  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
-    {
-      o[i] = TREE_VALUE (tail);
-      if (o[i] == error_mark_node)
-       return;
-    }
+         /* Now UNSIGNED0 is 1 if ARG0 zero-extends to FINAL_TYPE.  */
 
-  /* Generate the ASM_OPERANDS insn; store into the TREE_VALUEs of
-     OUTPUTS some trees for where the values were actually stored.  */
-  expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line);
+         /* For bitwise operations, signedness of nominal type
+            does not matter.  Consider only how operands were extended.  */
+         if (shorten == -1)
+           uns = unsigned0;
 
-  /* Copy all the intermediate outputs into the specified outputs.  */
-  for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
-    {
-      if (o[i] != TREE_VALUE (tail))
-       {
-         expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
-                      NULL_RTX, VOIDmode, EXPAND_NORMAL);
-         free_temp_slots ();
+         /* Note that in all three cases below we refrain from optimizing
+            an unsigned operation on sign-extended args.
+            That would not be valid.  */
 
-         /* Restore the original value so that it's correct the next
-            time we expand this function.  */
-         TREE_VALUE (tail) = o[i];
-       }
-      /* Detect modification of read-only values.
-        (Otherwise done by build_modify_expr.)  */
-      else
-       {
-         tree type = TREE_TYPE (o[i]);
-         if (TREE_READONLY (o[i])
-             || TYPE_READONLY (type)
-             || ((TREE_CODE (type) == RECORD_TYPE
-                  || TREE_CODE (type) == UNION_TYPE)
-                 && C_TYPE_FIELDS_READONLY (type)))
-           readonly_warning (o[i], "modification by `asm'");
+         /* Both args variable: if both extended in same way
+            from same width, do it in that width.
+            Do it unsigned if args were zero-extended.  */
+         if ((TYPE_PRECISION (TREE_TYPE (arg0))
+              < TYPE_PRECISION (result_type))
+             && (TYPE_PRECISION (TREE_TYPE (arg1))
+                 == TYPE_PRECISION (TREE_TYPE (arg0)))
+             && unsigned0 == unsigned1
+             && (unsigned0 || !uns))
+           result_type
+             = c_common_signed_or_unsigned_type
+             (unsigned0, common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+         else if (TREE_CODE (arg0) == INTEGER_CST
+                  && (unsigned1 || !uns)
+                  && (TYPE_PRECISION (TREE_TYPE (arg1))
+                      < TYPE_PRECISION (result_type))
+                  && (type
+                      = c_common_signed_or_unsigned_type (unsigned1,
+                                                          TREE_TYPE (arg1)),
+                      int_fits_type_p (arg0, type)))
+           result_type = type;
+         else if (TREE_CODE (arg1) == INTEGER_CST
+                  && (unsigned0 || !uns)
+                  && (TYPE_PRECISION (TREE_TYPE (arg0))
+                      < TYPE_PRECISION (result_type))
+                  && (type
+                      = c_common_signed_or_unsigned_type (unsigned0,
+                                                          TREE_TYPE (arg0)),
+                      int_fits_type_p (arg1, type)))
+           result_type = type;
        }
-    }
-
-  /* Those MODIFY_EXPRs could do autoincrements.  */
-  emit_queue ();
-}
-\f
-/* Expand a C `return' statement.
-   RETVAL is the expression for what to return,
-   or a null pointer for `return;' with no value.  */
-
-tree
-c_expand_return (tree retval)
-{
-  tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl));
-
-  if (TREE_THIS_VOLATILE (current_function_decl))
-    warning ("function declared `noreturn' has a `return' statement");
-
-  if (!retval)
-    {
-      current_function_returns_null = 1;
-      if ((warn_return_type || flag_isoc99)
-         && valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
-       pedwarn_c99 ("`return' with no value, in function returning non-void");
-    }
-  else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
-    {
-      current_function_returns_null = 1;
-      if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
-       pedwarn ("`return' with a value, in function returning void");
-    }
-  else
-    {
-      tree t = convert_for_assignment (valtype, retval, _("return"),
-                                      NULL_TREE, NULL_TREE, 0);
-      tree res = DECL_RESULT (current_function_decl);
-      tree inner;
-
-      current_function_returns_value = 1;
-      if (t == error_mark_node)
-       return NULL_TREE;
 
-      inner = t = convert (TREE_TYPE (res), t);
+      /* Shifts can be shortened if shifting right.  */
 
-      /* Strip any conversions, additions, and subtractions, and see if
-        we are returning the address of a local variable.  Warn if so.  */
-      while (1)
+      if (short_shift)
        {
-         switch (TREE_CODE (inner))
-           {
-           case NOP_EXPR:   case NON_LVALUE_EXPR:  case CONVERT_EXPR:
-           case PLUS_EXPR:
-             inner = TREE_OPERAND (inner, 0);
-             continue;
-
-           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);
+         int unsigned_arg;
+         tree arg0 = get_narrower (op0, &unsigned_arg);
 
-             while (TREE_CODE_CLASS (TREE_CODE (inner)) == 'r')
-               inner = TREE_OPERAND (inner, 0);
+         final_type = result_type;
 
-             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 (arg0 == op0 && final_type == TREE_TYPE (op0))
+           unsigned_arg = TYPE_UNSIGNED (TREE_TYPE (op0));
 
-           default:
-             break;
+         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.  */
+             && compare_tree_int (op1, TYPE_PRECISION (TREE_TYPE (arg0))) < 0
+             /* We cannot drop an unsigned shift after sign-extension.  */
+             && (!TYPE_UNSIGNED (final_type) || unsigned_arg))
+           {
+             /* Do an unsigned shift if the operand was zero-extended.  */
+             result_type
+               = c_common_signed_or_unsigned_type (unsigned_arg,
+                                                   TREE_TYPE (arg0));
+             /* Convert value-to-be-shifted to that type.  */
+             if (TREE_TYPE (op0) != result_type)
+               op0 = convert (result_type, op0);
+             converted = 1;
            }
-
-         break;
        }
 
-      retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
-    }
+      /* Comparison operations are shortened too but differently.
+        They identify themselves by setting short_compare = 1.  */
 
- return add_stmt (build_return_stmt (retval));
-}
-\f
-struct c_switch {
-  /* The SWITCH_STMT being built.  */
-  tree switch_stmt;
-  /* A splay-tree mapping the low element of a case range to the high
-     element, or NULL_TREE if there is no high element.  Used to
-     determine whether or not a new case label duplicates an old case
-     label.  We need a tree, rather than simply a hash table, because
-     of the GNU case range extension.  */
-  splay_tree cases;
-  /* The next node on the stack.  */
-  struct c_switch *next;
-};
+      if (short_compare)
+       {
+         /* Don't write &op0, etc., because that would prevent op0
+            from being kept in a register.
+            Instead, make copies of the our local variables and
+            pass the copies by reference, then copy them back afterward.  */
+         tree xop0 = op0, xop1 = op1, xresult_type = result_type;
+         enum tree_code xresultcode = resultcode;
+         tree val
+           = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
 
-/* A stack of the currently active switch statements.  The innermost
-   switch statement is on the top of the stack.  There is no need to
-   mark the stack for garbage collection because it is only active
-   during the processing of the body of a function, and we never
-   collect at that point.  */
+         if (val != 0)
+           return val;
 
-static struct c_switch *switch_stack;
+         op0 = xop0, op1 = xop1;
+         converted = 1;
+         resultcode = xresultcode;
 
-/* Start a C switch statement, testing expression EXP.  Return the new
-   SWITCH_STMT.  */
+         if (warn_sign_compare && skip_evaluation == 0)
+           {
+             int op0_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op0));
+             int op1_signed = ! TYPE_UNSIGNED (TREE_TYPE (orig_op1));
+             int unsignedp0, unsignedp1;
+             tree primop0 = get_narrower (op0, &unsignedp0);
+             tree primop1 = get_narrower (op1, &unsignedp1);
 
-tree
-c_start_case (tree exp)
-{
-  enum tree_code code;
-  tree type, orig_type = error_mark_node;
-  struct c_switch *cs;
+             xop0 = orig_op0;
+             xop1 = orig_op1;
+             STRIP_TYPE_NOPS (xop0);
+             STRIP_TYPE_NOPS (xop1);
 
-  if (exp != error_mark_node)
-    {
-      code = TREE_CODE (TREE_TYPE (exp));
-      orig_type = TREE_TYPE (exp);
+             /* Give warnings for comparisons between signed and unsigned
+                quantities that may fail.
 
-      if (! INTEGRAL_TYPE_P (orig_type)
-         && code != ERROR_MARK)
-       {
-         error ("switch quantity not an integer");
-         exp = integer_zero_node;
-       }
-      else
-       {
-         type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+                Do the checking based on the original operand trees, so that
+                casts will be considered, but default promotions won't be.
 
-         if (warn_traditional && !in_system_header
-             && (type == long_integer_type_node
-                 || type == long_unsigned_type_node))
-           warning ("`long' switch expression not converted to `int' in ISO C");
+                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 (! TYPE_UNSIGNED (result_type))
+               /* OK */;
+              /* Do not warn if both operands are the same signedness.  */
+              else if (op0_signed == op1_signed)
+                /* OK */;
+             else
+               {
+                 tree sop, uop;
 
-         exp = default_conversion (exp);
-         type = TREE_TYPE (exp);
-       }
-    }
+                 if (op0_signed)
+                   sop = xop0, uop = xop1;
+                 else
+                   sop = xop1, uop = xop0;
 
-  /* Add this new SWITCH_STMT to the stack.  */
-  cs = (struct c_switch *) xmalloc (sizeof (*cs));
-  cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
-  cs->cases = splay_tree_new (case_compare, NULL, NULL);
-  cs->next = switch_stack;
-  switch_stack = cs;
+                 /* Do not warn if the signed quantity is an
+                    unsuffixed integer literal (or some static
+                    constant expression involving such literals or a
+                    conditional expression involving such literals)
+                    and it is non-negative.  */
+                 if (c_tree_expr_nonnegative_p (sop))
+                   /* OK */;
+                 /* Do not warn if the comparison is an equality operation,
+                    the unsigned quantity is an integral constant, and it
+                    would fit in the result if the result were signed.  */
+                 else if (TREE_CODE (uop) == INTEGER_CST
+                          && (resultcode == EQ_EXPR || resultcode == NE_EXPR)
+                          && int_fits_type_p
+                          (uop, c_common_signed_type (result_type)))
+                   /* OK */;
+                 /* Do not warn if the unsigned quantity is an enumeration
+                    constant and its maximum value would fit in the result
+                    if the result were signed.  */
+                 else if (TREE_CODE (uop) == INTEGER_CST
+                          && TREE_CODE (TREE_TYPE (uop)) == ENUMERAL_TYPE
+                          && int_fits_type_p
+                          (TYPE_MAX_VALUE (TREE_TYPE(uop)),
+                           c_common_signed_type (result_type)))
+                   /* OK */;
+                 else
+                   warning ("comparison between signed and unsigned");
+               }
 
-  return add_stmt (switch_stack->switch_stmt);
-}
+             /* 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.
 
-/* Process a case label.  */
+                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.  */
 
-tree
-do_case (tree low_value, tree high_value)
-{
-  tree label = NULL_TREE;
+             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 (switch_stack)
-    {
-      bool switch_was_empty_p = (SWITCH_BODY (switch_stack->switch_stmt) == NULL_TREE);
+                 if (host_integerp (primop0, 0) || host_integerp (primop1, 0))
+                   {
+                     tree primop;
+                     HOST_WIDE_INT constant, mask;
+                     int unsignedp, bits;
 
-      label = c_add_case_label (switch_stack->cases,
-                               SWITCH_COND (switch_stack->switch_stmt),
-                               low_value, high_value);
-      if (label == error_mark_node)
-       label = NULL_TREE;
-      else if (switch_was_empty_p)
-       {
-         /* Attach the first case label to the SWITCH_BODY.  */
-         SWITCH_BODY (switch_stack->switch_stmt) = TREE_CHAIN (switch_stack->switch_stmt);
-         TREE_CHAIN (switch_stack->switch_stmt) = NULL_TREE;
+                     if (host_integerp (primop0, 0))
+                       {
+                         primop = primop1;
+                         unsignedp = unsignedp1;
+                         constant = tree_low_cst (primop0, 0);
+                       }
+                     else
+                       {
+                         primop = primop0;
+                         unsignedp = unsignedp0;
+                         constant = tree_low_cst (primop1, 0);
+                       }
+
+                     bits = TYPE_PRECISION (TREE_TYPE (primop));
+                     if (bits < TYPE_PRECISION (result_type)
+                         && bits < HOST_BITS_PER_WIDE_INT && unsignedp)
+                       {
+                         mask = (~ (HOST_WIDE_INT) 0) << 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");
+               }
+           }
        }
     }
-  else if (low_value)
-    error ("case label not within a switch statement");
-  else
-    error ("`default' label not within a switch statement");
 
-  return label;
-}
+  /* At this point, RESULT_TYPE must be nonzero to avoid an error message.
+     If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
+     Then the expression will be built.
+     It will be given type FINAL_TYPE if that is nonzero;
+     otherwise, it will be given type RESULT_TYPE.  */
 
-/* Finish the switch statement.  */
+  if (!result_type)
+    {
+      binary_op_error (code);
+      return error_mark_node;
+    }
 
-void
-c_finish_case (void)
-{
-  struct c_switch *cs = switch_stack;
+  if (! converted)
+    {
+      if (TREE_TYPE (op0) != result_type)
+       op0 = convert (result_type, op0);
+      if (TREE_TYPE (op1) != result_type)
+       op1 = convert (result_type, op1);
+    }
 
-  /* Rechain the next statements to the SWITCH_STMT.  */
-  last_tree = cs->switch_stmt;
+  if (build_type == NULL_TREE)
+    build_type = result_type;
 
-  /* Pop the stack.  */
-  switch_stack = switch_stack->next;
-  splay_tree_delete (cs->cases);
-  free (cs);
+  {
+    tree result = build (resultcode, build_type, op0, op1);
+    tree folded;
+
+    /* Treat expressions in initializers specially as they can't trap.  */
+    folded = initializer_stack ? fold_initializer (result)
+                              : fold (result);
+    if (folded == result)
+      TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
+    if (final_type != 0)
+      return convert (final_type, folded);
+    return folded;
+  }
 }
+