diff gcc/c-typeck.c @ 69:1b10fe6932e1

merge 69
author Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp>
date Sun, 21 Aug 2011 07:53:12 +0900
parents 326d9e06c2e3 f6334be47118
children b81903832de2
line wrap: on
line diff
--- a/gcc/c-typeck.c	Tue Dec 14 03:58:33 2010 +0900
+++ b/gcc/c-typeck.c	Sun Aug 21 07:53:12 2011 +0900
@@ -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, 2004, 2005, 2006, 2007, 2008, 2009
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -29,25 +29,22 @@
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "rtl.h"
 #include "tree.h"
 #include "langhooks.h"
 #include "c-tree.h"
 #include "c-lang.h"
-#include "tm_p.h"
 #include "flags.h"
 #include "output.h"
-#include "expr.h"
-#include "toplev.h"
 #include "intl.h"
-#include "ggc.h"
 #include "target.h"
 #include "tree-iterator.h"
+#include "bitmap.h"
 #include "gimple.h"
 #include "tree-flow.h"
 #ifndef noCbC
   #include "cbc-tree.h"
 #endif
+#include "c-family/c-objc.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
    diagnostic messages in convert_for_assignment.  */
@@ -58,13 +55,6 @@
   ic_return
 };
 
-/* Whether we are building a boolean conversion inside
-   convert_for_assignment, or some other late binary operation.  If
-   build_binary_op is called (from code shared with C++) in this case,
-   then the operands have already been folded and the result will not
-   be folded again, so C_MAYBE_CONST_EXPR should not be generated.  */
-bool in_late_binary_op;
-
 /* The level of nesting inside "__alignof__".  */
 int in_alignof;
 
@@ -83,10 +73,12 @@
 
 static bool null_pointer_constant_p (const_tree);
 static tree qualify_type (tree, tree);
-static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *);
+static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
+					 bool *);
 static int comp_target_types (location_t, tree, tree);
-static int function_types_compatible_p (const_tree, const_tree, bool *);
-static int type_lists_compatible_p (const_tree, const_tree, bool *);
+static int function_types_compatible_p (const_tree, const_tree, bool *,
+					bool *);
+static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
 static tree lookup_field (tree, tree);
 static int convert_arguments (tree, VEC(tree,gc) *, VEC(tree,gc) *, tree,
                   tree);
@@ -100,19 +92,19 @@
 static char *print_spelling (char *);
 static void warning_init (int, const char *);
 static tree digest_init (location_t, tree, tree, tree, bool, bool, int);
-static void output_init_element (tree, tree, bool, tree, tree, int, bool);
-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, tree, bool);
-static void set_nonincremental_init (void);
-static void set_nonincremental_init_from_string (tree);
-static tree find_init_member (tree);
-static void readonly_error (tree, enum lvalue_use);
+static void output_init_element (tree, tree, bool, tree, tree, int, bool,
+				 struct obstack *);
+static void output_pending_init_elements (int, struct obstack *);
+static int set_designator (int, struct obstack *);
+static void push_range_stack (tree, struct obstack *);
+static void add_pending_init (tree, tree, tree, bool, struct obstack *);
+static void set_nonincremental_init (struct obstack *);
+static void set_nonincremental_init_from_string (tree, struct obstack *);
+static tree find_init_member (tree, struct obstack *);
 static void readonly_warning (tree, enum lvalue_use);
-static int lvalue_or_else (const_tree, enum lvalue_use);
+static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
 static void record_maybe_used_decl (tree);
-static int comptypes_internal (const_tree, const_tree, bool *);
+static int comptypes_internal (const_tree, const_tree, bool *, bool *);
 
 /* Return true if EXP is a null pointer constant, false otherwise.  */
 
@@ -493,139 +485,138 @@
 #ifndef noCbC
     int is_code_segment = CbC_IS_CODE_SEGMENT(t1);
 #endif
-    tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
-    tree p1 = TYPE_ARG_TYPES (t1);
-    tree p2 = TYPE_ARG_TYPES (t2);
-    int len;
-    tree newargs, n;
-    int i;
-
-    /* Save space: see if the result is identical to one of the args.  */
-    if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2))
-      return build_type_attribute_variant (t1, attributes);
-    if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1))
-      return build_type_attribute_variant (t2, attributes);
-
-    /* Simple way if one arg fails to specify argument types.  */
-    if (TYPE_ARG_TYPES (t1) == 0)
-     {
+	tree valtype = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
+	tree p1 = TYPE_ARG_TYPES (t1);
+	tree p2 = TYPE_ARG_TYPES (t2);
+	int len;
+	tree newargs, n;
+	int i;
+
+	/* Save space: see if the result is identical to one of the args.  */
+	if (valtype == TREE_TYPE (t1) && !TYPE_ARG_TYPES (t2))
+	  return build_type_attribute_variant (t1, attributes);
+	if (valtype == TREE_TYPE (t2) && !TYPE_ARG_TYPES (t1))
+	  return build_type_attribute_variant (t2, attributes);
+
+	/* Simple way if one arg fails to specify argument types.  */
+	if (TYPE_ARG_TYPES (t1) == 0)
+	 {
 #ifndef noCbC
        if (is_code_segment) t1 = build_code_segment_type (valtype, TYPE_ARG_TYPES (t2));
        else
 #endif
-        t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
-        t1 = build_type_attribute_variant (t1, attributes);
-        return qualify_type (t1, t2);
-     }
-    if (TYPE_ARG_TYPES (t2) == 0)
-     {
+	    t1 = build_function_type (valtype, TYPE_ARG_TYPES (t2));
+	    t1 = build_type_attribute_variant (t1, attributes);
+	    return qualify_type (t1, t2);
+	 }
+	if (TYPE_ARG_TYPES (t2) == 0)
+	 {
 #ifndef noCbC
        if (is_code_segment) t1 = build_code_segment_type (valtype, TYPE_ARG_TYPES (t1));
        else
 #endif
-       t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1));
-       t1 = build_type_attribute_variant (t1, attributes);
-       return qualify_type (t1, t2);
-     }
-
-    /* If both args specify argument types, we must merge the two
-       lists, argument by argument.  */
-    /* Tell global_bindings_p to return false so that variable_size
-       doesn't die on VLAs in parameter types.  */
-    c_override_global_bindings_to_false = true;
-
-    len = list_length (p1);
-    newargs = 0;
-
-    for (i = 0; i < len; i++)
-      newargs = tree_cons (NULL_TREE, NULL_TREE, newargs);
-
-    n = newargs;
-
-    for (; p1;
-         p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n))
-      {
-        /* A null type means arg type is not specified.
-           Take whatever the other function type has.  */
-        if (TREE_VALUE (p1) == 0)
-          {
-        TREE_VALUE (n) = TREE_VALUE (p2);
-        goto parm_done;
-          }
-        if (TREE_VALUE (p2) == 0)
-          {
-        TREE_VALUE (n) = TREE_VALUE (p1);
-        goto parm_done;
-          }
-
-        /* Given  wait (union {union wait *u; int *i} *)
-           and  wait (union wait *),
-           prefer  union wait *  as type of parm.  */
-        if (TREE_CODE (TREE_VALUE (p1)) == UNION_TYPE
-        && TREE_VALUE (p1) != TREE_VALUE (p2))
-          {
-        tree memb;
-        tree mv2 = TREE_VALUE (p2);
-        if (mv2 && mv2 != error_mark_node
-            && TREE_CODE (mv2) != ARRAY_TYPE)
-          mv2 = TYPE_MAIN_VARIANT (mv2);
-        for (memb = TYPE_FIELDS (TREE_VALUE (p1));
-             memb; memb = TREE_CHAIN (memb))
-          {
-            tree mv3 = TREE_TYPE (memb);
-            if (mv3 && mv3 != error_mark_node
-            && TREE_CODE (mv3) != ARRAY_TYPE)
-              mv3 = TYPE_MAIN_VARIANT (mv3);
-            if (comptypes (mv3, mv2))
-              {
-            TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
-                             TREE_VALUE (p2));
-            pedwarn (input_location, OPT_pedantic,
-                 "function types not truly compatible in ISO C");
-            goto parm_done;
-              }
-          }
-          }
-        if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE
-        && TREE_VALUE (p2) != TREE_VALUE (p1))
-          {
-        tree memb;
-        tree mv1 = TREE_VALUE (p1);
-        if (mv1 && mv1 != error_mark_node
-            && TREE_CODE (mv1) != ARRAY_TYPE)
-          mv1 = TYPE_MAIN_VARIANT (mv1);
-        for (memb = TYPE_FIELDS (TREE_VALUE (p2));
-             memb; memb = TREE_CHAIN (memb))
-          {
-            tree mv3 = TREE_TYPE (memb);
-            if (mv3 && mv3 != error_mark_node
-            && TREE_CODE (mv3) != ARRAY_TYPE)
-              mv3 = TYPE_MAIN_VARIANT (mv3);
-            if (comptypes (mv3, mv1))
-              {
-            TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
-                             TREE_VALUE (p1));
-            pedwarn (input_location, OPT_pedantic,
-                 "function types not truly compatible in ISO C");
-            goto parm_done;
-              }
-          }
-          }
-        TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
-      parm_done: ;
-      }
-
-    c_override_global_bindings_to_false = false;
+	   t1 = build_function_type (valtype, TYPE_ARG_TYPES (t1));
+	   t1 = build_type_attribute_variant (t1, attributes);
+	   return qualify_type (t1, t2);
+	 }
+
+	/* If both args specify argument types, we must merge the two
+	   lists, argument by argument.  */
+	/* Tell global_bindings_p to return false so that variable_size
+	   doesn't die on VLAs in parameter types.  */
+	c_override_global_bindings_to_false = true;
+
+	len = list_length (p1);
+	newargs = 0;
+
+	for (i = 0; i < len; i++)
+	  newargs = tree_cons (NULL_TREE, NULL_TREE, newargs);
+
+	n = newargs;
+
+	for (; p1;
+	     p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2), n = TREE_CHAIN (n))
+	  {
+	    /* A null type means arg type is not specified.
+	       Take whatever the other function type has.  */
+	    if (TREE_VALUE (p1) == 0)
+	      {
+		TREE_VALUE (n) = TREE_VALUE (p2);
+		goto parm_done;
+	      }
+	    if (TREE_VALUE (p2) == 0)
+	      {
+		TREE_VALUE (n) = TREE_VALUE (p1);
+		goto parm_done;
+	      }
+
+	    /* Given  wait (union {union wait *u; int *i} *)
+	       and  wait (union wait *),
+	       prefer  union wait *  as type of parm.  */
+	    if (TREE_CODE (TREE_VALUE (p1)) == UNION_TYPE
+		&& TREE_VALUE (p1) != TREE_VALUE (p2))
+	      {
+		tree memb;
+		tree mv2 = TREE_VALUE (p2);
+		if (mv2 && mv2 != error_mark_node
+		    && TREE_CODE (mv2) != ARRAY_TYPE)
+		  mv2 = TYPE_MAIN_VARIANT (mv2);
+		for (memb = TYPE_FIELDS (TREE_VALUE (p1));
+		     memb; memb = DECL_CHAIN (memb))
+		  {
+		    tree mv3 = TREE_TYPE (memb);
+		    if (mv3 && mv3 != error_mark_node
+			&& TREE_CODE (mv3) != ARRAY_TYPE)
+		      mv3 = TYPE_MAIN_VARIANT (mv3);
+		    if (comptypes (mv3, mv2))
+		      {
+			TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+							 TREE_VALUE (p2));
+			pedwarn (input_location, OPT_pedantic,
+				 "function types not truly compatible in ISO C");
+			goto parm_done;
+		      }
+		  }
+	      }
+	    if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE
+		&& TREE_VALUE (p2) != TREE_VALUE (p1))
+	      {
+		tree memb;
+		tree mv1 = TREE_VALUE (p1);
+		if (mv1 && mv1 != error_mark_node
+		    && TREE_CODE (mv1) != ARRAY_TYPE)
+		  mv1 = TYPE_MAIN_VARIANT (mv1);
+		for (memb = TYPE_FIELDS (TREE_VALUE (p2));
+		     memb; memb = DECL_CHAIN (memb))
+		  {
+		    tree mv3 = TREE_TYPE (memb);
+		    if (mv3 && mv3 != error_mark_node
+			&& TREE_CODE (mv3) != ARRAY_TYPE)
+		      mv3 = TYPE_MAIN_VARIANT (mv3);
+		    if (comptypes (mv3, mv1))
+		      {
+			TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+							 TREE_VALUE (p1));
+			pedwarn (input_location, OPT_pedantic,
+				 "function types not truly compatible in ISO C");
+			goto parm_done;
+		      }
+		  }
+	      }
+	    TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
+	  parm_done: ;
+	  }
+
+	c_override_global_bindings_to_false = false;
 
 #ifndef noCbC
     if (is_code_segment) t1 = build_code_segment_type (valtype, newargs);
     else
 #endif
-    t1 = build_function_type (valtype, newargs);
-    t1 = qualify_type (t1, t2);
-    /* ... falls through ...  */
+	t1 = build_function_type (valtype, newargs);
+	t1 = qualify_type (t1, t2);
+	/* ... falls through ...  */
       }
-
     default:
       return build_type_attribute_variant (t1, attributes);
     }
@@ -994,7 +985,7 @@
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, NULL);
+  val = comptypes_internal (type1, type2, NULL, NULL);
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
   return val;
@@ -1009,7 +1000,23 @@
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, enum_and_int_p);
+  val = comptypes_internal (type1, type2, enum_and_int_p, NULL);
+  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+
+  return val;
+}
+
+/* Like comptypes, but if it returns nonzero for different types, it
+   sets *DIFFERENT_TYPES_P to true.  */
+
+int
+comptypes_check_different_types (tree type1, tree type2,
+				 bool *different_types_p)
+{
+  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = tagged_tu_seen_base;
+  int val;
+
+  val = comptypes_internal (type1, type2, NULL, different_types_p);
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
   return val;
@@ -1020,11 +1027,17 @@
    but a warning may be needed if you use them together.  If
    ENUM_AND_INT_P is not NULL, and one type is an enum and the other a
    compatible integer type, then this sets *ENUM_AND_INT_P to true;
-   *ENUM_AND_INT_P is never set to false.  This differs from
-   comptypes, in that we don't free the seen types.  */
+   *ENUM_AND_INT_P is never set to false.  If DIFFERENT_TYPES_P is not
+   NULL, and the types are compatible but different enough not to be
+   permitted in C1X typedef redeclarations, then this sets
+   *DIFFERENT_TYPES_P to true; *DIFFERENT_TYPES_P is never set to
+   false, but may or may not be set if the types are incompatible.
+   This differs from comptypes, in that we don't free the seen
+   types.  */
 
 static int
-comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p)
+comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p,
+		    bool *different_types_p)
 {
   const_tree t1 = type1;
   const_tree t2 = type2;
@@ -1036,17 +1049,6 @@
       || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK)
     return 1;
 
-  /* If either type is the internal version of sizetype, return the
-     language version.  */
-  if (TREE_CODE (t1) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t1)
-      && TYPE_ORIG_SIZE_TYPE (t1))
-    t1 = TYPE_ORIG_SIZE_TYPE (t1);
-
-  if (TREE_CODE (t2) == INTEGER_TYPE && TYPE_IS_SIZETYPE (t2)
-      && TYPE_ORIG_SIZE_TYPE (t2))
-    t2 = TYPE_ORIG_SIZE_TYPE (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.  */
@@ -1054,14 +1056,24 @@
   if (TREE_CODE (t1) == ENUMERAL_TYPE && TREE_CODE (t2) != ENUMERAL_TYPE)
     {
       t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1));
-      if (enum_and_int_p != NULL && TREE_CODE (t2) != VOID_TYPE)
-    *enum_and_int_p = true;
+      if (TREE_CODE (t2) != VOID_TYPE)
+	{
+	  if (enum_and_int_p != NULL)
+	    *enum_and_int_p = true;
+	  if (different_types_p != NULL)
+	    *different_types_p = true;
+	}
     }
   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 (enum_and_int_p != NULL && TREE_CODE (t1) != VOID_TYPE)
-    *enum_and_int_p = true;
+      if (TREE_CODE (t1) != VOID_TYPE)
+	{
+	  if (enum_and_int_p != NULL)
+	    *enum_and_int_p = true;
+	  if (different_types_p != NULL)
+	    *different_types_p = true;
+	}
     }
 
   if (t1 == t2)
@@ -1100,78 +1112,88 @@
       || TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2))
     break;
       val = (TREE_TYPE (t1) == TREE_TYPE (t2)
-         ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
-                       enum_and_int_p));
+	     ? 1 : comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
+				       enum_and_int_p, different_types_p));
       break;
 
     case FUNCTION_TYPE:
-      val = function_types_compatible_p (t1, t2, enum_and_int_p);
+      val = function_types_compatible_p (t1, t2, enum_and_int_p,
+					 different_types_p);
       break;
 
     case ARRAY_TYPE:
       {
-    tree d1 = TYPE_DOMAIN (t1);
-    tree d2 = TYPE_DOMAIN (t2);
-    bool d1_variable, d2_variable;
-    bool d1_zero, d2_zero;
-    val = 1;
-
-    /* Target types must match incl. qualifiers.  */
-    if (TREE_TYPE (t1) != TREE_TYPE (t2)
-        && 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
-                           enum_and_int_p)))
-      return 0;
-
-    /* Sizes must match unless one is missing or variable.  */
-    if (d1 == 0 || d2 == 0 || d1 == d2)
-      break;
-
-    d1_zero = !TYPE_MAX_VALUE (d1);
-    d2_zero = !TYPE_MAX_VALUE (d2);
-
-    d1_variable = (!d1_zero
-               && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
-               || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST));
-    d2_variable = (!d2_zero
-               && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
-               || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
-    d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1));
-    d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2));
-
-    if (d1_variable || d2_variable)
-      break;
-    if (d1_zero && d2_zero)
-      break;
-    if (d1_zero || d2_zero
-        || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
-        || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
-      val = 0;
-
-    break;
+	tree d1 = TYPE_DOMAIN (t1);
+	tree d2 = TYPE_DOMAIN (t2);
+	bool d1_variable, d2_variable;
+	bool d1_zero, d2_zero;
+	val = 1;
+
+	/* Target types must match incl. qualifiers.  */
+	if (TREE_TYPE (t1) != TREE_TYPE (t2)
+	    && 0 == (val = comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
+					       enum_and_int_p,
+					       different_types_p)))
+	  return 0;
+
+	if (different_types_p != NULL
+	    && (d1 == 0) != (d2 == 0))
+	  *different_types_p = true;
+	/* Sizes must match unless one is missing or variable.  */
+	if (d1 == 0 || d2 == 0 || d1 == d2)
+	  break;
+
+	d1_zero = !TYPE_MAX_VALUE (d1);
+	d2_zero = !TYPE_MAX_VALUE (d2);
+
+	d1_variable = (!d1_zero
+		       && (TREE_CODE (TYPE_MIN_VALUE (d1)) != INTEGER_CST
+			   || TREE_CODE (TYPE_MAX_VALUE (d1)) != INTEGER_CST));
+	d2_variable = (!d2_zero
+		       && (TREE_CODE (TYPE_MIN_VALUE (d2)) != INTEGER_CST
+			   || TREE_CODE (TYPE_MAX_VALUE (d2)) != INTEGER_CST));
+	d1_variable = d1_variable || (d1_zero && c_vla_type_p (t1));
+	d2_variable = d2_variable || (d2_zero && c_vla_type_p (t2));
+
+	if (different_types_p != NULL
+	    && d1_variable != d2_variable)
+	  *different_types_p = true;
+	if (d1_variable || d2_variable)
+	  break;
+	if (d1_zero && d2_zero)
+	  break;
+	if (d1_zero || d2_zero
+	    || !tree_int_cst_equal (TYPE_MIN_VALUE (d1), TYPE_MIN_VALUE (d2))
+	    || !tree_int_cst_equal (TYPE_MAX_VALUE (d1), TYPE_MAX_VALUE (d2)))
+	  val = 0;
+
+	break;
       }
 
     case ENUMERAL_TYPE:
     case RECORD_TYPE:
     case UNION_TYPE:
       if (val != 1 && !same_translation_unit_p (t1, t2))
-    {
-      tree a1 = TYPE_ATTRIBUTES (t1);
-      tree a2 = TYPE_ATTRIBUTES (t2);
-
-      if (! attribute_list_contained (a1, a2)
-          && ! attribute_list_contained (a2, a1))
-        break;
-
-      if (attrval != 2)
-        return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
-      val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p);
-    }
+	{
+	  tree a1 = TYPE_ATTRIBUTES (t1);
+	  tree a2 = TYPE_ATTRIBUTES (t2);
+
+	  if (! attribute_list_contained (a1, a2)
+	      && ! attribute_list_contained (a2, a1))
+	    break;
+
+	  if (attrval != 2)
+	    return tagged_types_tu_compatible_p (t1, t2, enum_and_int_p,
+						 different_types_p);
+	  val = tagged_types_tu_compatible_p (t1, t2, enum_and_int_p,
+					      different_types_p);
+	}
       break;
 
     case VECTOR_TYPE:
       val = (TYPE_VECTOR_SUBPARTS (t1) == TYPE_VECTOR_SUBPARTS (t2)
-         && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
-                    enum_and_int_p));
+	     && comptypes_internal (TREE_TYPE (t1), TREE_TYPE (t2),
+				    enum_and_int_p, different_types_p));
       break;
 
     default:
@@ -1303,11 +1325,12 @@
    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.  ENUM_AND_INT_P is as in comptypes_internal.  */
+   rules.  ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
+   comptypes_internal.  */
 
 static int
 tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
-                  bool *enum_and_int_p)
+			      bool *enum_and_int_p, bool *different_types_p)
 {
   tree s1, s2;
   bool needs_warning = false;
@@ -1402,117 +1425,117 @@
 
     case UNION_TYPE:
       {
-    struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
-    if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
-      {
-        tu->val = 0;
-        return 0;
-      }
-
-    /*  Speed up the common case where the fields are in the same order. */
-    for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2;
-         s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
-      {
-        int result;
-
-        if (DECL_NAME (s1) != DECL_NAME (s2))
-          break;
-        result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
-                     enum_and_int_p);
-
-        if (result != 1 && !DECL_NAME (s1))
-          break;
-        if (result == 0)
-          {
-        tu->val = 0;
-        return 0;
-          }
-        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)
-          {
-        tu->val = 0;
-        return 0;
-          }
-      }
-    if (!s1 && !s2)
-      {
-        tu->val = needs_warning ? 2 : 1;
-        return tu->val;
-      }
-
-    for (s1 = TYPE_FIELDS (t1); s1; s1 = TREE_CHAIN (s1))
-      {
-        bool ok = false;
-
-        for (s2 = TYPE_FIELDS (t2); s2; s2 = TREE_CHAIN (s2))
-          if (DECL_NAME (s1) == DECL_NAME (s2))
-        {
-          int result;
-
-          result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
-                           enum_and_int_p);
-
-          if (result != 1 && !DECL_NAME (s1))
-            continue;
-          if (result == 0)
-            {
-              tu->val = 0;
-              return 0;
-            }
-          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;
-        }
-        if (!ok)
-          {
-        tu->val = 0;
-        return 0;
-          }
-      }
-    tu->val = needs_warning ? 2 : 10;
-    return tu->val;
+	struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
+	if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
+	  {
+	    tu->val = 0;
+	    return 0;
+	  }
+
+	/*  Speed up the common case where the fields are in the same order. */
+	for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); s1 && s2;
+	     s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
+	  {
+	    int result;
+
+	    if (DECL_NAME (s1) != DECL_NAME (s2))
+	      break;
+	    result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
+					 enum_and_int_p, different_types_p);
+
+	    if (result != 1 && !DECL_NAME (s1))
+	      break;
+	    if (result == 0)
+	      {
+		tu->val = 0;
+		return 0;
+	      }
+	    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)
+	      {
+		tu->val = 0;
+		return 0;
+	      }
+	  }
+	if (!s1 && !s2)
+	  {
+	    tu->val = needs_warning ? 2 : 1;
+	    return tu->val;
+	  }
+
+	for (s1 = TYPE_FIELDS (t1); s1; s1 = DECL_CHAIN (s1))
+	  {
+	    bool ok = false;
+
+	    for (s2 = TYPE_FIELDS (t2); s2; s2 = DECL_CHAIN (s2))
+	      if (DECL_NAME (s1) == DECL_NAME (s2))
+		{
+		  int result;
+
+		  result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
+					       enum_and_int_p,
+					       different_types_p);
+
+		  if (result != 1 && !DECL_NAME (s1))
+		    continue;
+		  if (result == 0)
+		    {
+		      tu->val = 0;
+		      return 0;
+		    }
+		  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;
+		}
+	    if (!ok)
+	      {
+		tu->val = 0;
+		return 0;
+	      }
+	  }
+	tu->val = needs_warning ? 2 : 10;
+	return tu->val;
       }
 
     case RECORD_TYPE:
       {
-    struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
-
-    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_internal (TREE_TYPE (s1), TREE_TYPE (s2),
-                     enum_and_int_p);
-        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;
-      }
-    if (s1 && s2)
-      tu->val = 0;
-    else
-      tu->val = needs_warning ? 2 : 1;
-    return tu->val;
+	struct tagged_tu_seen_cache *tu = alloc_tagged_tu_seen_cache (t1, t2);
+
+	for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
+	     s1 && s2;
+	     s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
+	  {
+	    int result;
+	    if (TREE_CODE (s1) != TREE_CODE (s2)
+		|| DECL_NAME (s1) != DECL_NAME (s2))
+	      break;
+	    result = comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2),
+					 enum_and_int_p, different_types_p);
+	    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;
+	  }
+	if (s1 && s2)
+	  tu->val = 0;
+	else
+	  tu->val = needs_warning ? 2 : 1;
+	return tu->val;
       }
 
     default:
@@ -1526,11 +1549,11 @@
    Otherwise, if one type specifies only the number of arguments,
    the other must specify that number of self-promoting arg types.
    Otherwise, the argument types must match.
-   ENUM_AND_INT_P is as in comptypes_internal.  */
+   ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal.  */
 
 static int
 function_types_compatible_p (const_tree f1, const_tree f2,
-                 bool *enum_and_int_p)
+			     bool *enum_and_int_p, bool *different_types_p)
 {
   tree args1, args2;
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
@@ -1550,14 +1573,18 @@
                  TYPE_QUALS (ret1) & ~TYPE_QUAL_VOLATILE);
   if (TYPE_VOLATILE (ret2))
     ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
-                 TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
-  val = comptypes_internal (ret1, ret2, enum_and_int_p);
+				 TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
+  val = comptypes_internal (ret1, ret2, enum_and_int_p, different_types_p);
   if (val == 0)
     return 0;
 
   args1 = TYPE_ARG_TYPES (f1);
   args2 = TYPE_ARG_TYPES (f2);
 
+  if (different_types_p != NULL
+      && (args1 == 0) != (args2 == 0))
+    *different_types_p = true;
+
   /* An unspecified parmlist matches any specified parmlist
      whose argument types don't need default promotions.  */
 
@@ -1569,9 +1596,9 @@
      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),
-                       enum_and_int_p))
-    val = 2;
+	  && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1),
+					   enum_and_int_p, different_types_p))
+	val = 2;
       return val;
     }
   if (args2 == 0)
@@ -1579,24 +1606,26 @@
       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),
-                       enum_and_int_p))
-    val = 2;
+	  && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
+					   enum_and_int_p, different_types_p))
+	val = 2;
       return val;
     }
 
   /* Both types have argument lists: compare them and propagate results.  */
-  val1 = type_lists_compatible_p (args1, args2, enum_and_int_p);
+  val1 = type_lists_compatible_p (args1, args2, enum_and_int_p,
+				  different_types_p);
   return val1 != 1 ? val1 : val;
 }
 
 /* Check two lists of types for compatibility, returning 0 for
    incompatible, 1 for compatible, or 2 for compatible with
-   warning.  ENUM_AND_INT_P is as in comptypes_internal.  */
+   warning.  ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
+   comptypes_internal.  */
 
 static int
 type_lists_compatible_p (const_tree args1, const_tree args2,
-             bool *enum_and_int_p)
+			 bool *enum_and_int_p, bool *different_types_p)
 {
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
   int val = 1;
@@ -1618,9 +1647,12 @@
       if (mv2 && mv2 != error_mark_node && TREE_CODE (mv2) != ARRAY_TYPE)
     mv2 = TYPE_MAIN_VARIANT (mv2);
       /* A null pointer instead of a type
-     means there is supposed to be an argument
-     but nothing is specified about what type it has.
-     So match anything that self-promotes.  */
+	 means there is supposed to be an argument
+	 but nothing is specified about what type it has.
+	 So match anything that self-promotes.  */
+      if (different_types_p != NULL
+	  && (a1 == 0) != (a2 == 0))
+	*different_types_p = true;
       if (a1 == 0)
     {
       if (c_type_promotes_to (a2) != a2)
@@ -1633,57 +1665,62 @@
     }
       /* If one of the lists has an error marker, ignore this arg.  */
       else if (TREE_CODE (a1) == ERROR_MARK
-           || TREE_CODE (a2) == ERROR_MARK)
-    ;
-      else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p)))
-    {
-      /* Allow  wait (union {union wait *u; int *i} *)
-         and  wait (union wait *)  to be compatible.  */
-      if (TREE_CODE (a1) == UNION_TYPE
-          && (TYPE_NAME (a1) == 0
-          || TYPE_TRANSPARENT_UNION (a1))
-          && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
-          && tree_int_cst_equal (TYPE_SIZE (a1),
-                     TYPE_SIZE (a2)))
-        {
-          tree memb;
-          for (memb = TYPE_FIELDS (a1);
-           memb; memb = TREE_CHAIN (memb))
-        {
-          tree mv3 = TREE_TYPE (memb);
-          if (mv3 && mv3 != error_mark_node
-              && TREE_CODE (mv3) != ARRAY_TYPE)
-            mv3 = TYPE_MAIN_VARIANT (mv3);
-          if (comptypes_internal (mv3, mv2, enum_and_int_p))
-            break;
-        }
-          if (memb == 0)
-        return 0;
-        }
-      else if (TREE_CODE (a2) == UNION_TYPE
-           && (TYPE_NAME (a2) == 0
-               || TYPE_TRANSPARENT_UNION (a2))
-           && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
-           && tree_int_cst_equal (TYPE_SIZE (a2),
-                      TYPE_SIZE (a1)))
-        {
-          tree memb;
-          for (memb = TYPE_FIELDS (a2);
-           memb; memb = TREE_CHAIN (memb))
-        {
-          tree mv3 = TREE_TYPE (memb);
-          if (mv3 && mv3 != error_mark_node
-              && TREE_CODE (mv3) != ARRAY_TYPE)
-            mv3 = TYPE_MAIN_VARIANT (mv3);
-          if (comptypes_internal (mv3, mv1, enum_and_int_p))
-            break;
-        }
-          if (memb == 0)
-        return 0;
-        }
-      else
-        return 0;
-    }
+	       || TREE_CODE (a2) == ERROR_MARK)
+	;
+      else if (!(newval = comptypes_internal (mv1, mv2, enum_and_int_p,
+					      different_types_p)))
+	{
+	  if (different_types_p != NULL)
+	    *different_types_p = true;
+	  /* Allow  wait (union {union wait *u; int *i} *)
+	     and  wait (union wait *)  to be compatible.  */
+	  if (TREE_CODE (a1) == UNION_TYPE
+	      && (TYPE_NAME (a1) == 0
+		  || TYPE_TRANSPARENT_AGGR (a1))
+	      && TREE_CODE (TYPE_SIZE (a1)) == INTEGER_CST
+	      && tree_int_cst_equal (TYPE_SIZE (a1),
+				     TYPE_SIZE (a2)))
+	    {
+	      tree memb;
+	      for (memb = TYPE_FIELDS (a1);
+		   memb; memb = DECL_CHAIN (memb))
+		{
+		  tree mv3 = TREE_TYPE (memb);
+		  if (mv3 && mv3 != error_mark_node
+		      && TREE_CODE (mv3) != ARRAY_TYPE)
+		    mv3 = TYPE_MAIN_VARIANT (mv3);
+		  if (comptypes_internal (mv3, mv2, enum_and_int_p,
+					  different_types_p))
+		    break;
+		}
+	      if (memb == 0)
+		return 0;
+	    }
+	  else if (TREE_CODE (a2) == UNION_TYPE
+		   && (TYPE_NAME (a2) == 0
+		       || TYPE_TRANSPARENT_AGGR (a2))
+		   && TREE_CODE (TYPE_SIZE (a2)) == INTEGER_CST
+		   && tree_int_cst_equal (TYPE_SIZE (a2),
+					  TYPE_SIZE (a1)))
+	    {
+	      tree memb;
+	      for (memb = TYPE_FIELDS (a2);
+		   memb; memb = DECL_CHAIN (memb))
+		{
+		  tree mv3 = TREE_TYPE (memb);
+		  if (mv3 && mv3 != error_mark_node
+		      && TREE_CODE (mv3) != ARRAY_TYPE)
+		    mv3 = TYPE_MAIN_VARIANT (mv3);
+		  if (comptypes_internal (mv3, mv1, enum_and_int_p,
+					  different_types_p))
+		    break;
+		}
+	      if (memb == 0)
+		return 0;
+	    }
+	  else
+	    return 0;
+	}
 
       /* comptypes said ok, but record if it said to warn.  */
       if (newval > val)
@@ -1782,6 +1819,36 @@
   return build_unary_op (loc, ADDR_EXPR, exp, 0);
 }
 
+/* Mark EXP as read, not just set, for set but not used -Wunused
+   warning purposes.  */
+
+void
+mark_exp_read (tree exp)
+{
+  switch (TREE_CODE (exp))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+      DECL_READ_P (exp) = 1;
+      break;
+    case ARRAY_REF:
+    case COMPONENT_REF:
+    case MODIFY_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    CASE_CONVERT:
+    case ADDR_EXPR:
+      mark_exp_read (TREE_OPERAND (exp, 0));
+      break;
+    case COMPOUND_EXPR:
+    case C_MAYBE_CONST_EXPR:
+      mark_exp_read (TREE_OPERAND (exp, 1));
+      break;
+    default:
+      break;
+    }
+}
+
 /* Perform the default conversion of arrays and functions to pointers.
    Return the result of converting EXP.  For any other expression, just
    return EXP.
@@ -1837,6 +1904,12 @@
   return exp;
 }
 
+struct c_expr
+default_function_array_read_conversion (location_t loc, struct c_expr exp)
+{
+  mark_exp_read (exp.value);
+  return default_function_array_conversion (loc, exp);
+}
 
 /* EXP is an expression of integer type.  Apply the integer promotions
    to it and return the promoted value.  */
@@ -1898,6 +1971,8 @@
   enum tree_code code = TREE_CODE (type);
   tree promoted_type;
 
+  mark_exp_read (exp);
+
   /* Functions and arrays have been converted during parsing.  */
   gcc_assert (code != FUNCTION_TYPE);
   if (code == ARRAY_TYPE)
@@ -1934,7 +2009,7 @@
   return exp;
 }
 
-/* Look up COMPONENT in a structure or union DECL.
+/* Look up COMPONENT in a structure or union TYPE.
 
    If the component name is not found, returns NULL_TREE.  Otherwise,
    the return value is a TREE_LIST, with each TREE_VALUE a FIELD_DECL
@@ -1944,9 +2019,8 @@
    unions, the list steps down the chain to the component.  */
 
 static tree
-lookup_field (tree decl, tree component)
-{
-  tree type = TREE_TYPE (decl);
+lookup_field (tree type, tree component)
+{
   tree field;
 
   /* If TYPE_LANG_SPECIFIC is set, then it is a sorted array of pointers
@@ -1963,41 +2037,52 @@
       bot = 0;
       top = TYPE_LANG_SPECIFIC (type)->s->len;
       while (top - bot > 1)
-    {
-      half = (top - bot + 1) >> 1;
-      field = field_array[bot+half];
-
-      if (DECL_NAME (field) == NULL_TREE)
-        {
-          /* Step through all anon unions in linear fashion.  */
-          while (DECL_NAME (field_array[bot]) == NULL_TREE)
-        {
-          field = field_array[bot++];
-          if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
-              || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
-            {
-              tree anon = lookup_field (field, component);
-
-              if (anon)
-            return tree_cons (NULL_TREE, field, anon);
-            }
-        }
-
-          /* Entire record is only anon unions.  */
-          if (bot > top)
-        return NULL_TREE;
-
-          /* Restart the binary search, with new lower bound.  */
-          continue;
-        }
-
-      if (DECL_NAME (field) == component)
-        break;
-      if (DECL_NAME (field) < component)
-        bot += half;
-      else
-        top = bot + half;
-    }
+	{
+	  half = (top - bot + 1) >> 1;
+	  field = field_array[bot+half];
+
+	  if (DECL_NAME (field) == NULL_TREE)
+	    {
+	      /* Step through all anon unions in linear fashion.  */
+	      while (DECL_NAME (field_array[bot]) == NULL_TREE)
+		{
+		  field = field_array[bot++];
+		  if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+		      || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+		    {
+		      tree anon = lookup_field (TREE_TYPE (field), component);
+
+		      if (anon)
+			return tree_cons (NULL_TREE, field, anon);
+
+		      /* The Plan 9 compiler permits referring
+			 directly to an anonymous struct/union field
+			 using a typedef name.  */
+		      if (flag_plan9_extensions
+			  && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
+			  && (TREE_CODE (TYPE_NAME (TREE_TYPE (field)))
+			      == TYPE_DECL)
+			  && (DECL_NAME (TYPE_NAME (TREE_TYPE (field)))
+			      == component))
+			break;
+		    }
+		}
+
+	      /* Entire record is only anon unions.  */
+	      if (bot > top)
+		return NULL_TREE;
+
+	      /* Restart the binary search, with new lower bound.  */
+	      continue;
+	    }
+
+	  if (DECL_NAME (field) == component)
+	    break;
+	  if (DECL_NAME (field) < component)
+	    bot += half;
+	  else
+	    top = bot + half;
+	}
 
       if (DECL_NAME (field_array[bot]) == component)
     field = field_array[bot];
@@ -2006,21 +2091,31 @@
     }
   else
     {
-      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-    {
-      if (DECL_NAME (field) == NULL_TREE
-          && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
-          || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
-        {
-          tree anon = lookup_field (field, component);
-
-          if (anon)
-        return tree_cons (NULL_TREE, field, anon);
-        }
-
-      if (DECL_NAME (field) == component)
-        break;
-    }
+      for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	{
+	  if (DECL_NAME (field) == NULL_TREE
+	      && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+		  || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE))
+	    {
+	      tree anon = lookup_field (TREE_TYPE (field), component);
+
+	      if (anon)
+		return tree_cons (NULL_TREE, field, anon);
+
+	      /* The Plan 9 compiler permits referring directly to an
+		 anonymous struct/union field using a typedef
+		 name.  */
+	      if (flag_plan9_extensions
+		  && TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
+		  && TREE_CODE (TYPE_NAME (TREE_TYPE (field))) == TYPE_DECL
+		  && (DECL_NAME (TYPE_NAME (TREE_TYPE (field)))
+		      == component))
+		break;
+	    }
+
+	  if (DECL_NAME (field) == component)
+	    break;
+	}
 
       if (field == NULL_TREE)
     return NULL_TREE;
@@ -2045,6 +2140,11 @@
   if (!objc_is_public (datum, component))
     return error_mark_node;
 
+  /* Detect Objective-C property syntax object.property.  */
+  if (c_dialect_objc ()
+      && (ref = objc_maybe_build_component_ref (datum, component)))
+    return ref;
+
   /* See if there is a field or component with name COMPONENT.  */
 
   if (code == RECORD_TYPE || code == UNION_TYPE)
@@ -2055,7 +2155,7 @@
       return error_mark_node;
     }
 
-      field = lookup_field (datum, component);
+      field = lookup_field (type, component);
 
       if (!field)
     {
@@ -2184,26 +2284,8 @@
     }
     }
   else if (TREE_CODE (pointer) != ERROR_MARK)
-    switch (errstring)
-      {
-         case RO_ARRAY_INDEXING:
-           error_at (loc,
-                     "invalid type argument of array indexing (have %qT)",
-                     type);
-           break;
-         case RO_UNARY_STAR:
-           error_at (loc,
-                     "invalid type argument of unary %<*%> (have %qT)",
-                     type);
-           break;
-         case RO_ARROW:
-           error_at (loc,
-                     "invalid type argument of %<->%> (have %qT)",
-                     type);
-           break;
-         default:
-           gcc_unreachable ();
-      }
+    invalid_indirection_error (loc, type, errstring);
+
   return error_mark_node;
 }
 
@@ -2216,6 +2298,9 @@
    arrays that are not lvalues (for example, members of structures returned
    by functions).
 
+   For vector types, allow vector[i] but not i[vector], and create
+   *(((type*)&vectortype) + i) for the expression.
+
    LOC is the location to use for the returned expression.  */
 
 tree
@@ -2228,15 +2313,19 @@
     return error_mark_node;
 
   if (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE
-      && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE)
+      && TREE_CODE (TREE_TYPE (array)) != POINTER_TYPE
+      /* Allow vector[index] but not index[vector].  */
+      && TREE_CODE (TREE_TYPE (array)) != VECTOR_TYPE)
     {
       tree temp;
       if (TREE_CODE (TREE_TYPE (index)) != ARRAY_TYPE
-      && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
-    {
-      error_at (loc, "subscripted value is neither array nor pointer");
-      return error_mark_node;
-    }
+	  && TREE_CODE (TREE_TYPE (index)) != POINTER_TYPE)
+	{
+          error_at (loc, 
+            "subscripted value is neither array nor pointer nor vector");
+
+	  return error_mark_node;
+	}
       temp = array;
       array = index;
       index = temp;
@@ -2264,6 +2353,27 @@
   index = default_conversion (index);
 
   gcc_assert (TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE);
+  
+  /* For vector[index], convert the vector to a 
+     pointer of the underlying type.  */
+  if (TREE_CODE (TREE_TYPE (array)) == VECTOR_TYPE)
+    {
+      tree type = TREE_TYPE (array);
+      tree type1;
+
+      if (TREE_CODE (index) == INTEGER_CST)
+        if (!host_integerp (index, 1) 
+            || ((unsigned HOST_WIDE_INT) tree_low_cst (index, 1) 
+               >= TYPE_VECTOR_SUBPARTS (TREE_TYPE (array))))
+          warning_at (loc, OPT_Warray_bounds, "index value is out of bound");
+     
+      c_common_mark_addressable_vec (array);
+      type = build_qualified_type (TREE_TYPE (type), TYPE_QUALS (type));
+      type = build_pointer_type (type);
+      type1 = build_pointer_type (TREE_TYPE (array));
+      array = build1 (ADDR_EXPR, type1, array);
+      array = convert (type, array);
+    }
 
   if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE)
     {
@@ -2699,19 +2809,19 @@
       return trap;
     }
       else
-    {
-      tree rhs;
-
-      if (AGGREGATE_TYPE_P (return_type))
-        rhs = build_compound_literal (loc, return_type,
-                      build_constructor (return_type, 0),
-                      false);
-      else
-        rhs = fold_convert_loc (loc, return_type, integer_zero_node);
-
-      return require_complete_type (build2 (COMPOUND_EXPR, return_type,
-                        trap, rhs));
-    }
+	{
+	  tree rhs;
+
+	  if (AGGREGATE_TYPE_P (return_type))
+	    rhs = build_compound_literal (loc, return_type,
+					  build_constructor (return_type, 0),
+					  false);
+	  else
+	    rhs = build_zero_cst (return_type);
+
+	  return require_complete_type (build2 (COMPOUND_EXPR, return_type,
+						trap, rhs));
+	}
     }
 
   argarray = VEC_address (tree, params);
@@ -2836,10 +2946,18 @@
       tree parmval;
 
       if (type == void_type_node)
-    {
-      error ("too many arguments to function %qE", function);
-      return parmnum;
-    }
+	{
+	  if (selector)
+	    error_at (input_location,
+		      "too many arguments to method %qE", selector);
+	  else
+	    error_at (input_location,
+		      "too many arguments to function %qE", function);
+
+	  if (fundecl && !DECL_BUILT_IN (fundecl))
+	    inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
+	  return parmnum;
+	}
 
       if (selector && argnum > 2)
     {
@@ -3025,16 +3143,23 @@
         }
     }
       else if (TREE_CODE (valtype) == REAL_TYPE
-           && (TYPE_PRECISION (valtype)
-           < TYPE_PRECISION (double_type_node))
-           && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
+	       && (TYPE_PRECISION (valtype)
+		   < TYPE_PRECISION (double_type_node))
+	       && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
         {
-      if (type_generic)
-        parmval = val;
-      else
-        /* Convert `float' to `double'.  */
-        parmval = convert (double_type_node, val);
-    }
+	  if (type_generic)
+	    parmval = val;
+	  else
+	    {
+	      /* Convert `float' to `double'.  */
+	      if (warn_double_promotion && !c_inhibit_evaluation_warnings)
+		warning (OPT_Wdouble_promotion,
+			 "implicit conversion from %qT to %qT when passing "
+			 "argument to function",
+			 valtype, double_type_node);
+	      parmval = convert (double_type_node, val);
+	    }
+	}
       else if (excess_precision && !type_generic)
     /* A "double" argument with excess precision being passed
        without a prototype or in variable arguments.  */
@@ -3067,7 +3192,10 @@
   if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
 #endif
     {
-      error ("too few arguments to function %qE", function);
+      error_at (input_location, 
+		"too few arguments to function %qE", function);
+      if (fundecl && !DECL_BUILT_IN (fundecl))
+	inform (DECL_SOURCE_LOCATION (fundecl), "declared here");
       return -1;
     }
 
@@ -3435,26 +3563,10 @@
       goto return_build_unary_op;
 
     case REALPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-    ret = TREE_REALPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-    ret = fold_build1_loc (location,
-                   REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-      else
-    ret = arg;
-      if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
-    eptype = TREE_TYPE (eptype);
-      goto return_build_unary_op;
-
     case IMAGPART_EXPR:
-      if (TREE_CODE (arg) == COMPLEX_CST)
-    ret = TREE_IMAGPART (arg);
-      else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
-    ret = fold_build1_loc (location,
-                   IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
-      else
-    ret = omit_one_operand_loc (location, TREE_TYPE (arg),
-                integer_zero_node, arg);
+      ret = build_real_imag_expr (location, code, arg);
+      if (ret == error_mark_node)
+	return error_mark_node;
       if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
     eptype = TREE_TYPE (eptype);
       goto return_build_unary_op;
@@ -3477,12 +3589,15 @@
       goto return_build_unary_op;
     }
 
-      /* Complain about anything that is not a true lvalue.  */
-      if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
-                  || code == POSTINCREMENT_EXPR)
-                 ? lv_increment
-                 : lv_decrement)))
-    return error_mark_node;
+      /* Complain about anything that is not a true lvalue.  In
+	 Objective-C, skip this check for property_refs.  */
+      if (!objc_is_property_ref (arg) 
+	  && !lvalue_or_else (location,
+			      arg, ((code == PREINCREMENT_EXPR
+				     || code == POSTINCREMENT_EXPR)
+				    ? lv_increment
+				    : lv_decrement)))
+	return error_mark_node;
 
       if (warn_cxx_compat && TREE_CODE (TREE_TYPE (arg)) == ENUMERAL_TYPE)
     {
@@ -3531,88 +3646,95 @@
     }
 
       {
-    tree inc;
-
-    argtype = TREE_TYPE (arg);
-
-    /* Compute the increment.  */
-
-    if (typecode == POINTER_TYPE)
-      {
-        /* If pointer target is an undefined struct,
-           we just cannot know how to do the arithmetic.  */
-        if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (argtype)))
-          {
-        if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
-          error_at (location,
-                "increment of pointer to unknown structure");
-        else
-          error_at (location,
-                "decrement of pointer to unknown structure");
-          }
-        else if (TREE_CODE (TREE_TYPE (argtype)) == FUNCTION_TYPE
-             || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE)
-          {
-        if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
-          pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
-               "wrong type argument to increment");
-        else
-          pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
-               "wrong type argument to decrement");
-          }
-
-        inc = c_size_in_bytes (TREE_TYPE (argtype));
-        inc = fold_convert_loc (location, sizetype, inc);
-      }
-    else if (FRACT_MODE_P (TYPE_MODE (argtype)))
-      {
-        /* For signed fract types, we invert ++ to -- or
-           -- to ++, and change inc from 1 to -1, because
-           it is not possible to represent 1 in signed fract constants.
-           For unsigned fract types, the result always overflows and
-           we get an undefined (original) or the maximum value.  */
-        if (code == PREINCREMENT_EXPR)
-          code = PREDECREMENT_EXPR;
-        else if (code == PREDECREMENT_EXPR)
-          code = PREINCREMENT_EXPR;
-        else if (code == POSTINCREMENT_EXPR)
-          code = POSTDECREMENT_EXPR;
-        else /* code == POSTDECREMENT_EXPR  */
-          code = POSTINCREMENT_EXPR;
-
-        inc = integer_minus_one_node;
-        inc = convert (argtype, inc);
-      }
-    else
-      {
-        inc = integer_one_node;
-        inc = convert (argtype, inc);
-      }
-
-    /* Report a read-only lvalue.  */
-    if (TYPE_READONLY (argtype))
-      {
-        readonly_error (arg,
-                ((code == PREINCREMENT_EXPR
-                  || code == POSTINCREMENT_EXPR)
-                 ? lv_increment : lv_decrement));
-        return error_mark_node;
-      }
-    else if (TREE_READONLY (arg))
-      readonly_warning (arg,
-                ((code == PREINCREMENT_EXPR
-                  || code == POSTINCREMENT_EXPR)
-                 ? lv_increment : lv_decrement));
-
-    if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
-      val = boolean_increment (code, arg);
-    else
-      val = build2 (code, TREE_TYPE (arg), arg, inc);
-    TREE_SIDE_EFFECTS (val) = 1;
-    if (TREE_CODE (val) != code)
-      TREE_NO_WARNING (val) = 1;
-    ret = val;
-    goto return_build_unary_op;
+	tree inc;
+
+	argtype = TREE_TYPE (arg);
+
+	/* Compute the increment.  */
+
+	if (typecode == POINTER_TYPE)
+	  {
+	    /* If pointer target is an undefined struct,
+	       we just cannot know how to do the arithmetic.  */
+	    if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (argtype)))
+	      {
+		if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+		  error_at (location,
+			    "increment of pointer to unknown structure");
+		else
+		  error_at (location,
+			    "decrement of pointer to unknown structure");
+	      }
+	    else if (TREE_CODE (TREE_TYPE (argtype)) == FUNCTION_TYPE
+		     || TREE_CODE (TREE_TYPE (argtype)) == VOID_TYPE)
+	      {
+		if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
+		  pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+			   "wrong type argument to increment");
+		else
+		  pedwarn (location, pedantic ? OPT_pedantic : OPT_Wpointer_arith,
+			   "wrong type argument to decrement");
+	      }
+
+	    inc = c_size_in_bytes (TREE_TYPE (argtype));
+	    inc = fold_convert_loc (location, sizetype, inc);
+	  }
+	else if (FRACT_MODE_P (TYPE_MODE (argtype)))
+	  {
+	    /* For signed fract types, we invert ++ to -- or
+	       -- to ++, and change inc from 1 to -1, because
+	       it is not possible to represent 1 in signed fract constants.
+	       For unsigned fract types, the result always overflows and
+	       we get an undefined (original) or the maximum value.  */
+	    if (code == PREINCREMENT_EXPR)
+	      code = PREDECREMENT_EXPR;
+	    else if (code == PREDECREMENT_EXPR)
+	      code = PREINCREMENT_EXPR;
+	    else if (code == POSTINCREMENT_EXPR)
+	      code = POSTDECREMENT_EXPR;
+	    else /* code == POSTDECREMENT_EXPR  */
+	      code = POSTINCREMENT_EXPR;
+
+	    inc = integer_minus_one_node;
+	    inc = convert (argtype, inc);
+	  }
+	else
+	  {
+	    inc = integer_one_node;
+	    inc = convert (argtype, inc);
+	  }
+
+	/* If 'arg' is an Objective-C PROPERTY_REF expression, then we
+	   need to ask Objective-C to build the increment or decrement
+	   expression for it.  */
+	if (objc_is_property_ref (arg))
+	  return objc_build_incr_expr_for_property_ref (location, code, 
+							arg, inc);
+
+	/* Report a read-only lvalue.  */
+	if (TYPE_READONLY (argtype))
+	  {
+	    readonly_error (arg,
+			    ((code == PREINCREMENT_EXPR
+			      || code == POSTINCREMENT_EXPR)
+			     ? lv_increment : lv_decrement));
+	    return error_mark_node;
+	  }
+	else if (TREE_READONLY (arg))
+	  readonly_warning (arg,
+			    ((code == PREINCREMENT_EXPR
+			      || code == POSTINCREMENT_EXPR)
+			     ? lv_increment : lv_decrement));
+
+	if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
+	  val = boolean_increment (code, arg);
+	else
+	  val = build2 (code, TREE_TYPE (arg), arg, inc);
+	TREE_SIDE_EFFECTS (val) = 1;
+	if (TREE_CODE (val) != code)
+	  TREE_NO_WARNING (val) = 1;
+	ret = val;
+	goto return_build_unary_op;
       }
 
     case ADDR_EXPR:
@@ -3654,8 +3776,8 @@
       /* Anything not already handled and not a true memory reference
      or a non-lvalue array is an error.  */
       else if (typecode != FUNCTION_TYPE && !flag
-           && !lvalue_or_else (arg, lv_addressof))
-    return error_mark_node;
+	       && !lvalue_or_else (location, arg, lv_addressof))
+	return error_mark_node;
 
       /* Move address operations inside C_MAYBE_CONST_EXPR to simplify
      folding later.  */
@@ -3675,14 +3797,24 @@
       argtype = TREE_TYPE (arg);
 
       /* If the lvalue is const or volatile, merge that into the type
-     to which the address will point.  Note that you can't get a
-     restricted pointer by taking the address of something, so we
-     only have to deal with `const' and `volatile' here.  */
+	 to which the address will point.  This should only be needed
+	 for function types.  */
       if ((DECL_P (arg) || REFERENCE_CLASS_P (arg))
-      && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
-      argtype = c_build_type_variant (argtype,
-                      TREE_READONLY (arg),
-                      TREE_THIS_VOLATILE (arg));
+	  && (TREE_READONLY (arg) || TREE_THIS_VOLATILE (arg)))
+	{
+	  int orig_quals = TYPE_QUALS (strip_array_types (argtype));
+	  int quals = orig_quals;
+
+	  if (TREE_READONLY (arg))
+	    quals |= TYPE_QUAL_CONST;
+	  if (TREE_THIS_VOLATILE (arg))
+	    quals |= TYPE_QUAL_VOLATILE;
+
+	  gcc_assert (quals == orig_quals
+		      || TREE_CODE (argtype) == FUNCTION_TYPE);
+
+	  argtype = c_build_qualified_type (argtype, quals);
+	}
 
       if (!c_mark_addressable (arg))
     return error_mark_node;
@@ -3775,44 +3907,6 @@
       return 0;
     }
 }
-
-/* Give an error for storing in something that is 'const'.  */
-
-static void
-readonly_error (tree arg, enum lvalue_use use)
-{
-  gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
-          || use == lv_asm);
-  /* Using this macro rather than (for example) arrays of messages
-     ensures that all the format strings are checked at compile
-     time.  */
-#define READONLY_MSG(A, I, D, AS) (use == lv_assign ? (A)       \
-                   : (use == lv_increment ? (I)     \
-                   : (use == lv_decrement ? (D) : (AS))))
-  if (TREE_CODE (arg) == COMPONENT_REF)
-    {
-      if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
-    readonly_error (TREE_OPERAND (arg, 0), use);
-      else
-    error (READONLY_MSG (G_("assignment of read-only member %qD"),
-                 G_("increment of read-only member %qD"),
-                 G_("decrement of read-only member %qD"),
-                 G_("read-only member %qD used as %<asm%> output")),
-           TREE_OPERAND (arg, 1));
-    }
-  else if (TREE_CODE (arg) == VAR_DECL)
-    error (READONLY_MSG (G_("assignment of read-only variable %qD"),
-             G_("increment of read-only variable %qD"),
-             G_("decrement of read-only variable %qD"),
-             G_("read-only variable %qD used as %<asm%> output")),
-       arg);
-  else
-    error (READONLY_MSG (G_("assignment of read-only location %qE"),
-             G_("increment of read-only location %qE"),
-             G_("decrement of read-only location %qE"),
-             G_("read-only location %qE used as %<asm%> output")),
-       arg);
-}
 
 /* Give a warning for storing in something that is read-only in GCC
    terms but not const in ISO C terms.  */
@@ -3840,15 +3934,16 @@
 
 /* Return nonzero if REF is an lvalue valid for this language;
    otherwise, print an error message and return zero.  USE says
-   how the lvalue is being used and so selects the error message.  */
+   how the lvalue is being used and so selects the error message.
+   LOCATION is the location at which any error should be reported.  */
 
 static int
-lvalue_or_else (const_tree ref, enum lvalue_use use)
+lvalue_or_else (location_t loc, const_tree ref, enum lvalue_use use)
 {
   int win = lvalue_p (ref);
 
   if (!win)
-    lvalue_error (use);
+    lvalue_error (loc, use);
 
   return win;
 }
@@ -3920,6 +4015,34 @@
     }
 }
 
+/* Convert EXPR to TYPE, warning about conversion problems with
+   constants.  SEMANTIC_TYPE is the type this conversion would use
+   without excess precision. If SEMANTIC_TYPE is NULL, this function
+   is equivalent to convert_and_check. This function is a wrapper that
+   handles conversions that may be different than
+   the usual ones because of excess precision.  */
+
+static tree
+ep_convert_and_check (tree type, tree expr, tree semantic_type)
+{
+  if (TREE_TYPE (expr) == type)
+    return expr;
+
+  if (!semantic_type)
+    return convert_and_check (type, expr);
+
+  if (TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+      && TREE_TYPE (expr) != semantic_type)
+    {
+      /* For integers, we need to check the real conversion, not
+	 the conversion to the excess precision type.  */
+      expr = convert_and_check (semantic_type, expr);
+    }
+  /* Result type is the excess precision type, which should be
+     large enough, so do not check.  */
+  return convert (type, expr);
+}
+
 /* Build and return a conditional expression IFEXP ? OP1 : OP2.  If
    IFEXP_BCP then the condition is a call to __builtin_constant_p, and
    if folded to an integer constant then the unselected half may
@@ -3936,12 +4059,11 @@
   enum tree_code code1;
   enum tree_code code2;
   tree result_type = NULL;
-  tree ep_result_type = NULL;
+  tree semantic_result_type = NULL;
   tree orig_op1 = op1, orig_op2 = op2;
   bool int_const, op1_int_operands, op2_int_operands, int_operands;
   bool ifexp_int_operands;
   tree ret;
-  bool objc_ok;
 
   op1_int_operands = EXPR_INT_CONST_OPERANDS (orig_op1);
   if (op1_int_operands)
@@ -3978,8 +4100,6 @@
       return error_mark_node;
     }
 
-  objc_ok = objc_compare_types (type1, type2, -3, NULL_TREE);
-
   if ((TREE_CODE (op1) == EXCESS_PRECISION_EXPR
        || TREE_CODE (op2) == EXCESS_PRECISION_EXPR)
       && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
@@ -3987,7 +4107,7 @@
       && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
       || code2 == COMPLEX_TYPE))
     {
-      ep_result_type = c_common_type (type1, type2);
+      semantic_result_type = c_common_type (type1, type2);
       if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
     {
       op1 = TREE_OPERAND (op1, 0);
@@ -4031,6 +4151,10 @@
            || code2 == COMPLEX_TYPE))
     {
       result_type = c_common_type (type1, type2);
+      do_warn_double_promotion (result_type, type1, type2,
+				"implicit conversion from %qT to %qT to "
+				"match other result of conditional",
+				colon_loc);
 
       /* If -Wsign-compare, warn here if type1 and type2 have
      different signedness.  We'll promote the signed to unsigned
@@ -4133,24 +4257,26 @@
                               TREE_TYPE (type2)));
     }
       else if (VOID_TYPE_P (TREE_TYPE (type2)))
-    {
-      if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
-        pedwarn (colon_loc, OPT_pedantic,
-             "ISO C forbids conditional expr between "
-             "%<void *%> and function pointer");
-      result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
-                              TREE_TYPE (type1)));
-    }
+	{
+	  if (TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE)
+	    pedwarn (colon_loc, OPT_pedantic,
+		     "ISO C forbids conditional expr between "
+		     "%<void *%> and function pointer");
+	  result_type = build_pointer_type (qualify_type (TREE_TYPE (type2),
+							  TREE_TYPE (type1)));
+	}
+      /* Objective-C pointer comparisons are a bit more lenient.  */
+      else if (objc_have_common_type (type1, type2, -3, NULL_TREE))
+	result_type = objc_common_type (type1, type2);
       else
-    {
-      int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
-
-      if (!objc_ok)
-        pedwarn (colon_loc, 0,
-             "pointer type mismatch in conditional expression");
-      result_type = build_pointer_type
-              (build_qualified_type (void_type_node, qual));
-    }
+	{
+	  int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+
+	  pedwarn (colon_loc, 0,
+		   "pointer type mismatch in conditional expression");
+	  result_type = build_pointer_type
+			  (build_qualified_type (void_type_node, qual));
+	}
     }
   else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
     {
@@ -4192,10 +4318,8 @@
               TYPE_READONLY (type1) || TYPE_READONLY (type2),
               TYPE_VOLATILE (type1) || TYPE_VOLATILE (type2));
 
-  if (result_type != type1)
-    op1 = convert_and_check (result_type, op1);
-  if (result_type != type2)
-    op2 = convert_and_check (result_type, op2);
+  op1 = ep_convert_and_check (result_type, op1, semantic_result_type);
+  op2 = ep_convert_and_check (result_type, op2, semantic_result_type);
 
   if (ifexp_bcp && ifexp == truthvalue_true_node)
     {
@@ -4227,8 +4351,8 @@
       if (int_operands)
     ret = note_integer_operands (ret);
     }
-  if (ep_result_type)
-    ret = build1 (EXCESS_PRECISION_EXPR, ep_result_type, ret);
+  if (semantic_result_type)
+    ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
 
   protected_set_expr_location (ret, colon_loc);
   return ret;
@@ -4307,12 +4431,13 @@
 
 /* Issue -Wcast-qual warnings when appropriate.  TYPE is the type to
    which we are casting.  OTYPE is the type of the expression being
-   cast.  Both TYPE and OTYPE are pointer types.  -Wcast-qual appeared
-   on the command line.  Named address space qualifiers are not handled
-   here, because they result in different warnings.  */
+   cast.  Both TYPE and OTYPE are pointer types.  LOC is the location
+   of the cast.  -Wcast-qual appeared on the command line.  Named
+   address space qualifiers are not handled here, because they result
+   in different warnings.  */
 
 static void
-handle_warn_cast_qual (tree type, tree otype)
+handle_warn_cast_qual (location_t loc, tree type, tree otype)
 {
   tree in_type = type;
   tree in_otype = otype;
@@ -4345,13 +4470,15 @@
      && TREE_CODE (in_otype) == POINTER_TYPE);
 
   if (added)
-    warning (OPT_Wcast_qual, "cast adds new qualifiers to function type");
+    warning_at (loc, OPT_Wcast_qual,
+		"cast adds %q#v qualifier to function type", added);
 
   if (discarded)
     /* There are qualifiers present in IN_OTYPE that are not present
        in IN_TYPE.  */
-    warning (OPT_Wcast_qual,
-         "cast discards qualifiers from pointer target type");
+    warning_at (loc, OPT_Wcast_qual,
+		"cast discards %q#v qualifier from pointer target type",
+		discarded);
 
   if (added || discarded)
     return;
@@ -4382,13 +4509,14 @@
       in_type = TREE_TYPE (in_type);
       in_otype = TREE_TYPE (in_otype);
       if ((TYPE_QUALS (in_type) &~ TYPE_QUALS (in_otype)) != 0
-      && !is_const)
-    {
-      warning (OPT_Wcast_qual,
-           ("new qualifiers in middle of multi-level non-const cast "
-            "are unsafe"));
-      break;
-    }
+	  && !is_const)
+	{
+	  warning_at (loc, OPT_Wcast_qual,
+		      "to be safe all intermediate pointers in cast from "
+                      "%qT to %qT must be %<const%> qualified",
+		      otype, type);
+	  break;
+	}
       if (is_const)
     is_const = TYPE_READONLY (in_type);
     }
@@ -4449,23 +4577,27 @@
     {
       tree field;
 
-      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-    if (TREE_TYPE (field) != error_mark_node
-        && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
-              TYPE_MAIN_VARIANT (TREE_TYPE (value))))
-      break;
+      for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	if (TREE_TYPE (field) != error_mark_node
+	    && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
+			  TYPE_MAIN_VARIANT (TREE_TYPE (value))))
+	  break;
 
       if (field)
-    {
-      tree t;
-
-      pedwarn (loc, OPT_pedantic, "ISO C forbids casts to union type");
-      t = digest_init (loc, type,
-               build_constructor_single (type, field, value),
-               NULL_TREE, false, true, 0);
-      TREE_CONSTANT (t) = TREE_CONSTANT (value);
-      return t;
-    }
+	{
+	  tree t;
+	  bool maybe_const = true;
+
+	  pedwarn (loc, OPT_pedantic, "ISO C forbids casts to union type");
+	  t = c_fully_fold (value, false, &maybe_const);
+	  t = build_constructor_single (type, field, t);
+	  if (!maybe_const)
+	    t = c_wrap_maybe_const (t, true);
+	  t = digest_init (loc, type, t,
+			   NULL_TREE, false, true, 0);
+	  TREE_CONSTANT (t) = TREE_CONSTANT (value);
+	  return t;
+	}
       error_at (loc, "cast to union type from type not present in union");
       return error_mark_node;
     }
@@ -4484,9 +4616,9 @@
 
       /* Optionally warn about potentially worrisome casts.  */
       if (warn_cast_qual
-      && TREE_CODE (type) == POINTER_TYPE
-      && TREE_CODE (otype) == POINTER_TYPE)
-    handle_warn_cast_qual (type, otype);
+	  && TREE_CODE (type) == POINTER_TYPE
+	  && TREE_CODE (otype) == POINTER_TYPE)
+	handle_warn_cast_qual (loc, type, otype);
 
       /* Warn about conversions between pointers to disjoint
      address spaces.  */
@@ -4658,8 +4790,9 @@
   if (CAN_HAVE_LOCATION_P (ret) && !EXPR_HAS_LOCATION (ret))
     SET_EXPR_LOCATION (ret, loc);
 
-  /* C++ does not permits types to be defined in a cast.  */
-  if (warn_cxx_compat && type_name->specs->tag_defined_p)
+  /* C++ does not permits types to be defined in a cast, but it
+     allows references to incomplete types.  */
+  if (warn_cxx_compat && type_name->specs->typespec_kind == ctsk_tagdef)
     warning_at (loc, OPT_Wc___compat,
         "defining a type in a cast is invalid in C++");
 
@@ -4697,7 +4830,8 @@
   if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
     return error_mark_node;
 
-  if (!lvalue_or_else (lhs, lv_assign))
+  /* For ObjC properties, defer this check.  */
+  if (!objc_is_property_ref (lhs) && !lvalue_or_else (location, lhs, lv_assign))
     return error_mark_node;
 
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
@@ -4738,6 +4872,19 @@
       rhs_origtype = NULL_TREE;
     }
 
+  if (c_dialect_objc ())
+    {
+      /* Check if we are modifying an Objective-C property reference;
+	 if so, we need to generate setter calls.  */
+      result = objc_maybe_build_modify_expr (lhs, newrhs);
+      if (result)
+	return result;
+
+      /* Else, do the check that we postponed for Objective-C.  */
+      if (!lvalue_or_else (location, lhs, lv_assign))
+	return error_mark_node;
+    }
+
   /* Give an error for storing in something that is 'const'.  */
 
   if (TYPE_READONLY (lhstype)
@@ -4833,6 +4980,106 @@
   return result;
 }
 
+/* Return whether STRUCT_TYPE has an anonymous field with type TYPE.
+   This is used to implement -fplan9-extensions.  */
+
+static bool
+find_anonymous_field_with_type (tree struct_type, tree type)
+{
+  tree field;
+  bool found;
+
+  gcc_assert (TREE_CODE (struct_type) == RECORD_TYPE
+	      || TREE_CODE (struct_type) == UNION_TYPE);
+  found = false;
+  for (field = TYPE_FIELDS (struct_type);
+       field != NULL_TREE;
+       field = TREE_CHAIN (field))
+    {
+      if (DECL_NAME (field) == NULL
+	  && comptypes (type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+	{
+	  if (found)
+	    return false;
+	  found = true;
+	}
+      else if (DECL_NAME (field) == NULL
+	       && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+		   || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+	       && find_anonymous_field_with_type (TREE_TYPE (field), type))
+	{
+	  if (found)
+	    return false;
+	  found = true;
+	}
+    }
+  return found;
+}
+
+/* RHS is an expression whose type is pointer to struct.  If there is
+   an anonymous field in RHS with type TYPE, then return a pointer to
+   that field in RHS.  This is used with -fplan9-extensions.  This
+   returns NULL if no conversion could be found.  */
+
+static tree
+convert_to_anonymous_field (location_t location, tree type, tree rhs)
+{
+  tree rhs_struct_type, lhs_main_type;
+  tree field, found_field;
+  bool found_sub_field;
+  tree ret;
+
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (rhs)));
+  rhs_struct_type = TREE_TYPE (TREE_TYPE (rhs));
+  gcc_assert (TREE_CODE (rhs_struct_type) == RECORD_TYPE
+	      || TREE_CODE (rhs_struct_type) == UNION_TYPE);
+
+  gcc_assert (POINTER_TYPE_P (type));
+  lhs_main_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+
+  found_field = NULL_TREE;
+  found_sub_field = false;
+  for (field = TYPE_FIELDS (rhs_struct_type);
+       field != NULL_TREE;
+       field = TREE_CHAIN (field))
+    {
+      if (DECL_NAME (field) != NULL_TREE
+	  || (TREE_CODE (TREE_TYPE (field)) != RECORD_TYPE
+	      && TREE_CODE (TREE_TYPE (field)) != UNION_TYPE))
+	continue;
+      if (comptypes (lhs_main_type, TYPE_MAIN_VARIANT (TREE_TYPE (field))))
+	{
+	  if (found_field != NULL_TREE)
+	    return NULL_TREE;
+	  found_field = field;
+	}
+      else if (find_anonymous_field_with_type (TREE_TYPE (field),
+					       lhs_main_type))
+	{
+	  if (found_field != NULL_TREE)
+	    return NULL_TREE;
+	  found_field = field;
+	  found_sub_field = true;
+	}
+    }
+
+  if (found_field == NULL_TREE)
+    return NULL_TREE;
+
+  ret = fold_build3_loc (location, COMPONENT_REF, TREE_TYPE (found_field),
+			 build_fold_indirect_ref (rhs), found_field,
+			 NULL_TREE);
+  ret = build_fold_addr_expr_loc (location, ret);
+
+  if (found_sub_field)
+    {
+      ret = convert_to_anonymous_field (location, type, ret);
+      gcc_assert (ret != NULL_TREE);
+    }
+
+  return ret;
+}
+
 /* Convert value RHS to type TYPE as preparation for an assignment to
    an lvalue of type TYPE.  If ORIGTYPE is not NULL_TREE, it is the
    original type of RHS; this differs from TREE_TYPE (RHS) for enum
@@ -4898,7 +5145,7 @@
         pedwarn (LOCATION, OPT, AS);                                     \
         break;                                                           \
       case ic_init:                                                      \
-        pedwarn (LOCATION, OPT, IN);                                     \
+        pedwarn_init (LOCATION, OPT, IN);                                \
         break;                                                           \
       case ic_return:                                                    \
         pedwarn (LOCATION, OPT, RE);                                     \
@@ -4908,6 +5155,36 @@
       }                                                                  \
   } while (0)
 
+  /* This macro is used to emit diagnostics to ensure that all format
+     strings are complete sentences, visible to gettext and checked at
+     compile time.  It is the same as WARN_FOR_ASSIGNMENT but with an
+     extra parameter to enumerate qualifiers.  */
+
+#define WARN_FOR_QUALIFIERS(LOCATION, OPT, AR, AS, IN, RE, QUALS)        \
+  do {                                                                   \
+    switch (errtype)                                                     \
+      {                                                                  \
+      case ic_argpass:                                                   \
+        if (pedwarn (LOCATION, OPT, AR, parmnum, rname, QUALS))          \
+          inform ((fundecl && !DECL_IS_BUILTIN (fundecl))	         \
+	      	  ? DECL_SOURCE_LOCATION (fundecl) : LOCATION,		 \
+                  "expected %qT but argument is of type %qT",            \
+                  type, rhstype);                                        \
+        break;                                                           \
+      case ic_assign:                                                    \
+        pedwarn (LOCATION, OPT, AS, QUALS);                          \
+        break;                                                           \
+      case ic_init:                                                      \
+        pedwarn (LOCATION, OPT, IN, QUALS);                          \
+        break;                                                           \
+      case ic_return:                                                    \
+        pedwarn (LOCATION, OPT, RE, QUALS);                        	 \
+        break;                                                           \
+      default:                                                           \
+        gcc_unreachable ();                                              \
+      }                                                                  \
+  } while (0)
+
   if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
 
@@ -5025,11 +5302,11 @@
     {
       tree ret;
       bool save = in_late_binary_op;
-      if (codel == BOOLEAN_TYPE)
-    in_late_binary_op = true;
+      if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE)
+	in_late_binary_op = true;
       ret = convert_and_check (type, orig_rhs);
-      if (codel == BOOLEAN_TYPE)
-    in_late_binary_op = save;
+      if (codel == BOOLEAN_TYPE || codel == COMPLEX_TYPE)
+	in_late_binary_op = save;
       return ret;
     }
 
@@ -5039,116 +5316,118 @@
       && comptypes (type, rhstype))
     return convert_and_check (type, rhs);
 
-  /* Conversion to a transparent union from its member types.
+  /* Conversion to a transparent union or record from its member types.
      This applies only to function arguments.  */
-  if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type)
+  if (((codel == UNION_TYPE || codel == RECORD_TYPE)
+      && TYPE_TRANSPARENT_AGGR (type))
       && errtype == ic_argpass)
     {
       tree memb, marginal_memb = NULL_TREE;
 
-      for (memb = TYPE_FIELDS (type); memb ; memb = TREE_CHAIN (memb))
-    {
-      tree memb_type = TREE_TYPE (memb);
-
-      if (comptypes (TYPE_MAIN_VARIANT (memb_type),
-             TYPE_MAIN_VARIANT (rhstype)))
-        break;
-
-      if (TREE_CODE (memb_type) != POINTER_TYPE)
-        continue;
-
-      if (coder == POINTER_TYPE)
-        {
-          tree ttl = TREE_TYPE (memb_type);
-          tree ttr = TREE_TYPE (rhstype);
-
-          /* 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 (location, memb_type, rhstype))
-        {
-          /* 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;
-
-          /* Keep looking for a better type, but remember this one.  */
-          if (!marginal_memb)
-            marginal_memb = memb;
-        }
-        }
-
-      /* Can convert integer zero to any pointer type.  */
-      if (null_pointer_constant)
-        {
-          rhs = null_pointer_node;
-          break;
-        }
-    }
+      for (memb = TYPE_FIELDS (type); memb ; memb = DECL_CHAIN (memb))
+	{
+	  tree memb_type = TREE_TYPE (memb);
+
+	  if (comptypes (TYPE_MAIN_VARIANT (memb_type),
+			 TYPE_MAIN_VARIANT (rhstype)))
+	    break;
+
+	  if (TREE_CODE (memb_type) != POINTER_TYPE)
+	    continue;
+
+	  if (coder == POINTER_TYPE)
+	    {
+	      tree ttl = TREE_TYPE (memb_type);
+	      tree ttr = TREE_TYPE (rhstype);
+
+	      /* 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 (location, memb_type, rhstype))
+		{
+		  /* 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;
+
+		  /* Keep looking for a better type, but remember this one.  */
+		  if (!marginal_memb)
+		    marginal_memb = memb;
+		}
+	    }
+
+	  /* Can convert integer zero to any pointer type.  */
+	  if (null_pointer_constant)
+	    {
+	      rhs = null_pointer_node;
+	      break;
+	    }
+	}
 
       if (memb || marginal_memb)
-    {
-      if (!memb)
-        {
-          /* We have only a marginally acceptable member type;
-         it needs a warning.  */
-          tree ttl = TREE_TYPE (TREE_TYPE (marginal_memb));
-          tree ttr = TREE_TYPE (rhstype);
-
-          /* 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_NO_ADDR_SPACE (ttl)
-              & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
-            WARN_FOR_ASSIGNMENT (location, 0,
-                     G_("passing argument %d of %qE "
-                        "makes qualified function "
-                        "pointer from unqualified"),
-                     G_("assignment makes qualified "
-                        "function pointer from "
-                        "unqualified"),
-                     G_("initialization makes qualified "
-                        "function pointer from "
-                        "unqualified"),
-                     G_("return makes qualified function "
-                        "pointer from unqualified"));
-        }
-          else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
-               & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
-        WARN_FOR_ASSIGNMENT (location, 0,
-                     G_("passing argument %d of %qE discards "
-                    "qualifiers from pointer target type"),
-                     G_("assignment discards qualifiers "
-                    "from pointer target type"),
-                     G_("initialization discards qualifiers "
-                    "from pointer target type"),
-                     G_("return discards qualifiers from "
-                    "pointer target type"));
-
-          memb = marginal_memb;
-        }
-
-      if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl))
-        pedwarn (location, OPT_pedantic,
-             "ISO C prohibits argument conversion to union type");
-
-      rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs);
-      return build_constructor_single (type, memb, rhs);
-    }
+	{
+	  if (!memb)
+	    {
+	      /* We have only a marginally acceptable member type;
+		 it needs a warning.  */
+	      tree ttl = TREE_TYPE (TREE_TYPE (marginal_memb));
+	      tree ttr = TREE_TYPE (rhstype);
+
+	      /* 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_NO_ADDR_SPACE (ttl)
+		      & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
+		    WARN_FOR_QUALIFIERS (location, 0,
+					 G_("passing argument %d of %qE "
+					    "makes %q#v qualified function "
+					    "pointer from unqualified"),
+					 G_("assignment makes %q#v qualified "
+					    "function pointer from "
+					    "unqualified"),
+					 G_("initialization makes %q#v qualified "
+					    "function pointer from "
+					    "unqualified"),
+					 G_("return makes %q#v qualified function "
+					    "pointer from unqualified"),
+					 TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
+		}
+	      else if (TYPE_QUALS_NO_ADDR_SPACE (ttr)
+		       & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
+		WARN_FOR_QUALIFIERS (location, 0,
+				     G_("passing argument %d of %qE discards "
+					"%qv qualifier from pointer target type"),
+				     G_("assignment discards %qv qualifier "
+					"from pointer target type"),
+				     G_("initialization discards %qv qualifier "
+					"from pointer target type"),
+				     G_("return discards %qv qualifier from "
+					"pointer target type"),
+				     TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+	      memb = marginal_memb;
+	    }
+
+	  if (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl))
+	    pedwarn (location, OPT_pedantic,
+		     "ISO C prohibits argument conversion to union type");
+
+	  rhs = fold_convert_loc (location, TREE_TYPE (memb), rhs);
+	  return build_constructor_single (type, memb, rhs);
+	}
     }
 
   /* Conversions among pointers */
@@ -5171,6 +5450,25 @@
       /* Opaque pointers are treated like void pointers.  */
       is_opaque_pointer = vector_targets_convertible_p (ttl, ttr);
 
+      /* The Plan 9 compiler permits a pointer to a struct to be
+	 automatically converted into a pointer to an anonymous field
+	 within the struct.  */
+      if (flag_plan9_extensions
+	  && (TREE_CODE (mvl) == RECORD_TYPE || TREE_CODE(mvl) == UNION_TYPE)
+	  && (TREE_CODE (mvr) == RECORD_TYPE || TREE_CODE(mvr) == UNION_TYPE)
+	  && mvl != mvr)
+	{
+	  tree new_rhs = convert_to_anonymous_field (location, type, rhs);
+	  if (new_rhs != NULL_TREE)
+	    {
+	      rhs = new_rhs;
+	      rhstype = TREE_TYPE (rhs);
+	      coder = TREE_CODE (rhstype);
+	      ttr = TREE_TYPE (rhstype);
+	      mvr = TYPE_MAIN_VARIANT (ttr);
+	    }
+	}
+
       /* C++ does not allow the implicit conversion void* -> T*.  However,
      for the purpose of reducing the number of false positives, we
      tolerate the special case of
@@ -5250,87 +5548,85 @@
      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 (location, type, rhstype))
-      || is_opaque_pointer
-      || (c_common_unsigned_type (mvl)
-          == c_common_unsigned_type (mvr)))
-    {
-      if (pedantic
-          && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
-          ||
-          (VOID_TYPE_P (ttr)
-           && !null_pointer_constant
-           && TREE_CODE (ttl) == FUNCTION_TYPE)))
-        WARN_FOR_ASSIGNMENT (location, OPT_pedantic,
-                 G_("ISO C forbids passing argument %d of "
-                    "%qE between function pointer "
-                    "and %<void *%>"),
-                 G_("ISO C forbids assignment between "
-                    "function pointer and %<void *%>"),
-                 G_("ISO C forbids initialization between "
-                    "function pointer and %<void *%>"),
-                 G_("ISO C forbids return between function "
-                    "pointer and %<void *%>"));
-      /* 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_NO_ADDR_SPACE (ttr)
-          & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
-        {
-          /* Types differing only by the presence of the 'volatile'
-             qualifier are acceptable if the 'volatile' has been added
-             in by the Objective-C EH machinery.  */
-          if (!objc_type_quals_match (ttl, ttr))
-            WARN_FOR_ASSIGNMENT (location, 0,
-                     G_("passing argument %d of %qE discards "
-                        "qualifiers from pointer target type"),
-                     G_("assignment discards qualifiers "
-                        "from pointer target type"),
-                     G_("initialization discards qualifiers "
-                        "from pointer target type"),
-                     G_("return discards qualifiers from "
-                        "pointer target type"));
-        }
-          /* 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 (warn_pointer_sign)
-        WARN_FOR_ASSIGNMENT (location, OPT_Wpointer_sign,
-                     G_("pointer targets in passing argument "
-                    "%d of %qE differ in signedness"),
-                     G_("pointer targets in assignment "
-                    "differ in signedness"),
-                     G_("pointer targets in initialization "
-                    "differ in signedness"),
-                     G_("pointer targets in return differ "
-                    "in signedness"));
-        }
-      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_NO_ADDR_SPACE (ttl)
-          & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
-        WARN_FOR_ASSIGNMENT (location, 0,
-                     G_("passing argument %d of %qE makes "
-                    "qualified function pointer "
-                    "from unqualified"),
-                     G_("assignment makes qualified function "
-                    "pointer from unqualified"),
-                     G_("initialization makes qualified "
-                    "function pointer from unqualified"),
-                     G_("return makes qualified function "
-                    "pointer from unqualified"));
-        }
-    }
+	  || (target_cmp = comp_target_types (location, type, rhstype))
+	  || is_opaque_pointer
+	  || (c_common_unsigned_type (mvl)
+	      == c_common_unsigned_type (mvr)))
+	{
+	  if (pedantic
+	      && ((VOID_TYPE_P (ttl) && TREE_CODE (ttr) == FUNCTION_TYPE)
+		  ||
+		  (VOID_TYPE_P (ttr)
+		   && !null_pointer_constant
+		   && TREE_CODE (ttl) == FUNCTION_TYPE)))
+	    WARN_FOR_ASSIGNMENT (location, OPT_pedantic,
+				 G_("ISO C forbids passing argument %d of "
+				    "%qE between function pointer "
+				    "and %<void *%>"),
+				 G_("ISO C forbids assignment between "
+				    "function pointer and %<void *%>"),
+				 G_("ISO C forbids initialization between "
+				    "function pointer and %<void *%>"),
+				 G_("ISO C forbids return between function "
+				    "pointer and %<void *%>"));
+	  /* 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_NO_ADDR_SPACE (ttr)
+		  & ~TYPE_QUALS_NO_ADDR_SPACE (ttl))
+		{
+		  WARN_FOR_QUALIFIERS (location, 0,
+				       G_("passing argument %d of %qE discards "
+					  "%qv qualifier from pointer target type"),
+				       G_("assignment discards %qv qualifier "
+					  "from pointer target type"),
+				       G_("initialization discards %qv qualifier "
+					  "from pointer target type"),
+				       G_("return discards %qv qualifier from "
+					  "pointer target type"),
+				       TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl));
+		}
+	      /* 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 (warn_pointer_sign)
+		WARN_FOR_ASSIGNMENT (location, OPT_Wpointer_sign,
+				     G_("pointer targets in passing argument "
+					"%d of %qE differ in signedness"),
+				     G_("pointer targets in assignment "
+					"differ in signedness"),
+				     G_("pointer targets in initialization "
+					"differ in signedness"),
+				     G_("pointer targets in return differ "
+					"in signedness"));
+	    }
+	  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_NO_ADDR_SPACE (ttl)
+		  & ~TYPE_QUALS_NO_ADDR_SPACE (ttr))
+		WARN_FOR_QUALIFIERS (location, 0,
+				     G_("passing argument %d of %qE makes "
+					"%q#v qualified function pointer "
+					"from unqualified"),
+				     G_("assignment makes %q#v qualified function "
+					"pointer from unqualified"),
+				     G_("initialization makes %q#v qualified "
+					"function pointer from unqualified"),
+				     G_("return makes %q#v qualified function "
+					"pointer from unqualified"),
+				     TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr));
+	    }
+	}
       else
     /* Avoid warning about the volatile ObjC EH puts on decls.  */
     if (!objc_ok)
@@ -5637,15 +5933,16 @@
 }
 
 /* Issue an error message for a bad initializer component.
-   MSGID identifies the message.
+   GMSGID identifies the message.
    The component name is taken from the spelling stack.  */
 
 void
-error_init (const char *msgid)
+error_init (const char *gmsgid)
 {
   char *ofwhat;
 
-  error ("%s", _(msgid));
+  /* The gmsgid may be a format string with %< and %>. */
+  error (gmsgid);
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat)
     error ("(near initialization for %qs)", ofwhat);
@@ -5653,15 +5950,16 @@
 
 /* Issue a pedantic warning for a bad initializer component.  OPT is
    the option OPT_* (from options.h) controlling this warning or 0 if
-   it is unconditionally given.  MSGID identifies the message.  The
+   it is unconditionally given.  GMSGID identifies the message.  The
    component name is taken from the spelling stack.  */
 
 void
-pedwarn_init (location_t location, int opt, const char *msgid)
+pedwarn_init (location_t location, int opt, const char *gmsgid)
 {
   char *ofwhat;
-
-  pedwarn (location, opt, "%s", _(msgid));
+  
+  /* The gmsgid may be a format string with %< and %>. */
+  pedwarn (location, opt, gmsgid);
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat)
     pedwarn (location, opt, "(near initialization for %qs)", ofwhat);
@@ -5670,15 +5968,16 @@
 /* Issue a warning for a bad initializer component.
 
    OPT is the OPT_W* value corresponding to the warning option that
-   controls this warning.  MSGID identifies the message.  The
+   controls this warning.  GMSGID identifies the message.  The
    component name is taken from the spelling stack.  */
 
 static void
-warning_init (int opt, const char *msgid)
+warning_init (int opt, const char *gmsgid)
 {
   char *ofwhat;
 
-  warning (opt, "%s", _(msgid));
+  /* The gmsgid may be a format string with %< and %>. */
+  warning (opt, gmsgid);
   ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
   if (*ofwhat)
     warning (opt, "(near initialization for %qs)", ofwhat);
@@ -6329,8 +6628,8 @@
       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);
+	     && DECL_NAME (constructor_fields) == 0)
+	constructor_fields = DECL_CHAIN (constructor_fields);
 
       constructor_unfilled_fields = constructor_fields;
       constructor_bit_index = bitsize_zero_node;
@@ -6338,26 +6637,26 @@
   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_cst (NULL_TREE, -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_cst (NULL_TREE, -1);
-
-      constructor_index
-        = convert (bitsizetype,
-               TYPE_MIN_VALUE (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 = integer_minus_one_node;
+
+	  /* 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 = integer_minus_one_node;
+
+	  constructor_index
+	    = convert (bitsizetype,
+		       TYPE_MIN_VALUE (TYPE_DOMAIN (constructor_type)));
+	}
       else
     {
       constructor_index = bitsize_zero_node;
@@ -6388,7 +6687,7 @@
    IMPLICIT is 1 (or 2 if the push is because of designator list).  */
 
 void
-push_init_level (int implicit)
+push_init_level (int implicit, struct obstack * braced_init_obstack)
 {
   struct constructor_stack *p;
   tree value = NULL_TREE;
@@ -6402,19 +6701,21 @@
   if (implicit != 1)
     {
       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), true);
-      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), true);
-      else
-        break;
-    }
+	{
+	  if ((TREE_CODE (constructor_type) == RECORD_TYPE
+	       || TREE_CODE (constructor_type) == UNION_TYPE)
+	      && constructor_fields == 0)
+	    process_init_element (pop_init_level (1, braced_init_obstack),
+				  true, braced_init_obstack);
+	  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, braced_init_obstack),
+				  true, braced_init_obstack);
+	  else
+	    break;
+	}
     }
 
   /* Unless this is an explicit brace, we need to preserve previous
@@ -6422,11 +6723,11 @@
   if (implicit)
     {
       if ((TREE_CODE (constructor_type) == RECORD_TYPE
-       || TREE_CODE (constructor_type) == UNION_TYPE)
-      && constructor_fields)
-    value = find_init_member (constructor_fields);
+	   || TREE_CODE (constructor_type) == UNION_TYPE)
+	  && constructor_fields)
+	value = find_init_member (constructor_fields, braced_init_obstack);
       else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    value = find_init_member (constructor_index);
+	value = find_init_member (constructor_index, braced_init_obstack);
     }
 
   p = XNEW (struct constructor_stack);
@@ -6510,9 +6811,9 @@
       constructor_nonconst = CONSTRUCTOR_NON_CONST (value);
       constructor_elements = CONSTRUCTOR_ELTS (value);
       if (!VEC_empty (constructor_elt, constructor_elements)
-      && (TREE_CODE (constructor_type) == RECORD_TYPE
-          || TREE_CODE (constructor_type) == ARRAY_TYPE))
-    set_nonincremental_init ();
+	  && (TREE_CODE (constructor_type) == RECORD_TYPE
+	      || TREE_CODE (constructor_type) == ARRAY_TYPE))
+	set_nonincremental_init (braced_init_obstack);
     }
 
   if (implicit == 1 && warn_missing_braces && !missing_braces_mentioned)
@@ -6527,8 +6828,8 @@
       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);
+	     && DECL_NAME (constructor_fields) == 0)
+	constructor_fields = DECL_CHAIN (constructor_fields);
 
       constructor_unfilled_fields = constructor_fields;
       constructor_bit_index = bitsize_zero_node;
@@ -6544,37 +6845,37 @@
   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_cst (NULL_TREE, -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_cst (NULL_TREE, -1);
-
-      constructor_index
-        = convert (bitsizetype,
-               TYPE_MIN_VALUE (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 = integer_minus_one_node;
+
+	  /* 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 = integer_minus_one_node;
+
+	  constructor_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);
-    }
+	{
+	  /* 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, braced_init_obstack);
+	}
     }
   else
     {
@@ -6597,7 +6898,7 @@
    Otherwise, return a CONSTRUCTOR expression as the value.  */
 
 struct c_expr
-pop_init_level (int implicit)
+pop_init_level (int implicit, struct obstack * braced_init_obstack)
 {
   struct constructor_stack *p;
   struct c_expr ret;
@@ -6610,14 +6911,16 @@
       /* 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), true);
-
+	{
+	  process_init_element (pop_init_level (1, braced_init_obstack),
+				true, braced_init_obstack);
+	}
       gcc_assert (!constructor_range_stack);
     }
 
   /* Now output all pending elements.  */
   constructor_incremental = 1;
-  output_pending_init_elements (1);
+  output_pending_init_elements (1, braced_init_obstack);
 
   p = constructor_stack;
 
@@ -6633,21 +6936,22 @@
       if (integer_zerop (constructor_unfilled_index))
     constructor_type = NULL_TREE;
       else
-    {
-      gcc_assert (!TYPE_SIZE (constructor_type));
-
-      if (constructor_depth > 2)
-        error_init ("initialization of flexible array member in a nested context");
-      else
-        pedwarn_init (input_location, OPT_pedantic,
-              "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 die later.  */
-      if (TREE_CHAIN (constructor_fields) != NULL_TREE)
-        constructor_type = NULL_TREE;
-    }
+	{
+	  gcc_assert (!TYPE_SIZE (constructor_type));
+
+	  if (constructor_depth > 2)
+	    error_init ("initialization of flexible array member in a nested context");
+	  else
+	    pedwarn_init (input_location, OPT_pedantic,
+			  "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 die later.  */
+	  if (DECL_CHAIN (constructor_fields) != NULL_TREE)
+	    constructor_type = NULL_TREE;
+	}
     }
 
   /* Warn when some struct elements are implicitly initialized to zero.  */
@@ -6656,18 +6960,18 @@
       && 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);
-
-    /* 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 (OPT_Wmissing_field_initializers,
+	/* 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 = DECL_CHAIN (constructor_unfilled_fields);
+
+	/* 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 (OPT_Wmissing_field_initializers,
                           "missing initializer");
         RESTORE_SPELLING_DEPTH (constructor_depth);
       }
@@ -6758,7 +7062,7 @@
    ARRAY argument is nonzero for array ranges.  Returns zero for success.  */
 
 static int
-set_designator (int array)
+set_designator (int array, struct obstack * braced_init_obstack)
 {
   tree subtype;
   enum tree_code subcode;
@@ -6780,7 +7084,10 @@
       /* Designator list starts at the level of closest explicit
      braces.  */
       while (constructor_stack->implicit)
-    process_init_element (pop_init_level (1), true);
+	{
+	  process_init_element (pop_init_level (1, braced_init_obstack),
+				true, braced_init_obstack);
+	}
       constructor_designated = 1;
       return 0;
     }
@@ -6813,7 +7120,7 @@
     }
 
   constructor_designated = 1;
-  push_init_level (2);
+  push_init_level (2, braced_init_obstack);
   return 0;
 }
 
@@ -6822,11 +7129,13 @@
    NULL_TREE if there is no range designator at this level.  */
 
 static void
-push_range_stack (tree range_end)
+push_range_stack (tree range_end, struct obstack * braced_init_obstack)
 {
   struct constructor_range_stack *p;
 
-  p = GGC_NEW (struct constructor_range_stack);
+  p = (struct constructor_range_stack *)
+    obstack_alloc (braced_init_obstack,
+		   sizeof (struct constructor_range_stack));
   p->prev = constructor_range_stack;
   p->next = 0;
   p->fields = constructor_fields;
@@ -6844,9 +7153,10 @@
    of indices, running from FIRST through LAST.  */
 
 void
-set_init_index (tree first, tree last)
-{
-  if (set_designator (1))
+set_init_index (tree first, tree last,
+		struct obstack * braced_init_obstack)
+{
+  if (set_designator (1, braced_init_obstack))
     return;
 
   designator_erroneous = 1;
@@ -6918,18 +7228,18 @@
       designator_depth++;
       designator_erroneous = 0;
       if (constructor_range_stack || last)
-    push_range_stack (last);
+	push_range_stack (last, braced_init_obstack);
     }
 }
 
 /* Within a struct initializer, specify the next field to be initialized.  */
 
 void
-set_init_label (tree fieldname)
-{
-  tree tail;
-
-  if (set_designator (0))
+set_init_label (tree fieldname, struct obstack * braced_init_obstack)
+{
+  tree field;
+
+  if (set_designator (0, braced_init_obstack))
     return;
 
   designator_erroneous = 1;
@@ -6941,25 +7251,29 @@
       return;
     }
 
-  for (tail = TYPE_FIELDS (constructor_type); tail;
-       tail = TREE_CHAIN (tail))
-    {
-      if (DECL_NAME (tail) == fieldname)
-    break;
-    }
-
-  if (tail == 0)
+  field = lookup_field (constructor_type, fieldname);
+
+  if (field == 0)
     error ("unknown field %qE specified in initializer", fieldname);
-  else
-    {
-      constructor_fields = tail;
-      designator_depth++;
-      designator_erroneous = 0;
-      if (constructor_range_stack)
-    push_range_stack (NULL_TREE);
-    }
-}
-
+ else
+    do
+      {
+	constructor_fields = TREE_VALUE (field);
+	designator_depth++;
+	designator_erroneous = 0;
+	if (constructor_range_stack)
+	  push_range_stack (NULL_TREE, braced_init_obstack);
+	field = TREE_CHAIN (field);
+	if (field)
+	  {
+	    if (set_designator (0, braced_init_obstack))
+	      return;
+	  }
+      }
+    while (field != NULL_TREE);
+
+}
+
 /* 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.  If ORIGTYPE is not
@@ -6971,7 +7285,8 @@
    existing initializer.  */
 
 static void
-add_pending_init (tree purpose, tree value, tree origtype, bool implicit)
+add_pending_init (tree purpose, tree value, tree origtype, bool implicit,
+		  struct obstack * braced_init_obstack)
 {
   struct init_node *p, **q, *r;
 
@@ -7030,7 +7345,8 @@
     }
     }
 
-  r = GGC_NEW (struct init_node);
+  r = (struct init_node *) obstack_alloc (braced_init_obstack,
+					  sizeof (struct init_node));
   r->purpose = purpose;
   r->value = value;
   r->origtype = origtype;
@@ -7199,7 +7515,7 @@
 /* Build AVL tree from a sorted chain.  */
 
 static void
-set_nonincremental_init (void)
+set_nonincremental_init (struct obstack * braced_init_obstack)
 {
   unsigned HOST_WIDE_INT ix;
   tree index, value;
@@ -7209,7 +7525,10 @@
     return;
 
   FOR_EACH_CONSTRUCTOR_ELT (constructor_elements, ix, index, value)
-    add_pending_init (index, value, NULL_TREE, false);
+    {
+      add_pending_init (index, value, NULL_TREE, false,
+			braced_init_obstack);
+    }
   constructor_elements = 0;
   if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
@@ -7236,7 +7555,8 @@
 /* Build AVL tree from a string constant.  */
 
 static void
-set_nonincremental_init_from_string (tree str)
+set_nonincremental_init_from_string (tree str,
+				     struct obstack * braced_init_obstack)
 {
   tree value, purpose, type;
   HOST_WIDE_INT val[2];
@@ -7299,7 +7619,8 @@
     }
 
       value = build_int_cst_wide (type, val[1], val[0]);
-      add_pending_init (purpose, value, NULL_TREE, false);
+      add_pending_init (purpose, value, NULL_TREE, false,
+                        braced_init_obstack);
     }
 
   constructor_incremental = 0;
@@ -7309,15 +7630,15 @@
    not initialized yet.  */
 
 static tree
-find_init_member (tree field)
+find_init_member (tree field, struct obstack * braced_init_obstack)
 {
   struct init_node *p;
 
   if (TREE_CODE (constructor_type) == ARRAY_TYPE)
     {
       if (constructor_incremental
-      && tree_int_cst_lt (field, constructor_unfilled_index))
-    set_nonincremental_init ();
+	  && tree_int_cst_lt (field, constructor_unfilled_index))
+	set_nonincremental_init (braced_init_obstack);
 
       p = constructor_pending_elts;
       while (p)
@@ -7335,10 +7656,10 @@
       tree bitpos = bit_position (field);
 
       if (constructor_incremental
-      && (!constructor_unfilled_fields
-          || tree_int_cst_lt (bitpos,
-                  bit_position (constructor_unfilled_fields))))
-    set_nonincremental_init ();
+	  && (!constructor_unfilled_fields
+	      || tree_int_cst_lt (bitpos,
+				  bit_position (constructor_unfilled_fields))))
+	set_nonincremental_init (braced_init_obstack);
 
       p = constructor_pending_elts;
       while (p)
@@ -7382,7 +7703,8 @@
 
 static void
 output_init_element (tree value, tree origtype, bool strict_string, tree type,
-             tree field, int pending, bool implicit)
+		     tree field, int pending, bool implicit,
+		     struct obstack * braced_init_obstack)
 {
   tree semantic_type = NULL_TREE;
   constructor_elt *celt;
@@ -7473,10 +7795,10 @@
      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)))))
+	  || (COMPLETE_TYPE_P (TREE_TYPE (field))
+	      && integer_zerop (TYPE_SIZE (TREE_TYPE (field)))
+	      && (TREE_CODE (constructor_type) == ARRAY_TYPE
+		  || DECL_CHAIN (field)))))
     return;
 
   if (semantic_type)
@@ -7498,10 +7820,11 @@
       || !tree_int_cst_equal (field, constructor_unfilled_index)))
     {
       if (constructor_incremental
-      && tree_int_cst_lt (field, constructor_unfilled_index))
-    set_nonincremental_init ();
-
-      add_pending_init (field, value, origtype, implicit);
+	  && tree_int_cst_lt (field, constructor_unfilled_index))
+	set_nonincremental_init (braced_init_obstack);
+
+      add_pending_init (field, value, origtype, implicit,
+			braced_init_obstack);
       return;
     }
   else if (TREE_CODE (constructor_type) == RECORD_TYPE
@@ -7512,22 +7835,23 @@
      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, origtype, implicit);
+	{
+	  if (!constructor_unfilled_fields)
+	    set_nonincremental_init (braced_init_obstack);
+	  else
+	    {
+	      tree bitpos, unfillpos;
+
+	      bitpos = bit_position (field);
+	      unfillpos = bit_position (constructor_unfilled_fields);
+
+	      if (tree_int_cst_lt (bitpos, unfillpos))
+		set_nonincremental_init (braced_init_obstack);
+	    }
+	}
+
+      add_pending_init (field, value, origtype, implicit,
+			braced_init_obstack);
       return;
     }
   else if (TREE_CODE (constructor_type) == UNION_TYPE
@@ -7562,21 +7886,21 @@
   else if (TREE_CODE (constructor_type) == RECORD_TYPE)
     {
       constructor_unfilled_fields
-    = TREE_CHAIN (constructor_unfilled_fields);
+	= DECL_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);
+	     && DECL_C_BIT_FIELD (constructor_unfilled_fields)
+	     && DECL_NAME (constructor_unfilled_fields) == 0)
+	constructor_unfilled_fields =
+	  DECL_CHAIN (constructor_unfilled_fields);
     }
   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);
+    output_pending_init_elements (0, braced_init_obstack);
 }
 
 /* Output any pending elements which have become next.
@@ -7589,9 +7913,8 @@
 
    If ALL is 1, we output space as necessary so that
    we can output all the pending elements.  */
-
 static void
-output_pending_init_elements (int all)
+output_pending_init_elements (int all, struct obstack * braced_init_obstack)
 {
   struct init_node *elt = constructor_pending_elts;
   tree next;
@@ -7607,102 +7930,104 @@
   while (elt)
     {
       if (TREE_CODE (constructor_type) == ARRAY_TYPE)
-    {
-      if (tree_int_cst_equal (elt->purpose,
-                  constructor_unfilled_index))
-        output_init_element (elt->value, elt->origtype, true,
-                 TREE_TYPE (constructor_type),
-                 constructor_unfilled_index, 0, false);
-      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;
-            }
-        }
-        }
-    }
+	{
+	  if (tree_int_cst_equal (elt->purpose,
+				  constructor_unfilled_index))
+	    output_init_element (elt->value, elt->origtype, true,
+				 TREE_TYPE (constructor_type),
+				 constructor_unfilled_index, 0, false,
+				 braced_init_obstack);
+	  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;
+		    }
+		}
+	    }
+	}
       else if (TREE_CODE (constructor_type) == RECORD_TYPE
-           || TREE_CODE (constructor_type) == UNION_TYPE)
-    {
-      tree ctor_unfilled_bitpos, elt_bitpos;
-
-      /* 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, elt->origtype, true,
-                   TREE_TYPE (elt->purpose),
-                   elt->purpose, 0, false);
-        }
-      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;
-            }
-        }
-        }
-    }
+	       || TREE_CODE (constructor_type) == UNION_TYPE)
+	{
+	  tree ctor_unfilled_bitpos, elt_bitpos;
+
+	  /* 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, elt->origtype, true,
+				   TREE_TYPE (elt->purpose),
+				   elt->purpose, 0, false,
+				   braced_init_obstack);
+	    }
+	  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
@@ -7737,7 +8062,8 @@
    existing initializer.  */
 
 void
-process_init_element (struct c_expr value, bool implicit)
+process_init_element (struct c_expr value, bool implicit,
+		      struct obstack * braced_init_obstack)
 {
   tree orig_value = value.value;
   int string_flag = orig_value != 0 && TREE_CODE (orig_value) == STRING_CST;
@@ -7776,15 +8102,17 @@
   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), true);
+	   || TREE_CODE (constructor_type) == UNION_TYPE)
+	  && constructor_fields == 0)
+	process_init_element (pop_init_level (1, braced_init_obstack),
+			      true, braced_init_obstack);
       else if ((TREE_CODE (constructor_type) == ARRAY_TYPE
-            || TREE_CODE (constructor_type) == VECTOR_TYPE)
-           && (constructor_max_index == 0
-           || tree_int_cst_lt (constructor_max_index,
-                       constructor_index)))
-    process_init_element (pop_init_level (1), true);
+	        || TREE_CODE (constructor_type) == VECTOR_TYPE)
+	       && (constructor_max_index == 0
+		   || tree_int_cst_lt (constructor_max_index,
+				       constructor_index)))
+	process_init_element (pop_init_level (1, braced_init_obstack),
+			      true, braced_init_obstack);
       else
     break;
     }
@@ -7814,244 +8142,248 @@
   while (1)
     {
       if (TREE_CODE (constructor_type) == RECORD_TYPE)
-    {
-      tree fieldtype;
-      enum tree_code fieldcode;
-
-      if (constructor_fields == 0)
-        {
-          pedwarn_init (input_location, 0,
-                "excess elements in struct initializer");
-          break;
-        }
-
-      fieldtype = TREE_TYPE (constructor_fields);
-      if (fieldtype != error_mark_node)
-        fieldtype = TYPE_MAIN_VARIANT (fieldtype);
-      fieldcode = TREE_CODE (fieldtype);
-
-      /* 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;
-        }
-
-      /* Accept a string constant to initialize a subarray.  */
-      if (value.value != 0
-          && fieldcode == ARRAY_TYPE
-          && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype))
-          && string_flag)
-        value.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.value != 0
-           && value.value != error_mark_node
-           && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
-           && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
-               || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
-        {
-          push_init_level (1);
-          continue;
-        }
-
-      if (value.value)
-        {
-          push_member_name (constructor_fields);
-          output_init_element (value.value, value.original_type,
-                   strict_string, fieldtype,
-                   constructor_fields, 1, implicit);
-          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_loc (input_location, 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)
-        {
-          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);
-        }
-        }
-
-      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);
-    }
+	{
+	  tree fieldtype;
+	  enum tree_code fieldcode;
+
+	  if (constructor_fields == 0)
+	    {
+	      pedwarn_init (input_location, 0,
+			    "excess elements in struct initializer");
+	      break;
+	    }
+
+	  fieldtype = TREE_TYPE (constructor_fields);
+	  if (fieldtype != error_mark_node)
+	    fieldtype = TYPE_MAIN_VARIANT (fieldtype);
+	  fieldcode = TREE_CODE (fieldtype);
+
+	  /* Error for non-static initialization of a flexible array member.  */
+	  if (fieldcode == ARRAY_TYPE
+	      && !require_constant_value
+	      && TYPE_SIZE (fieldtype) == NULL_TREE
+	      && DECL_CHAIN (constructor_fields) == NULL_TREE)
+	    {
+	      error_init ("non-static initialization of a flexible array member");
+	      break;
+	    }
+
+	  /* Accept a string constant to initialize a subarray.  */
+	  if (value.value != 0
+	      && fieldcode == ARRAY_TYPE
+	      && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype))
+	      && string_flag)
+	    value.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.value != 0
+		   && value.value != error_mark_node
+		   && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
+		   && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
+		       || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
+	    {
+	      push_init_level (1, braced_init_obstack);
+	      continue;
+	    }
+
+	  if (value.value)
+	    {
+	      push_member_name (constructor_fields);
+	      output_init_element (value.value, value.original_type,
+				   strict_string, fieldtype,
+				   constructor_fields, 1, implicit,
+				   braced_init_obstack);
+	      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_loc (input_location, 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)
+		{
+		  constructor_unfilled_fields = DECL_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 =
+		      DECL_CHAIN (constructor_unfilled_fields);
+		}
+	    }
+
+	  constructor_fields = DECL_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 = DECL_CHAIN (constructor_fields);
+	}
       else if (TREE_CODE (constructor_type) == UNION_TYPE)
-    {
-      tree fieldtype;
-      enum tree_code fieldcode;
-
-      if (constructor_fields == 0)
-        {
-          pedwarn_init (input_location, 0,
-                "excess elements in union initializer");
-          break;
-        }
-
-      fieldtype = TREE_TYPE (constructor_fields);
-      if (fieldtype != error_mark_node)
-        fieldtype = TYPE_MAIN_VARIANT (fieldtype);
-      fieldcode = TREE_CODE (fieldtype);
-
-      /* 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 (!in_system_header && !constructor_designated
-          && !(value.value && (integer_zerop (value.value)
-                   || real_zerop (value.value))))
-        warning (OPT_Wtraditional, "traditional C rejects initialization "
-             "of unions");
-
-      /* Accept a string constant to initialize a subarray.  */
-      if (value.value != 0
-          && fieldcode == ARRAY_TYPE
-          && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype))
-          && string_flag)
-        value.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.value != 0
-           && value.value != error_mark_node
-           && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
-           && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
-               || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
-        {
-          push_init_level (1);
-          continue;
-        }
-
-      if (value.value)
-        {
-          push_member_name (constructor_fields);
-          output_init_element (value.value, value.original_type,
-                   strict_string, fieldtype,
-                   constructor_fields, 1, implicit);
-          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);
-        }
-
-      constructor_fields = 0;
-    }
+	{
+	  tree fieldtype;
+	  enum tree_code fieldcode;
+
+	  if (constructor_fields == 0)
+	    {
+	      pedwarn_init (input_location, 0,
+			    "excess elements in union initializer");
+	      break;
+	    }
+
+	  fieldtype = TREE_TYPE (constructor_fields);
+	  if (fieldtype != error_mark_node)
+	    fieldtype = TYPE_MAIN_VARIANT (fieldtype);
+	  fieldcode = TREE_CODE (fieldtype);
+
+	  /* 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 (!in_system_header && !constructor_designated
+	      && !(value.value && (integer_zerop (value.value)
+				   || real_zerop (value.value))))
+	    warning (OPT_Wtraditional, "traditional C rejects initialization "
+		     "of unions");
+
+	  /* Accept a string constant to initialize a subarray.  */
+	  if (value.value != 0
+	      && fieldcode == ARRAY_TYPE
+	      && INTEGRAL_TYPE_P (TREE_TYPE (fieldtype))
+	      && string_flag)
+	    value.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.value != 0
+		   && value.value != error_mark_node
+		   && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != fieldtype
+		   && (fieldcode == RECORD_TYPE || fieldcode == ARRAY_TYPE
+		       || fieldcode == UNION_TYPE || fieldcode == VECTOR_TYPE))
+	    {
+	      push_init_level (1, braced_init_obstack);
+	      continue;
+	    }
+
+	  if (value.value)
+	    {
+	      push_member_name (constructor_fields);
+	      output_init_element (value.value, value.original_type,
+				   strict_string, fieldtype,
+				   constructor_fields, 1, implicit,
+				   braced_init_obstack);
+	      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 = DECL_CHAIN (constructor_fields);
+	    }
+
+	  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);
-
-      /* Accept a string constant to initialize a subarray.  */
-      if (value.value != 0
-          && eltcode == ARRAY_TYPE
-          && INTEGRAL_TYPE_P (TREE_TYPE (elttype))
-          && string_flag)
-        value.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.value != 0
-           && value.value != error_mark_node
-           && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != elttype
-           && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
-               || eltcode == UNION_TYPE || eltcode == VECTOR_TYPE))
-        {
-          push_init_level (1);
-          continue;
-        }
-
-      if (constructor_max_index != 0
-          && (tree_int_cst_lt (constructor_max_index, constructor_index)
-          || integer_all_onesp (constructor_max_index)))
-        {
-          pedwarn_init (input_location, 0,
-                "excess elements in array initializer");
-          break;
-        }
-
-      /* Now output the actual element.  */
-      if (value.value)
-        {
-          push_array_bounds (tree_low_cst (constructor_index, 1));
-          output_init_element (value.value, value.original_type,
-                   strict_string, elttype,
-                   constructor_index, 1, implicit);
-          RESTORE_SPELLING_DEPTH (constructor_depth);
-        }
-
-      constructor_index
-        = size_binop_loc (input_location, PLUS_EXPR,
-                  constructor_index, bitsize_one_node);
-
-      if (!value.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;
-    }
+	{
+	  tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+	  enum tree_code eltcode = TREE_CODE (elttype);
+
+	  /* Accept a string constant to initialize a subarray.  */
+	  if (value.value != 0
+	      && eltcode == ARRAY_TYPE
+	      && INTEGRAL_TYPE_P (TREE_TYPE (elttype))
+	      && string_flag)
+	    value.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.value != 0
+		   && value.value != error_mark_node
+		   && TYPE_MAIN_VARIANT (TREE_TYPE (value.value)) != elttype
+		   && (eltcode == RECORD_TYPE || eltcode == ARRAY_TYPE
+		       || eltcode == UNION_TYPE || eltcode == VECTOR_TYPE))
+	    {
+	      push_init_level (1, braced_init_obstack);
+	      continue;
+	    }
+
+	  if (constructor_max_index != 0
+	      && (tree_int_cst_lt (constructor_max_index, constructor_index)
+		  || integer_all_onesp (constructor_max_index)))
+	    {
+	      pedwarn_init (input_location, 0,
+			    "excess elements in array initializer");
+	      break;
+	    }
+
+	  /* Now output the actual element.  */
+	  if (value.value)
+	    {
+	      push_array_bounds (tree_low_cst (constructor_index, 1));
+	      output_init_element (value.value, value.original_type,
+				   strict_string, elttype,
+				   constructor_index, 1, implicit,
+				   braced_init_obstack);
+	      RESTORE_SPELLING_DEPTH (constructor_depth);
+	    }
+
+	  constructor_index
+	    = size_binop_loc (input_location, PLUS_EXPR,
+			      constructor_index, bitsize_one_node);
+
+	  if (!value.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));
-
-     /* 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 (input_location, 0,
-                "excess elements in vector initializer");
-          break;
-        }
-
-      /* Now output the actual element.  */
-      if (value.value)
-        {
-          if (TREE_CODE (value.value) == VECTOR_CST)
-        elttype = TYPE_MAIN_VARIANT (constructor_type);
-          output_init_element (value.value, value.original_type,
-                   strict_string, elttype,
-                   constructor_index, 1, implicit);
-        }
-
-      constructor_index
-        = size_binop_loc (input_location,
-                  PLUS_EXPR, constructor_index, bitsize_one_node);
-
-      if (!value.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;
-    }
+	{
+	  tree elttype = TYPE_MAIN_VARIANT (TREE_TYPE (constructor_type));
+
+	 /* 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 (input_location, 0,
+			    "excess elements in vector initializer");
+	      break;
+	    }
+
+	  /* Now output the actual element.  */
+	  if (value.value)
+	    {
+	      if (TREE_CODE (value.value) == VECTOR_CST)
+		elttype = TYPE_MAIN_VARIANT (constructor_type);
+	      output_init_element (value.value, value.original_type,
+				   strict_string, elttype,
+				   constructor_index, 1, implicit,
+				   braced_init_obstack);
+	    }
+
+	  constructor_index
+	    = size_binop_loc (input_location,
+			      PLUS_EXPR, constructor_index, bitsize_one_node);
+
+	  if (!value.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;
+	}
 
       /* Handle the sole element allowed in a braced initializer
      for a scalar variable.  */
@@ -8063,63 +8395,67 @@
       break;
     }
       else
-    {
-      if (value.value)
-        output_init_element (value.value, value.original_type,
-                 strict_string, constructor_type,
-                 NULL_TREE, 1, implicit);
-      constructor_fields = 0;
-    }
+	{
+	  if (value.value)
+	    output_init_element (value.value, value.original_type,
+				 strict_string, constructor_type,
+				 NULL_TREE, 1, implicit,
+				 braced_init_obstack);
+	  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)
-        {
-          gcc_assert (constructor_stack->implicit);
-          process_init_element (pop_init_level (1), true);
-        }
-      for (p = range_stack;
-           !p->range_end || tree_int_cst_equal (p->index, p->range_end);
-           p = p->prev)
-        {
-          gcc_assert (constructor_stack->implicit);
-          process_init_element (pop_init_level (1), true);
-        }
-
-      p->index = size_binop_loc (input_location,
-                     PLUS_EXPR, p->index, bitsize_one_node);
-      if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
-        finish = 1;
-
-      while (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;
-        }
-
-      if (!finish)
-        constructor_range_stack = range_stack;
-      continue;
-    }
+	{
+	  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)
+	    {
+	      gcc_assert (constructor_stack->implicit);
+	      process_init_element (pop_init_level (1,
+						    braced_init_obstack),
+				    true, braced_init_obstack);
+	    }
+	  for (p = range_stack;
+	       !p->range_end || tree_int_cst_equal (p->index, p->range_end);
+	       p = p->prev)
+	    {
+	      gcc_assert (constructor_stack->implicit);
+	      process_init_element (pop_init_level (1, braced_init_obstack),
+				    true, braced_init_obstack);
+	    }
+
+	  p->index = size_binop_loc (input_location,
+				     PLUS_EXPR, p->index, bitsize_one_node);
+	  if (tree_int_cst_equal (p->index, p->range_end) && !p->prev)
+	    finish = 1;
+
+	  while (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, braced_init_obstack);
+	      p->stack = constructor_stack;
+	      if (p->range_end && tree_int_cst_equal (p->index, p->range_end))
+		p->index = p->range_start;
+	    }
+
+	  if (!finish)
+	    constructor_range_stack = range_stack;
+	  continue;
+	}
 
       break;
     }
@@ -8174,8 +8510,8 @@
      get an error.  Gross, but ...  */
       STRIP_NOPS (output);
 
-      if (!lvalue_or_else (output, lv_asm))
-    output = error_mark_node;
+      if (!lvalue_or_else (loc, output, lv_asm))
+	output = error_mark_node;
 
       if (output != error_mark_node
       && (TREE_READONLY (output)
@@ -8761,6 +9097,8 @@
 tree
 c_process_expr_stmt (location_t loc, tree expr)
 {
+  tree exprv;
+
   if (!expr)
     return NULL_TREE;
 
@@ -8781,6 +9119,12 @@
       && warn_unused_value)
     emit_side_effect_warnings (loc, expr);
 
+  exprv = expr;
+  while (TREE_CODE (exprv) == COMPOUND_EXPR)
+    exprv = TREE_OPERAND (exprv, 1);
+  if (DECL_P (exprv) || handled_component_p (exprv))
+    mark_exp_read (exprv);
+
   /* If the expression is not of a type to which we cannot assign a line
      number, wrap the thing in a no-op NOP_EXPR.  */
   if (DECL_P (expr) || CONSTANT_CLASS_P (expr))
@@ -9041,7 +9385,7 @@
 
   /* When the computation is in excess precision, the type of the
      final EXCESS_PRECISION_EXPR.  */
-  tree real_result_type = NULL;
+  tree semantic_result_type = NULL;
 
   /* Nonzero means operands have already been type-converted
      in whatever way is necessary.
@@ -9083,6 +9427,10 @@
      precision.  */
   bool may_need_excess_precision;
 
+  /* True means this is a boolean operation that converts both its
+     operands to truth-values.  */
+  bool boolean_op = false;
+
   if (location == UNKNOWN_LOCATION)
     location = input_location;
 
@@ -9297,20 +9645,21 @@
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
       if ((code0 == INTEGER_TYPE || code0 == POINTER_TYPE
-       || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
-       || code0 == FIXED_POINT_TYPE)
-      && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
-          || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
-          || code1 == FIXED_POINT_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 (location, op0);
-      op1 = c_common_truthvalue_conversion (location, op1);
-      converted = 1;
-    }
+	   || code0 == REAL_TYPE || code0 == COMPLEX_TYPE
+	   || code0 == FIXED_POINT_TYPE)
+	  && (code1 == INTEGER_TYPE || code1 == POINTER_TYPE
+	      || code1 == REAL_TYPE || code1 == COMPLEX_TYPE
+	      || code1 == FIXED_POINT_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 (location, op0);
+	  op1 = c_common_truthvalue_conversion (location, op1);
+	  converted = 1;
+	  boolean_op = true;
+	}
       if (code == TRUTH_ANDIF_EXPR)
     {
       int_const_or_overflow = (int_operands
@@ -9340,72 +9689,102 @@
      Also set SHORT_SHIFT if shifting rightward.  */
 
     case RSHIFT_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
-      && code1 == INTEGER_TYPE)
-    {
-      if (TREE_CODE (op1) == INTEGER_CST)
-        {
-          if (tree_int_cst_sgn (op1) < 0)
-        {
-          int_const = false;
-          if (c_inhibit_evaluation_warnings == 0)
-            warning (0, "right shift count is negative");
-        }
-          else
+      if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
         {
-          if (!integer_zerop (op1))
-            short_shift = 1;
-
-          if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
-            {
-              int_const = false;
-              if (c_inhibit_evaluation_warnings == 0)
-            warning (0, "right shift count >= width of type");
-            }
-        }
+          result_type = type0;
+          converted = 1;
         }
-
-      /* 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 (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+	  && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+          && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+	{
+	  result_type = type0;
+	  converted = 1;
+	}
+      else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+	  && code1 == INTEGER_TYPE)
+	{
+	  if (TREE_CODE (op1) == INTEGER_CST)
+	    {
+	      if (tree_int_cst_sgn (op1) < 0)
+		{
+		  int_const = false;
+		  if (c_inhibit_evaluation_warnings == 0)
+		    warning (0, "right shift count is negative");
+		}
+	      else
+		{
+		  if (!integer_zerop (op1))
+		    short_shift = 1;
+
+		  if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+		    {
+		      int_const = false;
+		      if (c_inhibit_evaluation_warnings == 0)
+			warning (0, "right shift count >= width of type");
+		    }
+		}
+	    }
+
+	  /* Use the type of the value to be shifted.  */
+	  result_type = type0;
+	  /* Convert the non vector shift-count to an integer, regardless
+	     of size of value being shifted.  */
+	  if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+	      && 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 LSHIFT_EXPR:
-      if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
-      && code1 == INTEGER_TYPE)
-    {
-      if (TREE_CODE (op1) == INTEGER_CST)
-        {
-          if (tree_int_cst_sgn (op1) < 0)
-        {
-          int_const = false;
-          if (c_inhibit_evaluation_warnings == 0)
-            warning (0, "left shift count is negative");
-        }
-
-          else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+      if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
         {
-          int_const = false;
-          if (c_inhibit_evaluation_warnings == 0)
-            warning (0, "left shift count >= width of type");
-        }
+          result_type = type0;
+          converted = 1;
         }
-
-      /* 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 (code0 == VECTOR_TYPE && code1 == VECTOR_TYPE
+	  && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE
+          && TREE_CODE (TREE_TYPE (type1)) == INTEGER_TYPE
+          && TYPE_VECTOR_SUBPARTS (type0) == TYPE_VECTOR_SUBPARTS (type1))
+	{
+	  result_type = type0;
+	  converted = 1;
+	}
+      else if ((code0 == INTEGER_TYPE || code0 == FIXED_POINT_TYPE)
+	  && code1 == INTEGER_TYPE)
+	{
+	  if (TREE_CODE (op1) == INTEGER_CST)
+	    {
+	      if (tree_int_cst_sgn (op1) < 0)
+		{
+		  int_const = false;
+		  if (c_inhibit_evaluation_warnings == 0)
+		    warning (0, "left shift count is negative");
+		}
+
+	      else if (compare_tree_int (op1, TYPE_PRECISION (type0)) >= 0)
+		{
+		  int_const = false;
+		  if (c_inhibit_evaluation_warnings == 0)
+		    warning (0, "left shift count >= width of type");
+		}
+	    }
+
+	  /* Use the type of the value to be shifted.  */
+	  result_type = type0;
+	  /* Convert the non vector shift-count to an integer, regardless
+	     of size of value being shifted.  */
+	  if (TREE_CODE (TREE_TYPE (op1)) != VECTOR_TYPE
+	      && 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:
@@ -9418,76 +9797,94 @@
      but don't convert the args to int!  */
       build_type = integer_type_node;
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
-       || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE)
-      && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
-          || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
-    short_compare = 1;
+	   || code0 == FIXED_POINT_TYPE || code0 == COMPLEX_TYPE)
+	  && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+	      || code1 == FIXED_POINT_TYPE || code1 == COMPLEX_TYPE))
+	short_compare = 1;
+      else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
+	{
+	  if (TREE_CODE (op0) == ADDR_EXPR
+	      && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
+	    {
+	      if (code == EQ_EXPR)
+		warning_at (location,
+			    OPT_Waddress,
+			    "the comparison will always evaluate as %<false%> "
+			    "for the address of %qD will never be NULL",
+			    TREE_OPERAND (op0, 0));
+	      else
+		warning_at (location,
+			    OPT_Waddress,
+			    "the comparison will always evaluate as %<true%> "
+			    "for the address of %qD will never be NULL",
+			    TREE_OPERAND (op0, 0));
+	    }
+	  result_type = type0;
+	}
+      else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
+	{
+	  if (TREE_CODE (op1) == ADDR_EXPR
+	      && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
+	    {
+	      if (code == EQ_EXPR)
+		warning_at (location,
+			    OPT_Waddress, 
+			    "the comparison will always evaluate as %<false%> "
+			    "for the address of %qD will never be NULL",
+			    TREE_OPERAND (op1, 0));
+	      else
+		warning_at (location,
+			    OPT_Waddress,
+			    "the comparison will always evaluate as %<true%> "
+			    "for the address of %qD will never be NULL",
+			    TREE_OPERAND (op1, 0));
+	    }
+	  result_type = type1;
+	}
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
-    {
-      tree tt0 = TREE_TYPE (type0);
-      tree tt1 = TREE_TYPE (type1);
-      addr_space_t as0 = TYPE_ADDR_SPACE (tt0);
-      addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
-      addr_space_t as_common = ADDR_SPACE_GENERIC;
-
-      /* 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 (location, type0, type1))
-        result_type = common_pointer_type (type0, type1);
-      else if (null_pointer_constant_p (orig_op0))
-        result_type = type1;
-      else if (null_pointer_constant_p (orig_op1))
-        result_type = type0;
-      else if (!addr_space_superset (as0, as1, &as_common))
-        {
-          error_at (location, "comparison of pointers to "
-            "disjoint address spaces");
-          return error_mark_node;
-        }
-      else if (VOID_TYPE_P (tt0))
-        {
-          if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
-        pedwarn (location, OPT_pedantic, "ISO C forbids "
-             "comparison of %<void *%> with function pointer");
-        }
-      else if (VOID_TYPE_P (tt1))
-        {
-          if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
-        pedwarn (location, OPT_pedantic, "ISO C forbids "
-             "comparison of %<void *%> with function pointer");
-        }
-      else
-        /* Avoid warning about the volatile ObjC EH puts on decls.  */
-        if (!objc_ok)
-          pedwarn (location, 0,
-               "comparison of distinct pointer types lacks a cast");
-
-      if (result_type == NULL_TREE)
-        {
-          int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
-          result_type = build_pointer_type
-                  (build_qualified_type (void_type_node, qual));
-        }
-    }
-      else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
-    {
-      if (TREE_CODE (op0) == ADDR_EXPR
-          && decl_with_nonnull_addr_p (TREE_OPERAND (op0, 0)))
-        warning_at (location,
-            OPT_Waddress, "the address of %qD will never be NULL",
-            TREE_OPERAND (op0, 0));
-      result_type = type0;
-    }
-      else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
-    {
-      if (TREE_CODE (op1) == ADDR_EXPR
-          && decl_with_nonnull_addr_p (TREE_OPERAND (op1, 0)))
-        warning_at (location,
-            OPT_Waddress, "the address of %qD will never be NULL",
-            TREE_OPERAND (op1, 0));
-      result_type = type1;
-    }
+	{
+	  tree tt0 = TREE_TYPE (type0);
+	  tree tt1 = TREE_TYPE (type1);
+	  addr_space_t as0 = TYPE_ADDR_SPACE (tt0);
+	  addr_space_t as1 = TYPE_ADDR_SPACE (tt1);
+	  addr_space_t as_common = ADDR_SPACE_GENERIC;
+
+	  /* 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 (location, type0, type1))
+	    result_type = common_pointer_type (type0, type1);
+	  else if (!addr_space_superset (as0, as1, &as_common))
+	    {
+	      error_at (location, "comparison of pointers to "
+			"disjoint address spaces");
+	      return error_mark_node;
+	    }
+	  else if (VOID_TYPE_P (tt0))
+	    {
+	      if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE)
+		pedwarn (location, OPT_pedantic, "ISO C forbids "
+			 "comparison of %<void *%> with function pointer");
+	    }
+	  else if (VOID_TYPE_P (tt1))
+	    {
+	      if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE)
+		pedwarn (location, OPT_pedantic, "ISO C forbids "
+			 "comparison of %<void *%> with function pointer");
+	    }
+	  else
+	    /* Avoid warning about the volatile ObjC EH puts on decls.  */
+	    if (!objc_ok)
+	      pedwarn (location, 0,
+		       "comparison of distinct pointer types lacks a cast");
+
+	  if (result_type == NULL_TREE)
+	    {
+	      int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+	      result_type = build_pointer_type
+			      (build_qualified_type (void_type_node, qual));
+	    }
+	}
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
     {
       result_type = type0;
@@ -9511,53 +9908,62 @@
           || code1 == FIXED_POINT_TYPE))
     short_compare = 1;
       else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
-    {
-      addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0));
-      addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
-      addr_space_t as_common;
-
-      if (comp_target_types (location, type0, type1))
-        {
-          result_type = common_pointer_type (type0, type1);
-          if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
-          != !COMPLETE_TYPE_P (TREE_TYPE (type1)))
-        pedwarn (location, 0,
-             "comparison of complete and incomplete pointers");
-          else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
-        pedwarn (location, OPT_pedantic, "ISO C forbids "
-             "ordered comparisons of pointers to functions");
-        }
-      else if (!addr_space_superset (as0, as1, &as_common))
-        {
-          error_at (location, "comparison of pointers to "
-            "disjoint address spaces");
-          return error_mark_node;
-        }
-      else
-        {
-          int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
-          result_type = build_pointer_type
-                  (build_qualified_type (void_type_node, qual));
-          pedwarn (location, 0,
-               "comparison of distinct pointer types lacks a cast");
-        }
-    }
+	{
+	  addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0));
+	  addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1));
+	  addr_space_t as_common;
+
+	  if (comp_target_types (location, type0, type1))
+	    {
+	      result_type = common_pointer_type (type0, type1);
+	      if (!COMPLETE_TYPE_P (TREE_TYPE (type0))
+		  != !COMPLETE_TYPE_P (TREE_TYPE (type1)))
+		pedwarn (location, 0,
+			 "comparison of complete and incomplete pointers");
+	      else if (TREE_CODE (TREE_TYPE (type0)) == FUNCTION_TYPE)
+		pedwarn (location, OPT_pedantic, "ISO C forbids "
+			 "ordered comparisons of pointers to functions");
+	      else if (null_pointer_constant_p (orig_op0)
+		       || null_pointer_constant_p (orig_op1))
+		warning_at (location, OPT_Wextra,
+			    "ordered comparison of pointer with null pointer");
+
+	    }
+	  else if (!addr_space_superset (as0, as1, &as_common))
+	    {
+	      error_at (location, "comparison of pointers to "
+			"disjoint address spaces");
+	      return error_mark_node;
+	    }
+	  else
+	    {
+	      int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
+	      result_type = build_pointer_type
+			      (build_qualified_type (void_type_node, qual));
+	      pedwarn (location, 0,
+		       "comparison of distinct pointer types lacks a cast");
+	    }
+	}
       else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1))
-    {
-      result_type = type0;
-      if (pedantic)
-        pedwarn (location, OPT_pedantic,
-             "ordered comparison of pointer with integer zero");
-      else if (extra_warnings)
-        warning_at (location, OPT_Wextra,
-             "ordered comparison of pointer with integer zero");
-    }
+	{
+	  result_type = type0;
+	  if (pedantic)
+	    pedwarn (location, OPT_pedantic,
+		     "ordered comparison of pointer with integer zero");
+	  else if (extra_warnings)
+	    warning_at (location, OPT_Wextra,
+			"ordered comparison of pointer with integer zero");
+	}
       else if (code1 == POINTER_TYPE && null_pointer_constant_p (orig_op0))
-    {
-      result_type = type1;
-      pedwarn (location, OPT_pedantic,
-           "ordered comparison of pointer with integer zero");
-    }
+	{
+	  result_type = type1;
+	  if (pedantic)
+	    pedwarn (location, OPT_pedantic,
+		     "ordered comparison of pointer with integer zero");
+	  else if (extra_warnings)
+	    warning_at (location, OPT_Wextra,
+			"ordered comparison of pointer with integer zero");
+	}
       else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
     {
       result_type = type0;
@@ -9597,94 +10003,99 @@
       int none_complex = (!first_complex && !second_complex);
 
       if (shorten || common || short_compare)
-    {
-      result_type = c_common_type (type0, type1);
-      if (result_type == error_mark_node)
-        return error_mark_node;
-    }
+	{
+	  result_type = c_common_type (type0, type1);
+	  do_warn_double_promotion (result_type, type0, type1,
+				    "implicit conversion from %qT to %qT "
+				    "to match other operand of binary "
+				    "expression",
+				    location);
+	  if (result_type == error_mark_node)
+	    return error_mark_node;
+	}
 
       if (first_complex != second_complex
-      && (code == PLUS_EXPR
-          || code == MINUS_EXPR
-          || code == MULT_EXPR
-          || (code == TRUNC_DIV_EXPR && first_complex))
-      && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE
-      && flag_signed_zeros)
-    {
-      /* An operation on mixed real/complex operands must be
-         handled specially, but the language-independent code can
-         more easily optimize the plain complex arithmetic if
-         -fno-signed-zeros.  */
-      tree real_type = TREE_TYPE (result_type);
-      tree real, imag;
-      if (type0 != orig_type0 || type1 != orig_type1)
-        {
-          gcc_assert (may_need_excess_precision && common);
-          real_result_type = c_common_type (orig_type0, orig_type1);
-        }
-      if (first_complex)
-        {
-          if (TREE_TYPE (op0) != result_type)
-        op0 = convert_and_check (result_type, op0);
-          if (TREE_TYPE (op1) != real_type)
-        op1 = convert_and_check (real_type, op1);
-        }
-      else
-        {
-          if (TREE_TYPE (op0) != real_type)
-        op0 = convert_and_check (real_type, op0);
-          if (TREE_TYPE (op1) != result_type)
-        op1 = convert_and_check (result_type, op1);
-        }
-      if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
-        return error_mark_node;
-      if (first_complex)
-        {
-          op0 = c_save_expr (op0);
-          real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR,
-                     op0, 1);
-          imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR,
-                     op0, 1);
-          switch (code)
-        {
-        case MULT_EXPR:
-        case TRUNC_DIV_EXPR:
-          imag = build2 (resultcode, real_type, imag, op1);
-          /* Fall through.  */
-        case PLUS_EXPR:
-        case MINUS_EXPR:
-          real = build2 (resultcode, real_type, real, op1);
-          break;
-        default:
-          gcc_unreachable();
-        }
-        }
-      else
-        {
-          op1 = c_save_expr (op1);
-          real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR,
-                     op1, 1);
-          imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR,
-                     op1, 1);
-          switch (code)
-        {
-        case MULT_EXPR:
-          imag = build2 (resultcode, real_type, op0, imag);
-          /* Fall through.  */
-        case PLUS_EXPR:
-          real = build2 (resultcode, real_type, op0, real);
-          break;
-        case MINUS_EXPR:
-          real = build2 (resultcode, real_type, op0, real);
-          imag = build1 (NEGATE_EXPR, real_type, imag);
-          break;
-        default:
-          gcc_unreachable();
-        }
-        }
-      ret = build2 (COMPLEX_EXPR, result_type, real, imag);
-      goto return_build_binary_op;
-    }
+	  && (code == PLUS_EXPR
+	      || code == MINUS_EXPR
+	      || code == MULT_EXPR
+	      || (code == TRUNC_DIV_EXPR && first_complex))
+	  && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE
+	  && flag_signed_zeros)
+	{
+	  /* An operation on mixed real/complex operands must be
+	     handled specially, but the language-independent code can
+	     more easily optimize the plain complex arithmetic if
+	     -fno-signed-zeros.  */
+	  tree real_type = TREE_TYPE (result_type);
+	  tree real, imag;
+	  if (type0 != orig_type0 || type1 != orig_type1)
+	    {
+	      gcc_assert (may_need_excess_precision && common);
+	      semantic_result_type = c_common_type (orig_type0, orig_type1);
+	    }
+	  if (first_complex)
+	    {
+	      if (TREE_TYPE (op0) != result_type)
+		op0 = convert_and_check (result_type, op0);
+	      if (TREE_TYPE (op1) != real_type)
+		op1 = convert_and_check (real_type, op1);
+	    }
+	  else
+	    {
+	      if (TREE_TYPE (op0) != real_type)
+		op0 = convert_and_check (real_type, op0);
+	      if (TREE_TYPE (op1) != result_type)
+		op1 = convert_and_check (result_type, op1);
+	    }
+	  if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
+	    return error_mark_node;
+	  if (first_complex)
+	    {
+	      op0 = c_save_expr (op0);
+	      real = build_unary_op (EXPR_LOCATION (orig_op0), REALPART_EXPR,
+				     op0, 1);
+	      imag = build_unary_op (EXPR_LOCATION (orig_op0), IMAGPART_EXPR,
+				     op0, 1);
+	      switch (code)
+		{
+		case MULT_EXPR:
+		case TRUNC_DIV_EXPR:
+		  imag = build2 (resultcode, real_type, imag, op1);
+		  /* Fall through.  */
+		case PLUS_EXPR:
+		case MINUS_EXPR:
+		  real = build2 (resultcode, real_type, real, op1);
+		  break;
+		default:
+		  gcc_unreachable();
+		}
+	    }
+	  else
+	    {
+	      op1 = c_save_expr (op1);
+	      real = build_unary_op (EXPR_LOCATION (orig_op1), REALPART_EXPR,
+				     op1, 1);
+	      imag = build_unary_op (EXPR_LOCATION (orig_op1), IMAGPART_EXPR,
+				     op1, 1);
+	      switch (code)
+		{
+		case MULT_EXPR:
+		  imag = build2 (resultcode, real_type, op0, imag);
+		  /* Fall through.  */
+		case PLUS_EXPR:
+		  real = build2 (resultcode, real_type, op0, real);
+		  break;
+		case MINUS_EXPR:
+		  real = build2 (resultcode, real_type, op0, real);
+		  imag = build1 (NEGATE_EXPR, real_type, imag);
+		  break;
+		default:
+		  gcc_unreachable();
+		}
+	    }
+	  ret = build2 (COMPLEX_EXPR, result_type, real, imag);
+	  goto return_build_binary_op;
+	}
 
       /* For certain operations (which identify themselves by shorten != 0)
      if both args were extended from the same smaller type,
@@ -9817,12 +10228,21 @@
       return error_mark_node;
     }
 
+  if (build_type == NULL_TREE)
+    {
+      build_type = result_type;
+      if ((type0 != orig_type0 || type1 != orig_type1)
+	  && !boolean_op)
+	{
+	  gcc_assert (may_need_excess_precision && common);
+	  semantic_result_type = c_common_type (orig_type0, orig_type1);
+	}
+    }
+
   if (!converted)
     {
-      if (TREE_TYPE (op0) != result_type)
-    op0 = convert_and_check (result_type, op0);
-      if (TREE_TYPE (op1) != result_type)
-    op1 = convert_and_check (result_type, op1);
+      op0 = ep_convert_and_check (result_type, op0, semantic_result_type);
+      op1 = ep_convert_and_check (result_type, op1, semantic_result_type);
 
       /* This can happen if one operand has a vector type, and the other
      has a different type.  */
@@ -9830,16 +10250,6 @@
     return error_mark_node;
     }
 
-  if (build_type == NULL_TREE)
-    {
-      build_type = result_type;
-      if (type0 != orig_type0 || type1 != orig_type1)
-    {
-      gcc_assert (may_need_excess_precision && common);
-      real_result_type = c_common_type (orig_type0, orig_type1);
-    }
-    }
-
   /* Treat expressions in initializers specially as they can't trap.  */
   if (int_const_or_overflow)
     ret = (require_constant_value
@@ -9860,8 +10270,8 @@
   else if (TREE_CODE (ret) != INTEGER_CST && int_operands
        && !in_late_binary_op)
     ret = note_integer_operands (ret);
-  if (real_result_type)
-    ret = build1 (EXCESS_PRECISION_EXPR, real_result_type, ret);
+  if (semantic_result_type)
+    ret = build1 (EXCESS_PRECISION_EXPR, semantic_result_type, ret);
   protected_set_expr_location (ret, location);
   return ret;
 }
@@ -9889,6 +10299,10 @@
       error_at (location, "used union type value where scalar is required");
       return error_mark_node;
 
+    case VOID_TYPE:
+      error_at (location, "void value not ignored as it ought to be");
+      return error_mark_node;
+
     case FUNCTION_TYPE:
       gcc_unreachable ();
 
@@ -9901,8 +10315,8 @@
   if (int_operands)
     expr = remove_c_maybe_const_expr (expr);
 
-  /* ??? Should we also give an error for void and vectors rather than
-     leaving those to give errors later?  */
+  /* ??? Should we also give an error for vectors rather than leaving
+     those to give errors later?  */
   expr = c_common_truthvalue_conversion (location, expr);
 
   if (TREE_CODE (expr) == INTEGER_CST && int_operands && !int_const)