diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9f124c17310e8212ff861e2445009e5464b1f3a5..8829c32b0ff0158374f73796e138d0834852d69f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,153 @@
+2004-06-21  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
+
+	* alias.c (adjust_offset_for_component_ref): Use
+	component_ref_field_offset.
+	* c-decl.c (build_array_declarator): Add news args for ARRAY_REF.
+	* c-gimplify.c (gimplify_expr_stmt): Use alloc_stmt_list.
+	(gimplify_decl_stmt): Call gimplify_type_sizes for type.
+	For decl, call gimplify_one_sizepos and use statement list.
+	(gimplify_compound_literal_expr): New arg PRE_P.
+	Add statement to PRE_P list and return DECL.
+	(c_gimplify_expr, case COMPOUND_LITERAL_EXPR): Add arg to
+	gimplify_compound_literal_expr.
+	* c-tree.h (getdecls): Deleted.
+	* c-typeck.c (build_component_ref): Add operand for COMPONENT_REF.
+	(build_array_ref): Add two operands for ARRAY_REF.
+	(build_unary_op): Set TREE_INVARIANT and TREE_CONSTANT for
+	COMPOUND_LITERAL_EXPR.
+	* coverage.c (tree_coverage_counter_ref): Add new operands
+	for ARRAY_REF.
+	* emit-rtl.c (component_ref_for_mem_expr): Add new operand
+	for COMPONENT_REF.
+	(set_mem_attributes_minus_bitpos): Use array_ref_low_bound
+	and array_ref_element_size.
+	(widen_memory_access):Use component_ref_field_offset.
+	* explow.c (update_nonlocal_goto_save_area): Add two operands
+	for ARRAY_REF.
+	* expr.c (array_ref_element_size, array_ref_low_bound): New functions.
+	(component_ref_field_offset): Likewise.
+	(get_inner_reference): Use them.
+	(expand_expr_real_1, case ARRAY_REF): Use array_ref_low_bound.
+	* fold-const.c (fold, case EQ_EXPR): Properly handle DECL_SIZE.
+	(fold_read_from_constant_string): Use array_ref_low_bound.
+	Verify that result is a character type.
+	(build_fold_indirect_ref): Add two operands for ARRAY_REF.
+	* function.c (expand_function_start): Likewise.
+	* gimple-low.c (expand_var_p): Delete duplicated line.
+	* gimplify.c: Add static decls for local functions.
+	(cgraph.h): Now included.
+	(create_tmp_var): Remove check for ARRAY_TYPE.
+	(copy_if_shared_r): Look at bounds and sizes of types.
+	(build_and_jump): Return alloc_stmt_list instead of build_empty_stmt.
+	(gimplify_exit_expr, shortcut_cond_expr): Likewise.
+	(gimplify_save_expr, gimple_push_cleanup): Likewise.
+	(gimplify_init_constructor): Likewise.
+	WANT_VALUE now bool.
+	If empty list with no result wanted, return GS_UNHANDLED.
+	Add additional operands for ARRAY_REF and COMPONENT_REF.
+	(canonicalize_component_ref): Convert to &array[L].
+	(gimplify_array_ref_to_plus): Use array_ref_element_size and
+	array_ref_lower_bound.
+	(build_addr_expr_with_type, build_addr_expr): New functions.
+	(gimplify_compound_lval): WANT_LVALUE now bool.
+	Major rework to allow handle_component_p and initialize and
+	gimplify new operands for ARRAY_REF, ARRAY_RANGE_REF, and
+	COMPONENT_REF.
+	(gimplify_array_ref): Deleted.
+	(gimplify_self_mod_expr): WANT_VALUE now bool.
+	(gimplify_modify_expr): Gimplify to_p and from_p later.
+	Factor out code into gimplify_modify_expr_rhs and call twice.
+	Move variable-size code earlier and handle PLACEHOLDER_EXPR.
+	(gimplify_modify_expr_rhs, gimplify_variable_sized_compare): New fns.
+	(gimplify_addr_expr, case VIEW_CONVERT_EXPR): New case.
+	(gimplify_expr, case ARRAY_REF): Delete special case.
+	Instead handle like COMPONENT_REF; also do ARRAY_RANGE_REF,
+	IMAGPART, and REALPART the same way.
+	(gimplify_expr, case VIEW_CONVERT_EXPR): New case.
+	(gimplify_expr): Call gimplify_variable_sized_compare if applicable.
+	Call alloc_stmt_list instead of build_empty_stmt.
+	Deal with _REF that's volatile.
+	(gimplify_type_sizes, gimplify_one_sizepos): New functions.
+	(unshare_body, unvisit_body): New functions.
+	(gimplify_body): Call them.
+	* stmt.c (expand_stack_alloc): Don't expand TYPE_MAX_VALUE.
+	* stor-layout.c (get_pending_sizes): Don't change SAVE_EXPR_CONTEXT.
+	* tree-alias-common.c (get_alias_var): Also skip ARRAY_RANGE_REF.
+	* tree-cfg.c (tree_node_can_be_shared): Treat ARRAY_RANGE_REF
+	like ARRAY_REF.
+	(verify_expr, case ADDR_EXPR): Use handled_component_p.
+	* tree-dfa.c (get_virtual_var): Likewise.
+	* tree-dump.c (dequeue_and_dump, case COMPONENT_REF, ARRAY_REF):
+	New cases to dump new operands; likewise for ARRAY_RANGE_REF.
+	* tree-eh.c (tree_could_trap, case ARRAY_RANGE_REF): Like ARRAY_REF.
+	* tree-gimple.c (is_gimple_addr_expr_arg): Add ARRAY_RANGE_REF
+	and INDIRECT_REF.
+	(get_base_address): Use handled_component_p.
+	* tree-gimple.h (gimplify_type_sizes, gimplify_one_sizepos): New.
+	* tree-inline.c (walk_tree): Walk more things for types and decls.
+	* tree-mudflap.c (mf_build_check_statement_for): Add new operands
+	for ARRAY_REF and COMPONENT_REF.
+	(mx_xform_derefs_1): Clean up usage of decl sizes.
+	* tree-nested.c (build_addr): Use handled_component_p.
+	(walk_stmts, case CATCH_EXPR): Add missing "break".
+	(get_static_chain, get_frame_field): Add new operand for COMPONENT_REF.
+	(finalize_nesting_tree_1): Likewise.
+	(convert_nonlocal_reference, case ARRAY_RANGE_REF): Like ARRAY_REF
+	and process additional operands.
+	(convert_local_reference): Likewise.
+	* tree-outof-ssa.c (discover_nonconstant_array_refs_r): Treat
+	ARRAY_RANGE_REF similarly to ARRAY_REF.
+	* tree-pretty-print.c (dump_generic_node, case QUAL_UNION_TYPE): Handle
+	like RECORD_TYPE.
+	(dump_generic_node, case COMPONENT_REF): Print offset operand.
+	(dump_generic_node, case ARRAY_RANGE_REF): Treat like ARRAY_REF
+	and print lower bound and element size for both.
+	(op_prio, case ARRAY_RANGE_REF): Like ARRAY_REF.
+	* tree-sra.c (csc_build_component_ref): Add new operand.
+	(scalarize_call_expr): Use get_base_address.
+	* tree-ssa-ccp.c (widen_bitfield): Clean up size handling.
+	(maybe_fold_offset_to_array_ref): Rework to handle input having an
+	ARRAY_REF, refine handling of lower bound, and add new operands
+	for ARRAY_REF.
+	(maybe_fold_to_component_ref): Add new operand for COMPONENT_REF.
+	(maybe_fold_stmt_indirect): Only fold *&B to B if types match.
+	(maybe_fold_stmt_addition): Only handle constant lower bound.
+	* tree-ssa-operands.c (get_expr_operands): Minor rearrangements.
+	Treat ARRAY_REF and ARRAY_RANGE_REF the same; look at extra operands.
+	Look at new offset operand of COMPONENT_REF.
+	* tree-ssa.c (set_is_used): Use handled_component_p.
+	* tree.c (substitute_in_expr, case COMPONENT_REF): Add new operand.
+	(stabilize_reference, case COMPONENT_REF): Likewise.
+	(stabilize_reference, case ARRAY_RANGE_REF, ARRAY_REF): Similarly.
+	(recompute_tree_invariant_for_addr_expr): Completely rework to
+	be more precise.  Also set TREE_SIDE_EFFECTS.
+	(build1_stat, case ARRAY_EXPR): Don't handle TREE_SIDE_EFFECTS here.
+	(build2_stat, build3_stat, build4_stat): For references,
+	propagate TREE_THIS_VOLATILE.
+	(get_unwidened): Add new operand for COMPONENT_REF.
+	(get_narrower): Likewise; use host_integerp for DECL_SIZE.
+	* tree.def (COMPONENT_REF): Add new operand.
+	(ARRAY_REF, ARRAY_RANGE_REF): Add two new operands.
+	* tree.h (array_ref_element_size, array_ref_low_bound): New decls.
+	(component_ref_field_offset): Likewise.
+	* config/alpha/alpha.c (alpha_va_start): Add new op for COMPONENT_REF.
+	(alpha_gimplify_va_arg): Likewise.
+	* config/i386/i386.c (ix86_va_start, ix86_gimplify_va_arg): Likewise.
+	* config/i860/i860.c (i860_va_start, i860_va_arg): Likewise.
+	* config/iq2000/iq2000.c (iq2000_va_arg): Likewise.
+	* config/mips/mips.c (mips_va_start, mips_va_arg): Likewise.
+	* config/rs6000/rs6000.c (rs6000_va_start, rs6000_gimplify_va_arg):
+	Likewise.
+	* config/s390/s390.c (s390_va_start, s390_gimplify_va_arg): Likewise.
+	* config/sh/sh.c (sh_va_start, sh_va_arg): Likewise.
+	* config/stormy16/stormy16.c (xstormy1_expand_builin_va_start):
+	Likewise.
+	(xstormy16_expand_builtin_va_arg): Likewise.
+	* config/xtensa/xtensa.c (xtensa_va_start, xtensa_va_arg): Likewise.
+	* objc/objc-act.c (generate_static_references): Likewise.
+	(generate_strings, build_method_prototype_list_template): Likewise.
+	(generate_protocol_list): Likewise.
+
 2004-06-21  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
 	PR rtl-optimization/14782
diff --git a/gcc/alias.c b/gcc/alias.c
index 8e168c2b47789d95f9249aa3fe03347a3bd486cb..b8661d7b6bdbe98cabc1042afa983bd004e4c93c 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -2015,11 +2015,12 @@ adjust_offset_for_component_ref (tree x, rtx offset)
   ioffset = INTVAL (offset);
   do
     {
+      tree offset = component_ref_field_offset (x);
       tree field = TREE_OPERAND (x, 1);
 
-      if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
+      if (! host_integerp (offset, 1))
 	return NULL_RTX;
-      ioffset += (tree_low_cst (DECL_FIELD_OFFSET (field), 1)
+      ioffset += (tree_low_cst (offset, 1)
 		  + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
 		     / BITS_PER_UNIT));
 
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index ec1778bc35c5cdd989130e5837ef7de6c1daef59..4735dabf6448037b94bc2a9b9840e1131d88246a 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -2508,7 +2508,7 @@ tree
 build_array_declarator (tree expr, tree quals, int static_p, int vla_unspec_p)
 {
   tree decl;
-  decl = build_nt (ARRAY_REF, NULL_TREE, expr);
+  decl = build_nt (ARRAY_REF, NULL_TREE, expr, NULL_TREE, NULL_TREE);
   TREE_TYPE (decl) = quals;
   TREE_STATIC (decl) = (static_p ? 1 : 0);
   if (pedantic && !flag_isoc99)
diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c
index 359733116c441ab747c956f0ad711466e19b4916..113a09d1b16ddaad8ac5ff1249b0095119e0d0cc 100644
--- a/gcc/c-gimplify.c
+++ b/gcc/c-gimplify.c
@@ -243,7 +243,7 @@ gimplify_expr_stmt (tree *stmt_p)
     }
 
   if (stmt == NULL_TREE)
-    stmt = build_empty_stmt ();
+    stmt = alloc_stmt_list ();
 
   *stmt_p = stmt;
 
@@ -475,8 +475,6 @@ gimplify_decl_stmt (tree *stmt_p)
 {
   tree stmt = *stmt_p;
   tree decl = DECL_STMT_DECL (stmt);
-  tree pre = NULL_TREE;
-  tree post = NULL_TREE;
 
   if (TREE_TYPE (decl) == error_mark_node)
     {
@@ -485,38 +483,34 @@ gimplify_decl_stmt (tree *stmt_p)
     }
     
   if (TREE_CODE (decl) == TYPE_DECL)
-    {
-      tree type = TREE_TYPE (decl);
-      if (TYPE_SIZE_UNIT (type)
-          && !TREE_CONSTANT (TYPE_SIZE_UNIT (type)))
-        {
-          /* This is a variable-sized array type.  Simplify its size.  */
-          tree temp = TYPE_SIZE_UNIT (type);
-          gimplify_expr (&temp, &pre, &post, is_gimple_val, fb_rvalue);
-        }
-    }
+    *stmt_p = gimplify_type_sizes (TREE_TYPE (decl));
 
-  if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+  else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
     {
       tree init = DECL_INITIAL (decl);
 
+      *stmt_p = NULL_TREE;
+      gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
+      gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
+
       if (!TREE_CONSTANT (DECL_SIZE (decl)))
 	{
-	  tree pt_type = build_pointer_type (TREE_TYPE (decl));
-	  tree alloc, size;
-
 	  /* This is a variable-sized decl.  Simplify its size and mark it
 	     for deferred expansion.  Note that mudflap depends on the format
 	     of the emitted code: see mx_register_decls().  */
 
-	  size = get_initialized_tmp_var (DECL_SIZE_UNIT (decl), &pre, &post);
+	  tree pt_type = build_pointer_type (TREE_TYPE (decl));
+	  tree alloc_stmt
+	    = (build_function_call_expr
+	       (implicit_built_in_decls[BUILT_IN_STACK_ALLOC],
+		tree_cons (NULL_TREE,
+			   build1 (ADDR_EXPR, pt_type, decl),
+			   tree_cons (NULL_TREE, DECL_SIZE_UNIT (decl),
+				      NULL_TREE))));
+
+	  gimplify_stmt (&alloc_stmt);
+	  append_to_statement_list(alloc_stmt, stmt_p);
 	  DECL_DEFER_OUTPUT (decl) = 1;
-	  alloc = build_function_call_expr
-	    (implicit_built_in_decls[BUILT_IN_STACK_ALLOC],
-	     tree_cons (NULL_TREE,
-			build1 (ADDR_EXPR, pt_type, decl),
-			tree_cons (NULL_TREE, size, NULL_TREE)));
-	  append_to_compound_expr (alloc, &pre);
 	}
 
       if (init && init != error_mark_node)
@@ -531,14 +525,13 @@ gimplify_decl_stmt (tree *stmt_p)
               
 	      DECL_INITIAL (decl) = NULL_TREE;
 	      init = build (MODIFY_EXPR, void_type_node, decl, init);
-	      append_to_compound_expr (init, &pre);
+	      gimplify_stmt (&init);
+	      append_to_statement_list (init, stmt_p);
 	    }
 	  else
-	    {
-	      /* We must still examine initializers for static variables
-		 as they may contain a label address.  */
-	      walk_tree (&init, force_labels_r, NULL, NULL);
-	    }
+	    /* We must still examine initializers for static variables
+	       as they may contain a label address.  */
+	    walk_tree (&init, force_labels_r, NULL, NULL);
 	}
 
       /* This decl isn't mentioned in the enclosing block, so add it to the
@@ -547,10 +540,10 @@ gimplify_decl_stmt (tree *stmt_p)
       if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
 	gimple_add_tmp_var (decl);
     }
+  else
+    *stmt_p = alloc_stmt_list ();
 
-  append_to_compound_expr (post, &pre);
-  *stmt_p = pre;
-  return GS_OK;
+  return GS_ALL_DONE;
 }
 
 /* Gimplification of expression trees.  */
@@ -560,7 +553,7 @@ gimplify_decl_stmt (tree *stmt_p)
    instead.  */
 
 static enum gimplify_status
-gimplify_compound_literal_expr (tree *expr_p)
+gimplify_compound_literal_expr (tree *expr_p, tree *pre_p)
 {
   tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p);
   tree decl = DECL_STMT_DECL (decl_s);
@@ -572,7 +565,8 @@ gimplify_compound_literal_expr (tree *expr_p)
     gimple_add_tmp_var (decl);
 
   gimplify_decl_stmt (&decl_s);
-  *expr_p = decl_s ? decl_s : decl;
+  append_to_statement_list (decl_s, pre_p);
+  *expr_p = decl;
   return GS_OK;
 }
 
@@ -586,7 +580,7 @@ c_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
   switch (code)
     {
     case COMPOUND_LITERAL_EXPR:
-      return gimplify_compound_literal_expr (expr_p);
+      return gimplify_compound_literal_expr (expr_p, pre_p);
 
     case FOR_STMT:
       return gimplify_for_stmt (expr_p, pre_p);
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index 052275ab96f756dc2eaf37a5e8860ac0bd7c4d3a..66691eba29999325321a46091fa9f4abd26115d9 100644
--- a/gcc/c-tree.h
+++ b/gcc/c-tree.h
@@ -147,7 +147,6 @@ extern int c_in_iteration_stmt;
 extern int c_in_case_stmt;
 
 extern int global_bindings_p (void);
-extern tree getdecls (void);
 extern void push_scope (void);
 extern tree pop_scope (void);
 extern void insert_block (tree);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index e619fa13ea51597df24f4aeea25b5ba3f8b65535..63c91210015b5bc81372b8d18f8ce3c5d647a64f 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -1222,10 +1222,10 @@ default_function_array_conversion (tree exp)
 
       if (TREE_CODE (exp) == VAR_DECL)
 	{
-	  /* ??? This is not really quite correct
-	     in that the type of the operand of ADDR_EXPR
-	     is not the target type of the type of the ADDR_EXPR itself.
-	     Question is, can this lossage be avoided?  */
+	  /* We are making an ADDR_EXPR of ptrtype.  This is a valid
+	     ADDR_EXPR because it's the best way of representing what
+	     happens in C when we take the address of an array and place
+	     it in a pointer to the element type.  */
 	  adr = build1 (ADDR_EXPR, ptrtype, exp);
 	  if (!c_mark_addressable (exp))
 	    return error_mark_node;
@@ -1483,7 +1483,8 @@ build_component_ref (tree datum, tree component)
 	  if (TREE_TYPE (subdatum) == error_mark_node)
 	    return error_mark_node;
 
-	  ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum);
+	  ref = build (COMPONENT_REF, TREE_TYPE (subdatum), datum, subdatum,
+		       NULL_TREE);
 	  if (TREE_READONLY (datum) || TREE_READONLY (subdatum))
 	    TREE_READONLY (ref) = 1;
 	  if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (subdatum))
@@ -1636,7 +1637,7 @@ build_array_ref (tree array, tree index)
 	}
 
       type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (array)));
-      rval = build (ARRAY_REF, type, array, index);
+      rval = build (ARRAY_REF, type, array, index, NULL_TREE, NULL_TREE);
       /* Array ref is const/volatile if the array elements are
          or if the array is.  */
       TREE_READONLY (rval)
@@ -2562,6 +2563,9 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
 	else
 	  addr = build1 (code, argtype, arg);
 
+	if (TREE_CODE (arg) == COMPOUND_LITERAL_EXPR)
+	  TREE_INVARIANT (addr) = TREE_CONSTANT (addr) = 1;
+
 	return addr;
       }
 
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 36b765ea69b3342ee00dc200f318f95d6721e9f5..dd4409a217651a80e8340b46aee550f43ccf72ef 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -6274,9 +6274,9 @@ alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
       offset_field = TREE_CHAIN (base_field);
 
       base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
-			  valist, base_field);
+			  valist, base_field, NULL_TREE);
       offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
-			    valist, offset_field);
+			    valist, offset_field, NULL_TREE);
 
       t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
       t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0));
@@ -6383,9 +6383,9 @@ alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   base_field = TYPE_FIELDS (va_list_type_node);
   offset_field = TREE_CHAIN (base_field);
   base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
-		      valist, base_field);
+		      valist, base_field, NULL_TREE);
   offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
-			valist, offset_field);
+			valist, offset_field, NULL_TREE);
 
   /* Pull the fields of the structure out into temporaries.  Since we never
      modify the base field, we can use a formal temporary.  Sign-extend the
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 8313e0a5f39786034e6d3a5cdaa035078dd54459..30d031507e246eeae0f9be8ba589f5e53ea3c1b7 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -3136,10 +3136,10 @@ ix86_va_start (tree valist, rtx nextarg)
   f_sav = TREE_CHAIN (f_ovf);
 
   valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   /* Count number of gp and fp argument registers used.  */
   words = current_function_args_info.words;
@@ -3202,10 +3202,10 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   f_sav = TREE_CHAIN (f_ovf);
 
   valist = build_fold_indirect_ref (valist);
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   size = int_size_in_bytes (type);
   if (size == -1)
diff --git a/gcc/config/i860/i860.c b/gcc/config/i860/i860.c
index 7c455eb3d617afae5b278572a511332c5d6b8f4f..d23277d1dbed48649aaf414345553634ac89b3b3 100644
--- a/gcc/config/i860/i860.c
+++ b/gcc/config/i860/i860.c
@@ -1877,10 +1877,10 @@ i860_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
   f_fpr = TREE_CHAIN (f_gpr);
 #endif
 
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
-  mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
+  mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem, NULL_TREE);
 
   /* Initialize the `mem_ptr' field to the address of the first anonymous
      stack argument.  */
@@ -1943,10 +1943,10 @@ i860_va_arg (tree valist, tree type)
   f_fpr = TREE_CHAIN (f_gpr);
 #endif
 
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   size = int_size_in_bytes (type);
 
diff --git a/gcc/config/iq2000/iq2000.c b/gcc/config/iq2000/iq2000.c
index 41d4a0e17975d055bb604f471fe6594d0d06a077..786a7b6c91e8a9aa23aa1e4fe8dc0b37f2007f38 100644
--- a/gcc/config/iq2000/iq2000.c
+++ b/gcc/config/iq2000/iq2000.c
@@ -1656,11 +1656,11 @@ iq2000_va_arg (tree valist, tree type)
   f_goff = TREE_CHAIN (f_ftop);
   f_foff = TREE_CHAIN (f_goff);
 
-  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
-  gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
-  ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
-  goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
-  foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl, NULL_TREE);
+  gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop, NULL_TREE);
+  ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop, NULL_TREE);
+  goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff, NULL_TREE);
+  foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff, NULL_TREE);
 
   lab_false = gen_label_rtx ();
   lab_over = gen_label_rtx ();
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 9abd0b3c7ee1099ab376a7a0eea902d3b56ff195..15489b19d767fee46e800131cc46bed551fc21cd 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -4045,11 +4045,16 @@ mips_va_start (tree valist, rtx nextarg)
 	  f_goff = TREE_CHAIN (f_ftop);
 	  f_foff = TREE_CHAIN (f_goff);
 
-	  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
-	  gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
-	  ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
-	  goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
-	  foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+	  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
+			NULL_TREE);
+	  gtop = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
+			NULL_TREE);
+	  ftop = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
+			NULL_TREE);
+	  goff = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
+			NULL_TREE);
+	  foff = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
+			NULL_TREE);
 
 	  /* Emit code to initialize OVFL, which points to the next varargs
 	     stack argument.  CUM->STACK_WORDS gives the number of stack
@@ -4212,12 +4217,15 @@ mips_va_arg (tree valist, tree type)
 	  lab_false = gen_label_rtx ();
 	  lab_over = gen_label_rtx ();
 
-	  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl);
+	  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
+			NULL_TREE);
 	  if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
 	      && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
 	    {
-	      top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop);
-	      off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff);
+	      top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
+			   NULL_TREE);
+	      off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
+			   NULL_TREE);
 
 	      /* When floating-point registers are saved to the stack,
 		 each one will take up UNITS_PER_HWFPVALUE bytes, regardless
@@ -4245,8 +4253,10 @@ mips_va_arg (tree valist, tree type)
 	    }
 	  else
 	    {
-	      top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop);
-	      off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff);
+	      top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
+			   NULL_TREE);
+	      off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
+			   NULL_TREE);
 	      if (rsize > UNITS_PER_WORD)
 		{
 		  /* [1] Emit code for: off &= -rsize.	*/
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 2376fc44498fdaa4c3747a7601cb76f33b2a5a16..861b00ad514aaa36d4e99b18559454ba19b92438 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -5026,10 +5026,10 @@ rs6000_va_start (tree valist, rtx nextarg)
   f_sav = TREE_CHAIN (f_ovf);
 
   valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   /* Count number of gp and fp argument registers used.  */
   words = current_function_args_info.words;
@@ -5131,10 +5131,10 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   f_sav = TREE_CHAIN (f_ovf);
 
   valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   size = int_size_in_bytes (type);
   rsize = (size + 3) / 4;
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 3e2ad5a43a6ff17b26efbc5e8040010f4868887f..cc48d015629765c70349746b06734e12f09242c9 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -6381,10 +6381,10 @@ s390_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
   f_sav = TREE_CHAIN (f_ovf);
 
   valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   /* Count number of gp and fp argument registers used.  */
 
@@ -6462,10 +6462,10 @@ s390_gimplify_va_arg (tree valist, tree type, tree *pre_p,
   f_sav = TREE_CHAIN (f_ovf);
 
   valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
-  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
-  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
-  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
-  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+  gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
+  fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
+  ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
+  sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   size = int_size_in_bytes (type);
 
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index d70178bf4958e0493bf44940f0bd4a2bf9332047..2308f1b42d7d619d96367c6ee82e3b780616c18a 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -6237,14 +6237,16 @@ sh_va_start (tree valist, rtx nextarg)
   f_next_fp_limit = TREE_CHAIN (f_next_fp);
   f_next_stack = TREE_CHAIN (f_next_fp_limit);
 
-  next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o);
+  next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
+		  NULL_TREE);
   next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
-			valist, f_next_o_limit);
-  next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp);
+			valist, f_next_o_limit, NULL_TREE);
+  next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp,
+		   NULL_TREE);
   next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
-			 valist, f_next_fp_limit);
+			 valist, f_next_fp_limit, NULL_TREE);
   next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
-		      valist, f_next_stack);
+		      valist, f_next_stack, NULL_TREE);
 
   /* Call __builtin_saveregs.  */
   u = make_tree (ptr_type_node, expand_builtin_saveregs ());
@@ -6317,15 +6319,16 @@ sh_va_arg (tree valist, tree type)
       f_next_fp_limit = TREE_CHAIN (f_next_fp);
       f_next_stack = TREE_CHAIN (f_next_fp_limit);
 
-      next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o);
+      next_o = build (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
+		      NULL_TREE);
       next_o_limit = build (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
-			    valist, f_next_o_limit);
+			    valist, f_next_o_limit, NULL_TREE);
       next_fp = build (COMPONENT_REF, TREE_TYPE (f_next_fp),
-		       valist, f_next_fp);
+		       valist, f_next_fp, NULL_TREE);
       next_fp_limit = build (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
-			     valist, f_next_fp_limit);
+			     valist, f_next_fp_limit, NULL_TREE);
       next_stack = build (COMPONENT_REF, TREE_TYPE (f_next_stack),
-			  valist, f_next_stack);
+			  valist, f_next_stack, NULL_TREE);
 
       /* Structures with a single member with a distinct mode are passed
 	 like their member.  This is relevant if the latter has a REAL_TYPE
diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c
index 9ba54c199535141ebc4f7441954715379914a0c7..821279450fa7490f8b8b62e2a468d7fb78ca9f3b 100644
--- a/gcc/config/stormy16/stormy16.c
+++ b/gcc/config/stormy16/stormy16.c
@@ -1285,8 +1285,9 @@ xstormy16_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
   f_base = TYPE_FIELDS (va_list_type_node);
   f_count = TREE_CHAIN (f_base);
   
-  base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
-  count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
+  base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE);
+  count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count,
+		 NULL_TREE);
 
   t = make_tree (TREE_TYPE (base), virtual_incoming_args_rtx);
   t = build (PLUS_EXPR, TREE_TYPE (base), t, 
@@ -1320,8 +1321,9 @@ xstormy16_expand_builtin_va_arg (tree valist, tree type)
   f_base = TYPE_FIELDS (va_list_type_node);
   f_count = TREE_CHAIN (f_base);
   
-  base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base);
-  count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count);
+  base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE);
+  count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count,
+		 NULL_TREE);
 
   must_stack = MUST_PASS_IN_STACK (TYPE_MODE (type), type);
   size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index e062fd9c2224103f4d5e758c77d5dc4a31707c69..2d9ea5235b9a7adca35f71641edd489183a29fea 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -2430,9 +2430,9 @@ xtensa_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
   f_reg = TREE_CHAIN (f_stk);
   f_ndx = TREE_CHAIN (f_reg);
 
-  stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk);
-  reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg);
-  ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx);
+  stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk, NULL_TREE);
+  reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg, NULL_TREE);
+  ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx, NULL_TREE);
 
   /* Call __builtin_saveregs; save the result in __va_reg */
   u = make_tree (ptr_type_node, expand_builtin_saveregs ());
@@ -2494,9 +2494,9 @@ xtensa_va_arg (tree valist, tree type)
   f_reg = TREE_CHAIN (f_stk);
   f_ndx = TREE_CHAIN (f_reg);
 
-  stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk);
-  reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg);
-  ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx);
+  stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk, NULL_TREE);
+  reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg, NULL_TREE);
+  ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx, NULL_TREE);
 
   type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
 
diff --git a/gcc/coverage.c b/gcc/coverage.c
index 3eab7a5dd4652d7743edac8b82ec8d8d1b9d9b98..e39f0a66cc7f0d07d8f7e3165059cea9bcb7d613 100644
--- a/gcc/coverage.c
+++ b/gcc/coverage.c
@@ -428,16 +428,18 @@ rtl_coverage_counter_ref (unsigned counter, unsigned no)
 tree
 tree_coverage_counter_ref (unsigned counter, unsigned no)
 {
-  tree t;
+  tree domain_type = TYPE_DOMAIN (TREE_TYPE (tree_ctr_tables[counter]));
 
   if (no >= fn_n_ctrs[counter] - fn_b_ctrs[counter])
     abort ();
   no += prg_n_ctrs[counter] + fn_b_ctrs[counter];
 
   /* "no" here is an array index, scaled to bytes later.  */
-  t = build (ARRAY_REF, GCOV_TYPE_NODE, tree_ctr_tables[counter],
-	     build_int_2 (no, 0));
-  return t;
+  return build (ARRAY_REF, GCOV_TYPE_NODE, tree_ctr_tables[counter],
+		fold_convert (domain_type, build_int_2 (no, 0)),
+		TYPE_MIN_VALUE (domain_type),
+		size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (GCOV_TYPE_NODE),
+			    size_int (TYPE_ALIGN (GCOV_TYPE_NODE))));
 }
 
 /* Generate a checksum for a string.  CHKSUM is the current
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 029105711b4bd6e3722787f0f564630d10c932d3..d8b494bdff6887cd9f4da8f0c78231f1186773a1 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,29 @@
+2004-06-21  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
+
+	* call.c (build_vfield_ref): Add new operand for COMPONENT_REF.
+	(build_new_method_call): Likewise.
+	* decl.c (local_variable_p_walkfn): Don't walk into types.
+	* decl2.c (grok_array_decl): Add new operands for ARRAY_REF.
+	(build_anon_union_vars): Add new operand for COMPONENT_REF.
+	* init.c (buld_new): Add new operand for ARRAY_REF.
+	* method.c (do_build_copy_constructor): New op for COMPONENT_REF.
+	(do_build_assign_ref): Likewise.
+	* parser.c (cp_parser_direct_new_declarator): Add new operands
+	for ARRAY_REF.
+	(cp_parser_direct_declarator): Likewise.
+	* pt.c (tsubst): Likewise.
+	(tsubst_copy, tsubst_copy_and_build): Likewise; also add new operand
+ 	for COMPONENT_REF.
+	* semantics.c (finish_non_static_data_member): Add new operand
+	for COMPONENT_REF.
+	* typeck.c (build_class_member_access_expr): Likewise.
+	(build_class_member_access_expr, finish_class_member_access_expr):
+	Likewise.
+	(build_ptrmemfunc_access_expr): Likewise.
+	(build_array_ref): Add new operands for ARRAY_REF.
+	* typeck2.c (split_nonconstant_init_1): Likewise; COMPONENT_REF too.
+	* tree.c (count_trees_r, no_linkage_helper): Don't walk in types.
+
 2004-06-21  Richard Henderson  <rth@redhat.com>
 
 	* dump.c (cp_dump_tree): Don't use dump_next_stmt.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 616cf812f9211359dc7c0696c333506fe5a0286b..0c247b8127a435a313d711c6f2d401bbc52abbc0 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -203,7 +203,7 @@ build_vfield_ref (tree datum, tree type)
     datum = convert_to_base (datum, type, /*check_access=*/false);
 
   return build (COMPONENT_REF, TREE_TYPE (TYPE_VFIELD (type)),
-		datum, TYPE_VFIELD (type));
+		datum, TYPE_VFIELD (type), NULL_TREE);
 }
 
 /* Returns nonzero iff the destructor name specified in NAME
@@ -3868,8 +3868,7 @@ builtin:
       return build_conditional_expr (arg1, arg2, arg3);
 
     case MEMBER_REF:
-      return build_m_component_ref
-	(build_indirect_ref (arg1, NULL), arg2);
+      return build_m_component_ref (build_indirect_ref (arg1, NULL), arg2);
 
       /* The caller will deal with these.  */
     case ADDR_EXPR:
@@ -5360,7 +5359,7 @@ build_new_method_call (tree instance, tree fns, tree args,
   if (processing_template_decl && call != error_mark_node)
     call = (build_min_non_dep
 	    (CALL_EXPR, call,
-	     build_min_nt (COMPONENT_REF, orig_instance, orig_fns),
+	     build_min_nt (COMPONENT_REF, orig_instance, orig_fns, NULL_TREE),
 	     orig_args, NULL_TREE));
 
  /* Free all the conversions we allocated.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 84f3b8459af5c7e85ab4e6e2c28b3f53d6ec9a0c..55ce6841723c7cd0af8bade3869a99bc8d042c79 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8508,14 +8508,18 @@ nonstatic_local_decl_p (tree t)
    function.  */
 
 static tree
-local_variable_p_walkfn (tree* tp,
-                         int* walk_subtrees ATTRIBUTE_UNUSED ,
-                         void* data ATTRIBUTE_UNUSED )
+local_variable_p_walkfn (tree *tp, int *walk_subtrees,
+			 void *data ATTRIBUTE_UNUSED)
 {
-  return ((local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp))
-	  ? *tp : NULL_TREE);
+  if (local_variable_p (*tp) && !DECL_ARTIFICIAL (*tp))
+    return *tp;
+  else if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+
+  return NULL_TREE;
 }
 
+
 /* Check that ARG, which is a default-argument expression for a
    parameter DECL, is valid.  Returns ARG, or ERROR_MARK_NODE, if
    something goes wrong.  DECL may also be a _TYPE node, rather than a
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index eacab5f283b1e676b7608d9722707959e607b791..00105a6d2a6945153a804484be9b644eebdeaafe 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -369,7 +369,8 @@ grok_array_decl (tree array_expr, tree index_exp)
     {
       if (type_dependent_expression_p (array_expr)
 	  || type_dependent_expression_p (index_exp))
-	return build_min_nt (ARRAY_REF, array_expr, index_exp);
+	return build_min_nt (ARRAY_REF, array_expr, index_exp,
+			     NULL_TREE, NULL_TREE);
       array_expr = build_non_dependent_expr (array_expr);
       index_exp = build_non_dependent_expr (index_exp);
     }
@@ -426,8 +427,8 @@ grok_array_decl (tree array_expr, tree index_exp)
       expr = build_array_ref (array_expr, index_exp);
     }
   if (processing_template_decl && expr != error_mark_node)
-    return build_min_non_dep (ARRAY_REF, expr,
-			      orig_array_expr, orig_index_exp);
+    return build_min_non_dep (ARRAY_REF, expr, orig_array_expr, orig_index_exp,
+			      NULL_TREE, NULL_TREE);
   return expr;
 }
 
@@ -1175,7 +1176,8 @@ build_anon_union_vars (tree object)
 	cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
 
       if (processing_template_decl)
-	ref = build_min_nt (COMPONENT_REF, object, DECL_NAME (field));
+	ref = build_min_nt (COMPONENT_REF, object,
+			    DECL_NAME (field), NULL_TREE);
       else
 	ref = build_class_member_access_expr (object, field, NULL_TREE,
 					      false);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 6c886238ea59a7175161198842f5fa77136986e7..2af51185e7ba2d1f63e04a9661227938f273cfde 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1777,7 +1777,8 @@ build_new (tree placement, tree decl, tree init, int use_global_new)
     {
       if (has_array)
 	t = tree_cons (tree_cons (NULL_TREE, type, NULL_TREE),
-		       build_min_nt (ARRAY_REF, NULL_TREE, nelts),
+		       build_min_nt (ARRAY_REF, NULL_TREE, nelts,
+				     NULL_TREE, NULL_TREE),
 		       NULL_TREE);
       else
 	t = type;
@@ -1815,7 +1816,7 @@ build_new (tree placement, tree decl, tree init, int use_global_new)
     }
 
   if (has_array)
-    t = build_nt (ARRAY_REF, type, nelts);
+    t = build_nt (ARRAY_REF, type, nelts, NULL_TREE, NULL_TREE);
   else
     t = type;
 
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 357ea868ed327bc65892ed7942c17b570ff227e5..495244fa748fb9433a4f3995f278fc5ea422c7dd 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -591,7 +591,7 @@ do_build_copy_constructor (tree fndecl)
 	  expr_type = TREE_TYPE (field);
 	  if (TREE_CODE (expr_type) != REFERENCE_TYPE)
 	    expr_type = cp_build_qualified_type (expr_type, cvquals);
-	  init = build (COMPONENT_REF, expr_type, init, field);
+	  init = build (COMPONENT_REF, expr_type, init, field, NULL_TREE);
 	  init = build_tree_list (NULL_TREE, init);
 
 	  member_init_list
@@ -687,10 +687,11 @@ do_build_assign_ref (tree fndecl)
 	  else
 	    continue;
 
-	  comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field);
+	  comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field,
+			NULL_TREE);
 	  init = build (COMPONENT_REF,
 	                cp_build_qualified_type (TREE_TYPE (field), cvquals),
-	                init, field);
+	                init, field, NULL_TREE);
 
 	  if (DECL_NAME (field))
 	    finish_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bd6abe8393d1de1dfb67bc0274faaa9af49fb25f..5ad4250ee0a8e7ab874516bb67a8ed5ee547a5eb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -4767,7 +4767,8 @@ cp_parser_direct_new_declarator (cp_parser* parser)
       cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
 
       /* Add this bound to the declarator.  */
-      declarator = build_nt (ARRAY_REF, declarator, expression);
+      declarator = build_nt (ARRAY_REF, declarator, expression,
+			     NULL_TREE, NULL_TREE);
 
       /* If the next token is not a `[', then there are no more
 	 bounds.  */
@@ -10714,7 +10715,8 @@ cp_parser_direct_declarator (cp_parser* parser,
 	      break;
 	    }
 
-	  declarator = build_nt (ARRAY_REF, declarator, bounds);
+	  declarator = build_nt (ARRAY_REF, declarator, bounds,
+				 NULL_TREE, NULL_TREE);
 	}
       else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
 	{
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f8e259c6fbca64a180690f1f534abc3be2bf1a08..1e23acbcf079adb2ae5d4969c76c8c8cc78e4eb8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7201,7 +7201,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 	if (e1 == error_mark_node || e2 == error_mark_node)
 	  return error_mark_node;
 
-	return build_nt (ARRAY_REF, e1, e2);
+	return build_nt (ARRAY_REF, e1, e2, NULL_TREE, NULL_TREE);
       }
 
     case CALL_EXPR:
@@ -7563,7 +7563,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
 				  in_decl);
 	else
 	  name = tsubst_copy (name, args, complain, in_decl);
-	return build_nt (COMPONENT_REF, object, name);
+	return build_nt (COMPONENT_REF, object, name, NULL_TREE);
       }
 
     case PLUS_EXPR:
@@ -8143,7 +8143,7 @@ tsubst_copy_and_build (tree t,
 	
 	if (object)
 	  return build (COMPONENT_REF, TREE_TYPE (template), 
-			object, template);
+			object, template, NULL_TREE);
 	else
 	  return template;
       }
@@ -8255,7 +8255,8 @@ tsubst_copy_and_build (tree t,
       if (tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)
 	  == NULL_TREE)
 	/* new-type-id */
-	return build_nt (ARRAY_REF, NULL_TREE, RECUR (TREE_OPERAND (t, 1)));
+	return build_nt (ARRAY_REF, NULL_TREE, RECUR (TREE_OPERAND (t, 1)),
+			 NULL_TREE, NULL_TREE);
 
       op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
 						args, complain, in_decl);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0da94942c2e49677096ed6c00ae0c92a72bcf136..9e4b884c3b3b08942e1659cb1df51097db9e7a25 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1233,7 +1233,7 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
 	  type = cp_build_qualified_type (type, quals);
 	}
       
-      return build_min (COMPONENT_REF, type, object, decl);
+      return build_min (COMPONENT_REF, type, object, decl, NULL_TREE);
     }
   else
     {
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 6b558800e682023a5743a7e08fbbfa1a1c25b97e..527e9c27d50cd0f2c82965cdb5230d8d5eba4c27 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1026,11 +1026,13 @@ bind_template_template_parm (tree t, tree newargs)
 /* Called from count_trees via walk_tree.  */
 
 static tree
-count_trees_r (tree* tp ATTRIBUTE_UNUSED , 
-               int* walk_subtrees ATTRIBUTE_UNUSED , 
-               void* data)
+count_trees_r (tree *tp, int *walk_subtrees, void *data)
 {
-  ++ *((int*) data);
+  ++*((int *) data);
+
+  if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+
   return NULL_TREE;
 }
 
@@ -1107,9 +1109,8 @@ find_tree (tree t, tree x)
 /* Passed to walk_tree.  Checks for the use of types with no linkage.  */
 
 static tree
-no_linkage_helper (tree* tp, 
-                   int* walk_subtrees ATTRIBUTE_UNUSED , 
-                   void* data ATTRIBUTE_UNUSED )
+no_linkage_helper (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+		   void *data ATTRIBUTE_UNUSED)
 {
   tree t = *tp;
 
@@ -1118,6 +1119,7 @@ no_linkage_helper (tree* tp,
       && (decl_function_context (TYPE_MAIN_DECL (t))
 	  || TYPE_ANONYMOUS_P (t)))
     return t;
+
   return NULL_TREE;
 }
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index bdf7377d0e060c6c4081186e64cb8939883fe4d4..880000783cf3e15dd1fe35ad2aeb821b2ddff004 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1752,7 +1752,8 @@ build_class_member_access_expr (tree object, tree member,
 	  member_type = cp_build_qualified_type (member_type, type_quals);
 	}
 
-      result = fold (build (COMPONENT_REF, member_type, object, member));
+      result = fold (build (COMPONENT_REF, member_type, object, member,
+			    NULL_TREE));
 
       /* Mark the expression const or volatile, as appropriate.  Even
 	 though we've dealt with the type above, we still have to mark the
@@ -1779,7 +1780,7 @@ build_class_member_access_expr (tree object, tree member,
 	type = unknown_type_node;
       /* Note that we do not convert OBJECT to the BASELINK_BINFO
 	 base.  That will happen when the function is called.  */
-      result = build (COMPONENT_REF, type, object, member);
+      result = build (COMPONENT_REF, type, object, member, NULL_TREE);
     }
   else if (TREE_CODE (member) == CONST_DECL)
     {
@@ -1878,7 +1879,7 @@ finish_class_member_access_expr (tree object, tree name)
 	  || (TREE_CODE (name) == SCOPE_REF
 	      && TYPE_P (TREE_OPERAND (name, 0))
 	      && dependent_type_p (TREE_OPERAND (name, 0))))
-	return build_min_nt (COMPONENT_REF, object, name);
+	return build_min_nt (COMPONENT_REF, object, name, NULL_TREE);
       object = build_non_dependent_expr (object);
     }
   
@@ -2005,7 +2006,7 @@ finish_class_member_access_expr (tree object, tree name)
 					 /*preserve_reference=*/false);
   if (processing_template_decl && expr != error_mark_node)
     return build_min_non_dep (COMPONENT_REF, expr,
-			      orig_object, orig_name);
+			      orig_object, orig_name, NULL_TREE);
   return expr;
 }
 
@@ -2033,7 +2034,7 @@ build_ptrmemfunc_access_expr (tree ptrmem, tree member_name)
 			  /*want_type=*/false);
   member_type = cp_build_qualified_type (TREE_TYPE (member),
 					 cp_type_quals (ptrmem_type));
-  return fold (build (COMPONENT_REF, member_type, ptrmem, member));
+  return fold (build (COMPONENT_REF, member_type, ptrmem, member, NULL_TREE));
 }
 
 /* Given an expression PTR for a pointer, return an expression
@@ -2249,7 +2250,7 @@ build_array_ref (tree array, tree idx)
 	}
 
       type = TREE_TYPE (TREE_TYPE (array));
-      rval = build (ARRAY_REF, type, array, idx);
+      rval = build (ARRAY_REF, type, array, idx, NULL_TREE, NULL_TREE);
       /* Array ref is const/volatile if the array elements are
 	 or if the array is..  */
       TREE_READONLY (rval)
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 9ea4f55d5fbee881a4bb3c96342baae9d1bacd67..2e08d563079bfce1f05425219d21b219d4c0cb10 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -320,9 +320,11 @@ split_nonconstant_init_1 (tree dest, tree init)
 	  if (TREE_CODE (value) == CONSTRUCTOR)
 	    {
 	      if (array_type_p)
-	        sub = build (ARRAY_REF, inner_type, dest, field_index);
+	        sub = build (ARRAY_REF, inner_type, dest, field_index,
+			     NULL_TREE, NULL_TREE);
 	      else
-	        sub = build (COMPONENT_REF, inner_type, dest, field_index);
+	        sub = build (COMPONENT_REF, inner_type, dest, field_index,
+			     NULL_TREE);
 
 	      split_nonconstant_init_1 (sub, value);
 	    }
@@ -331,9 +333,11 @@ split_nonconstant_init_1 (tree dest, tree init)
 	      *pelt = TREE_CHAIN (elt);
 
 	      if (array_type_p)
-	        sub = build (ARRAY_REF, inner_type, dest, field_index);
+	        sub = build (ARRAY_REF, inner_type, dest, field_index,
+			     NULL_TREE, NULL_TREE);
 	      else
-	        sub = build (COMPONENT_REF, inner_type, dest, field_index);
+	        sub = build (COMPONENT_REF, inner_type, dest, field_index,
+			     NULL_TREE);
 
 	      code = build (MODIFY_EXPR, inner_type, sub, value);
 	      code = build_stmt (EXPR_STMT, code);
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 41679151c641f20b18e12f67a80007497b4ba9a7..984f81ffd6acb5dacca9c5641b22a89a6673a08f 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -1460,8 +1460,8 @@ component_ref_for_mem_expr (tree ref)
   if (inner == TREE_OPERAND (ref, 0))
     return ref;
   else
-    return build (COMPONENT_REF, TREE_TYPE (ref), inner,
-		  TREE_OPERAND (ref, 1));
+    return build (COMPONENT_REF, TREE_TYPE (ref), inner, TREE_OPERAND (ref, 1),
+		  NULL_TREE);
 }
 
 /* Returns 1 if both MEM_EXPR can be considered equal
@@ -1625,28 +1625,22 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp,
 	  do
 	    {
 	      tree index = TREE_OPERAND (t2, 1);
-	      tree array = TREE_OPERAND (t2, 0);
-	      tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-	      tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
-	      tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+	      tree low_bound = array_ref_low_bound (t2);
+	      tree unit_size = array_ref_element_size (t2);
 
 	      /* We assume all arrays have sizes that are a multiple of a byte.
 		 First subtract the lower bound, if any, in the type of the
-		 index, then convert to sizetype and multiply by the size of the
-		 array element.  */
-	      if (low_bound != 0 && ! integer_zerop (low_bound))
+		 index, then convert to sizetype and multiply by the size of
+		 the array element.  */
+	      if (! integer_zerop (low_bound))
 		index = fold (build (MINUS_EXPR, TREE_TYPE (index),
 				     index, low_bound));
 
-	      /* If the index has a self-referential type, instantiate it;
-		 likewise for the component size.  */
-	      index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, t2);
-	      unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array);
-	      off_tree
-		= fold (build (PLUS_EXPR, sizetype,
-			       fold (build (MULT_EXPR, sizetype,
-					    index, unit_size)),
-			       off_tree));
+	      off_tree = size_binop (PLUS_EXPR,
+				     size_binop (MULT_EXPR, convert (sizetype,
+								     index),
+						 unit_size),
+				     off_tree);
 	      t2 = TREE_OPERAND (t2, 0);
 	    }
 	  while (TREE_CODE (t2) == ARRAY_REF);
@@ -2042,6 +2036,7 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
       if (TREE_CODE (expr) == COMPONENT_REF)
 	{
 	  tree field = TREE_OPERAND (expr, 1);
+	  tree offset = component_ref_field_offset (expr);
 
 	  if (! DECL_SIZE_UNIT (field))
 	    {
@@ -2056,17 +2051,18 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset)
 	      && INTVAL (memoffset) >= 0)
 	    break;
 
-	  if (! host_integerp (DECL_FIELD_OFFSET (field), 1))
+	  if (! host_integerp (offset, 1))
 	    {
 	      expr = NULL_TREE;
 	      break;
 	    }
 
 	  expr = TREE_OPERAND (expr, 0);
-	  memoffset = (GEN_INT (INTVAL (memoffset)
-		       + tree_low_cst (DECL_FIELD_OFFSET (field), 1)
-		       + (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
-		          / BITS_PER_UNIT)));
+	  memoffset
+	    = (GEN_INT (INTVAL (memoffset)
+			+ tree_low_cst (offset, 1)
+			+ (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+			   / BITS_PER_UNIT)));
 	}
       /* Similarly for the decl.  */
       else if (DECL_P (expr)
diff --git a/gcc/explow.c b/gcc/explow.c
index af67003eacfb0b3d2cd64ae868116d4e56294d24..672d3f6525a3ecdcf04a8611f63905a7a49a434e 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -1100,7 +1100,7 @@ update_nonlocal_goto_save_area (void)
      STACK_SAVEAREA_MODE.  Create a reference to array index 1, the first
      of the stack save area slots.  */
   t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
-		  integer_one_node);
+		  integer_one_node, NULL_TREE, NULL_TREE);
   r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
   emit_stack_save (SAVE_NONLOCAL, &r_save, NULL_RTX);
diff --git a/gcc/expr.c b/gcc/expr.c
index aad7b1cb5ae019bdfb404c79d04b4dfeab52213e..989a5fa6dca55a15b5489b77a4a20ce571a4f227 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -5591,15 +5591,13 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
       else if (TREE_CODE (exp) == COMPONENT_REF)
 	{
 	  tree field = TREE_OPERAND (exp, 1);
-	  tree this_offset = DECL_FIELD_OFFSET (field);
+	  tree this_offset = component_ref_field_offset (exp);
 
 	  /* If this field hasn't been filled in yet, don't go
 	     past it.  This should only happen when folding expressions
 	     made during type construction.  */
 	  if (this_offset == 0)
 	    break;
-	  else
-	    this_offset = SUBSTITUTE_PLACEHOLDER_IN_EXPR (this_offset, exp);
 
 	  offset = size_binop (PLUS_EXPR, offset, this_offset);
 	  bit_offset = size_binop (PLUS_EXPR, bit_offset,
@@ -5612,23 +5610,17 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
 	       || TREE_CODE (exp) == ARRAY_RANGE_REF)
 	{
 	  tree index = TREE_OPERAND (exp, 1);
-	  tree array = TREE_OPERAND (exp, 0);
-	  tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-	  tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0);
-	  tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
+	  tree low_bound = array_ref_low_bound (exp);
+	  tree unit_size = array_ref_element_size (exp);
 
 	  /* We assume all arrays have sizes that are a multiple of a byte.
 	     First subtract the lower bound, if any, in the type of the
 	     index, then convert to sizetype and multiply by the size of the
 	     array element.  */
-	  if (low_bound != 0 && ! integer_zerop (low_bound))
+	  if (! integer_zerop (low_bound))
 	    index = fold (build (MINUS_EXPR, TREE_TYPE (index),
 				 index, low_bound));
 
-	  /* If the index has a self-referential type, instantiate it with
-	     the object; likewise for the component size.  */
-	  index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, exp);
-	  unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array);
 	  offset = size_binop (PLUS_EXPR, offset,
 			       size_binop (MULT_EXPR,
 					   convert (sizetype, index),
@@ -5676,6 +5668,70 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   return exp;
 }
 
+/* Return a tree of sizetype representing the size, in bytes, of the element
+   of EXP, an ARRAY_REF.  */
+
+tree
+array_ref_element_size (tree exp)
+{
+  tree aligned_size = TREE_OPERAND (exp, 3);
+  tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+  /* If a size was specified in the ARRAY_REF, it's the size measured
+     in alignment units of the element type.  So multiply by that value.  */
+  if (aligned_size)
+    return size_binop (MULT_EXPR, aligned_size,
+		       size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT));
+
+  /* Otherwise, take the size from that of the element type.  Substitute 
+     any PLACEHOLDER_EXPR that we have.  */
+  else
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elmt_type), exp);
+}
+
+/* Return a tree representing the lower bound of the array mentioned in
+   EXP, an ARRAY_REF.  */
+
+tree
+array_ref_low_bound (tree exp)
+{
+  tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+
+  /* If a lower bound is specified in EXP, use it.  */
+  if (TREE_OPERAND (exp, 2))
+    return TREE_OPERAND (exp, 2);
+
+  /* Otherwise, if there is a domain type and it has a lower bound, use it,
+     substituting for a PLACEHOLDER_EXPR as needed.  */
+  if (domain_type && TYPE_MIN_VALUE (domain_type))
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), exp);
+
+  /* Otherwise, return a zero of the appropriate type.  */
+  return fold_convert (TREE_TYPE (TREE_OPERAND (exp, 1)), integer_zero_node);
+}
+
+/* Return a tree representing the offset, in bytes, of the field referenced
+   by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
+
+tree
+component_ref_field_offset (tree exp)
+{
+  tree aligned_offset = TREE_OPERAND (exp, 2);
+  tree field = TREE_OPERAND (exp, 1);
+
+  /* If an offset was specified in the COMPONENT_REF, it's the offset measured
+     in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT.  So multiply by that
+     value.  */
+  if (aligned_offset)
+    return size_binop (MULT_EXPR, aligned_offset,
+		       size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT));
+
+  /* Otherwise, take the offset from that of the field.  Substitute 
+     any PLACEHOLDER_EXPR that we have.  */
+  else
+    return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
+}
+
 /* Return 1 if T is an expression that get_inner_reference handles.  */
 
 int
@@ -7001,8 +7057,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       {
 	tree array = TREE_OPERAND (exp, 0);
-	tree domain = TYPE_DOMAIN (TREE_TYPE (array));
-	tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+	tree low_bound = array_ref_low_bound (exp);
 	tree index = convert (sizetype, TREE_OPERAND (exp, 1));
 	HOST_WIDE_INT i;
 
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 68c9722ea183640f3fa5e4e9d496e9cc15088a28..3d4cccaaa6b7426aeb934d080dc368090b9b0ec8 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2019,9 +2019,9 @@ non_lvalue (tree x)
   case COMPONENT_REF:
   case INDIRECT_REF:
   case ARRAY_REF:
+  case ARRAY_RANGE_REF:
   case BIT_FIELD_REF:
   case BUFFER_REF:
-  case ARRAY_RANGE_REF:
   case VTABLE_REF:
 
   case REALPART_EXPR:
@@ -7901,24 +7901,26 @@ fold (tree expr)
 	  /* If VAROP is a reference to a bitfield, we must mask
 	     the constant by the width of the field.  */
 	  if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
-	      && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1)))
+	      && DECL_BIT_FIELD (TREE_OPERAND (TREE_OPERAND (varop, 0), 1))
+	      && host_integerp (DECL_SIZE (TREE_OPERAND
+					   (TREE_OPERAND (varop, 0), 1)), 1))
 	    {
 	      tree fielddecl = TREE_OPERAND (TREE_OPERAND (varop, 0), 1);
-	      int size = TREE_INT_CST_LOW (DECL_SIZE (fielddecl));
+	      HOST_WIDE_INT size = tree_low_cst (DECL_SIZE (fielddecl), 1);
 	      tree folded_compare, shift;
 
 	      /* First check whether the comparison would come out
 		 always the same.  If we don't do that we would
 		 change the meaning with the masking.  */
 	      folded_compare = fold (build2 (code, type,
-					     TREE_OPERAND (varop, 0),
-					     arg1));
+					     TREE_OPERAND (varop, 0), arg1));
 	      if (integer_zerop (folded_compare)
 		  || integer_onep (folded_compare))
 		return omit_one_operand (type, folded_compare, varop);
 
 	      shift = build_int_2 (TYPE_PRECISION (TREE_TYPE (varop)) - size,
 				   0);
+	      shift = fold_convert (TREE_TYPE (varop), shift);
 	      newconst = fold (build2 (LSHIFT_EXPR, TREE_TYPE (varop),
 				       newconst, shift));
 	      newconst = fold (build2 (RSHIFT_EXPR, TREE_TYPE (varop),
@@ -10106,13 +10108,10 @@ fold_read_from_constant_string (tree exp)
       tree string;
 
       if (TREE_CODE (exp) == INDIRECT_REF)
-	{
-	  string = string_constant (exp1, &index);
-	}
+	string = string_constant (exp1, &index);
       else
 	{
-	  tree domain = TYPE_DOMAIN (TREE_TYPE (exp1));
-	  tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
+	  tree low_bound = array_ref_low_bound (exp);
 	  index = fold_convert (sizetype, TREE_OPERAND (exp, 1));
 	  
 	  /* Optimize the special-case of a zero lower bound.
@@ -10129,6 +10128,7 @@ fold_read_from_constant_string (tree exp)
 	}
 
       if (string
+	  && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (string))
 	  && TREE_CODE (string) == STRING_CST
 	  && TREE_CODE (index) == INTEGER_CST
 	  && compare_tree_int (index, TREE_STRING_LENGTH (string)) < 0
@@ -10456,7 +10456,7 @@ build_fold_indirect_ref (tree t)
       /* *(foo *)&fooarray => fooarray[0] */
       else if (TREE_CODE (optype) == ARRAY_TYPE
 	       && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
-	return build2 (ARRAY_REF, type, op, size_zero_node);
+	return build4 (ARRAY_REF, type, op, size_zero_node, NULL_TREE, NULL_TREE);
     }
 
   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
@@ -10465,7 +10465,7 @@ build_fold_indirect_ref (tree t)
       && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
     {
       sub = build_fold_indirect_ref (sub);
-      return build2 (ARRAY_REF, type, sub, size_zero_node);
+      return build4 (ARRAY_REF, type, sub, size_zero_node, NULL_TREE, NULL_TREE);
     }
 
   return build1 (INDIRECT_REF, type, t);
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 01147289fb47cfaf8cfb759f609d60758f660587..a2bb02c019c59c4919654df9339f407970bcfde7 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,22 @@
+2004-06-21  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
+
+	* f95-lang.c (LANG_HOOKS_GIMPLE_BEFORE_INLINING): Deleted.
+	* trans-array.c (gfc_conv_descriptor_data): Add operand
+	for COMPONENT_REF.
+	(gfc_conv_descriptor_offset, gfc_conv_descriptor_dtype): Likewise.
+	(gfc_conv_descriptor_dimension, gfc_conv_descriptor_stride): Likewise.
+	(gfc_conv_descriptor_lbound, gfc_conv_descriptor_ubound): Likewise.
+	* trans-common.c (create_common): Likewise.
+	* trans-expr.c (gfc_conv_component_ref): Likewise.
+	* trans-io.c (set_parameter_value): Likewise.
+	(set_parameter_ref, set_string, set_flag, io_result): Likewise.
+	(transfer_expr): Likewise.
+	* trans-decl.c (gfc_trans_auto_character_variable):
+	Set up to get DECL_SIZE and DECL_SIZE_UNIT gimplified.
+	(gfc_simplify_function): New function.
+	(gfc_generate_function-code): Properly handle nested functions.
+	* trans.c (gfc_build_array_ref): Add two new operands for ARRAY_REF.
+
 2004-06-22  Janne Blomqvist  <jblomqvi@cc.hut.fi>
 
 	PR fortran/15750
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index ab151fcd7373337015967b3833e1c46ae050acd5..fd4fe5c2616d6873acf11f7447809ed82a543caa 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -122,7 +122,6 @@ static void gfc_expand_function (tree);
 #undef LANG_HOOKS_UNSIGNED_TYPE
 #undef LANG_HOOKS_SIGNED_TYPE
 #undef LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE
-#undef LANG_HOOKS_GIMPLE_BEFORE_INLINING
 #undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
 
 /* Define lang hooks.  */
@@ -141,7 +140,6 @@ static void gfc_expand_function (tree);
 #define LANG_HOOKS_UNSIGNED_TYPE           gfc_unsigned_type
 #define LANG_HOOKS_SIGNED_TYPE             gfc_signed_type
 #define LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE gfc_signed_or_unsigned_type
-#define LANG_HOOKS_GIMPLE_BEFORE_INLINING false
 #define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION gfc_expand_function
 
 const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index e83a45d030f4374e0c90f1282b18447962b465e1..bccaf414895808f6180bdf80c84c10c79ead8e58 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -189,7 +189,7 @@ gfc_conv_descriptor_data (tree desc)
 	  && TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE
 	  && TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == ARRAY_TYPE);
 
-  return build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+  return build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
 }
 
 tree
@@ -204,7 +204,7 @@ gfc_conv_descriptor_offset (tree desc)
   field = gfc_advance_chain (TYPE_FIELDS (type), OFFSET_FIELD);
   assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
 
-  return build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+  return build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
 }
 
 tree
@@ -219,7 +219,7 @@ gfc_conv_descriptor_dtype (tree desc)
   field = gfc_advance_chain (TYPE_FIELDS (type), DTYPE_FIELD);
   assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
 
-  return build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+  return build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
 }
 
 static tree
@@ -237,7 +237,7 @@ gfc_conv_descriptor_dimension (tree desc, tree dim)
 	  && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
 	  && TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == RECORD_TYPE);
 
-  tmp = build (COMPONENT_REF, TREE_TYPE (field), desc, field);
+  tmp = build (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
   tmp = gfc_build_array_ref (tmp, dim);
   return tmp;
 }
@@ -253,7 +253,7 @@ gfc_conv_descriptor_stride (tree desc, tree dim)
   field = gfc_advance_chain (field, STRIDE_SUBFIELD);
   assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
 
-  tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field);
+  tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field, NULL_TREE);
   return tmp;
 }
 
@@ -268,7 +268,7 @@ gfc_conv_descriptor_lbound (tree desc, tree dim)
   field = gfc_advance_chain (field, LBOUND_SUBFIELD);
   assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
 
-  tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field);
+  tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field, NULL_TREE);
   return tmp;
 }
 
@@ -283,7 +283,7 @@ gfc_conv_descriptor_ubound (tree desc, tree dim)
   field = gfc_advance_chain (field, UBOUND_SUBFIELD);
   assert (field != NULL_TREE && TREE_TYPE (field) == gfc_array_index_type);
 
-  tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field);
+  tmp = build (COMPONENT_REF, TREE_TYPE (field), tmp, field, NULL_TREE);
   return tmp;
 }
 
diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c
index 667038d5cc45202cc3309c46ee35b52fbbcfc32a..f0c385adfbb94979536f63e9a9e236a35b7199e7 100644
--- a/gcc/fortran/trans-common.c
+++ b/gcc/fortran/trans-common.c
@@ -425,7 +425,7 @@ create_common (gfc_symbol *sym)
   for (h = current_common; h; h = next_s)
     {
       h->sym->backend_decl = build (COMPONENT_REF, TREE_TYPE (h->field),
-                                    decl, h->field);
+                                    decl, h->field, NULL_TREE);
 
       next_s = h->next;
       gfc_free (h);
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index ecabfc4d5507ac0cc2674fb2dda16b85e1d2a873..8cf6cbb185de95d14fed6d28b394fb7d06bab70b 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -1645,6 +1645,14 @@ gfc_trans_auto_character_variable (gfc_symbol * sym, tree fnbody)
 
   DECL_DEFER_OUTPUT (decl) = 1;
 
+  /* Since we don't use a DECL_STMT or equivalent, we have to deal
+     with getting these gimplified.  But we can't gimplify it yet since
+     we're still generating statements.
+
+     ??? This should be cleaned up and handled like other front ends.  */
+  gfc_add_expr_to_block (&body, save_expr (DECL_SIZE (decl)));
+  gfc_add_expr_to_block (&body, save_expr (DECL_SIZE_UNIT (decl)));
+
   /* Generate code to allocate the automatic variable.  It will be freed
      automatically.  */
   tmp = gfc_build_addr_expr (NULL, decl);
@@ -1949,6 +1957,24 @@ gfc_finalize (tree decl)
   cgraph_finalize_function (decl, false);
 }
 
+/* Convert FNDECL's code to GIMPLE and handle any nested functions.  */
+
+static void
+gfc_gimplify_function (tree fndecl)
+{
+  struct cgraph_node *cgn;
+
+  gimplify_function_tree (fndecl);
+  dump_function (TDI_generic, fndecl);
+
+  /* Convert all nested functions to GIMPLE now.  We do things in this order
+     so that items like VLA sizes are expanded properly in the context of the
+     correct function.  */
+  cgn = cgraph_node (fndecl);
+  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+    gfc_gimplify_function (cgn->decl);
+}
+
 /* Generate code for a function.  */
 
 void
@@ -2120,26 +2146,17 @@ gfc_generate_function_code (gfc_namespace * ns)
   current_function_decl = old_context;
 
   if (decl_function_context (fndecl))
-    {
-      /* Register this function with cgraph just far enough to get it
-	 added to our parent's nested function list.  */
-      (void) cgraph_node (fndecl);
-
-      /* Lowering nested functions requires gimple input.  */
-      gimplify_function_tree (fndecl);
-    }
+    /* Register this function with cgraph just far enough to get it
+       added to our parent's nested function list.  */
+    (void) cgraph_node (fndecl);
   else
     {
-      if (cgraph_node (fndecl)->nested)
-	{
-	  gimplify_function_tree (fndecl);
-          lower_nested_functions (fndecl);
-	}
+      gfc_gimplify_function (fndecl);
+      lower_nested_functions (fndecl);
       gfc_finalize (fndecl);
     }
 }
 
-
 void
 gfc_generate_constructors (void)
 {
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index e4953f6f080548dfd5093baf25e3fb2beec90a99..717a5d83bb3e73c4cf45b5ef52157433a356fedb 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -221,7 +221,7 @@ gfc_conv_component_ref (gfc_se * se, gfc_ref * ref)
   field = c->backend_decl;
   assert (TREE_CODE (field) == FIELD_DECL);
   decl = se->expr;
-  tmp = build (COMPONENT_REF, TREE_TYPE (field), decl, field);
+  tmp = build (COMPONENT_REF, TREE_TYPE (field), decl, field, NULL_TREE);
 
   se->expr = tmp;
 
diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c
index 3f4076fc557b34d9948ffcd9501e66ad1e04aa4a..f3aa37d28d8634964c198a82a0a4a8d1a9482834 100644
--- a/gcc/fortran/trans-io.c
+++ b/gcc/fortran/trans-io.c
@@ -359,7 +359,7 @@ set_parameter_value (stmtblock_t * block, tree var, gfc_expr * e)
   gfc_conv_expr_type (&se, e, TREE_TYPE (var));
   gfc_add_block_to_block (block, &se.pre);
 
-  tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var);
+  tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var, NULL_TREE);
   gfc_add_modify_expr (block, tmp, se.expr);
 }
 
@@ -379,7 +379,7 @@ set_parameter_ref (stmtblock_t * block, tree var, gfc_expr * e)
   gfc_conv_expr_type (&se, e, TREE_TYPE (var));
   gfc_add_block_to_block (block, &se.pre);
 
-  tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var);
+  tmp = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var, NULL_TREE);
   gfc_add_modify_expr (block, tmp, se.expr);
 }
 
@@ -400,8 +400,9 @@ set_string (stmtblock_t * block, stmtblock_t * postblock, tree var,
   gfc_init_se (&se, NULL);
   gfc_conv_expr (&se, e);
 
-  io = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var);
-  len = build (COMPONENT_REF, TREE_TYPE (var_len), ioparm_var, var_len);
+  io = build (COMPONENT_REF, TREE_TYPE (var), ioparm_var, var, NULL_TREE);
+  len = build (COMPONENT_REF, TREE_TYPE (var_len), ioparm_var, var_len,
+	       NULL_TREE);
 
   /*  Integer variable assigned a format label.  */
   if (e->ts.type == BT_INTEGER && e->symtree->n.sym->attr.assign == 1)
@@ -433,7 +434,7 @@ set_flag (stmtblock_t *block, tree var)
 {
   tree tmp;
 
-  tmp = build (COMPONENT_REF, TREE_TYPE(var), ioparm_var, var);
+  tmp = build (COMPONENT_REF, TREE_TYPE(var), ioparm_var, var, NULL_TREE);
   gfc_add_modify_expr (block, tmp, integer_one_node);
 }
 
@@ -496,7 +497,7 @@ io_result (stmtblock_t * block, gfc_st_label * err_label,
   tmp = gfc_finish_block (&body);
 
   rc = build (COMPONENT_REF, TREE_TYPE (ioparm_library_return), ioparm_var,
-	      ioparm_library_return);
+	      ioparm_library_return, NULL_TREE);
 
   tmp = build_v (SWITCH_EXPR, rc, tmp, NULL_TREE);
 
@@ -1127,7 +1128,8 @@ transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr)
 	  field = c->backend_decl;
 	  assert (field && TREE_CODE (field) == FIELD_DECL);
 
-	  tmp = build (COMPONENT_REF, TREE_TYPE (field), expr, field);
+	  tmp = build (COMPONENT_REF, TREE_TYPE (field), expr, field,
+		       NULL_TREE);
 
 	  if (c->ts.type == BT_CHARACTER)
 	    {
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index bb994a7f6dae0fb5717848f4c3d341eff4d1352b..29277282b5e89463ca6f823359b940086062c48d 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -306,7 +306,7 @@ gfc_build_array_ref (tree base, tree offset)
   if (DECL_P (base))
     TREE_ADDRESSABLE (base) = 1;
 
-  return build (ARRAY_REF, type, base, offset);
+  return build (ARRAY_REF, type, base, offset, NULL_TREE, NULL_TREE);
 }
 
 
diff --git a/gcc/function.c b/gcc/function.c
index 3f1f45bbcaa243ac28ce63e5d16ef673376c2d04..8fd0a6f35abe4f8b4a0b602490b640a5212471b1 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -6544,7 +6544,7 @@ expand_function_start (tree subr, int parms_have_cleanups)
       expand_var (TREE_OPERAND (cfun->nonlocal_goto_save_area, 0));
 
       t_save = build (ARRAY_REF, ptr_type_node, cfun->nonlocal_goto_save_area,
-		      integer_zero_node);
+		      integer_zero_node, NULL_TREE, NULL_TREE);
       r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
 
       emit_move_insn (r_save, virtual_stack_vars_rtx);
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 98346cc2bf23b7358ccbad733e5f04073e5260e4..32e5ceec5f489dd06355c5cf5449b1074a67ead4 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -476,8 +476,6 @@ expand_var_p (tree var)
   if (TREE_CODE (var) != VAR_DECL)
     return true;
 
-  ann = var_ann (var);
-
   /* Remove all unused, unaliased temporaries.  Also remove unused, unaliased
      local variables during highly optimizing compilations.  */
   ann = var_ann (var);
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index f6e4a04bf9bfe67bc6ef1481b47c0c2627ec475e..36492720ff96d83f9096e9a4b787104aa8370717 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1,6 +1,5 @@
 /* Tree lowering pass.  This pass converts the GENERIC functions-as-trees
    tree representation into the GIMPLE form.
-
    Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
    Major work done by Sebastian Pop <s.pop@laposte.net>,
    Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
@@ -36,6 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "langhooks.h"
 #include "langhooks-def.h"
 #include "tree-flow.h"
+#include "cgraph.h"
 #include "timevar.h"
 #include "except.h"
 #include "hashtab.h"
@@ -71,6 +71,73 @@ typedef struct gimple_temp_hash_elt
   tree temp;  /* Value */
 } elt_t;
 
+/* Forward declarations.  */
+static hashval_t gimple_tree_hash (const void *);
+static int gimple_tree_eq (const void *, const void *);
+static bool gimple_conditional_context (void);
+static void gimple_push_condition (void);
+static void gimple_pop_condition (tree *);
+static void append_to_statement_list_1 (tree, tree *, bool);
+static inline void remove_suffix (char *, int);
+static inline tree create_tmp_from_val (tree);
+static tree lookup_tmp_var (tree, bool);
+static tree internal_get_tmp_var (tree, tree *, tree *, bool);
+static bool should_carry_locus_p (tree);
+static tree mostly_copy_tree_r (tree *, int *, void *);
+static tree mark_decls_volatile_r (tree *, int *, void *);
+static tree copy_if_shared_r (tree *, int *, void *);
+static tree unmark_visited_r (tree *, int *, void *);
+static void unshare_body (tree *, tree);
+static void unvisit_body (tree *, tree);
+static void build_stack_save_restore (tree *, tree *);
+static enum gimplify_status gimplify_bind_expr (tree *, tree, tree *);
+static enum gimplify_status gimplify_return_expr (tree, tree *);
+static enum gimplify_status gimplify_loop_expr (tree *, tree *);
+static int compare_case_labels (const void *, const void *);
+static enum gimplify_status gimplify_switch_expr (tree *, tree *);
+static enum gimplify_status gimplify_case_label_expr (tree *);
+static enum gimplify_status gimplify_labeled_block_expr (tree *);
+static enum gimplify_status gimplify_exit_block_expr (tree *);
+static enum gimplify_status gimplify_exit_expr (tree *);
+static enum gimplify_status gimplify_init_constructor (tree *, tree *, tree *,
+						       bool);
+static void canonicalize_component_ref (tree *);
+static void canonicalize_addr_expr (tree *);
+static enum gimplify_status gimplify_conversion (tree *);
+static enum gimplify_status gimplify_minimax_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_array_ref_to_plus (tree *, tree *,
+							tree *);
+static tree build_addr_expr_with_type (tree, tree);
+static tree build_addr_expr (tree);
+static enum gimplify_status gimplify_compound_lval (tree *, tree *, tree *,
+						    bool);
+static enum gimplify_status gimplify_self_mod_expr (tree *, tree *, tree *,
+						    bool);
+static enum gimplify_status gimplify_call_expr (tree *, tree *,
+						bool (*) (tree));
+static tree shortcut_cond_r (tree, tree *, tree *);
+static tree shortcut_cond_expr (tree);
+static tree gimple_boolify (tree);
+static enum gimplify_status gimplify_cond_expr (tree *, tree *, tree);
+static enum gimplify_status gimplify_modify_expr (tree *, tree *, tree *,
+						  bool);
+static enum gimplify_status gimplify_modify_expr_rhs (tree *, tree *, tree *,
+						      tree *, tree *, bool);
+static enum gimplify_status gimplify_variable_sized_compare (tree *);
+static enum gimplify_status gimplify_boolean_expr (tree *);
+static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
+static enum gimplify_status gimplify_statement_list (tree *);
+static enum gimplify_status gimplify_save_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_addr_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_asm_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_cleanup_point_expr (tree *, tree *);
+static void gimple_push_cleanup (tree, tree, tree *);
+static enum gimplify_status gimplify_target_expr (tree *, tree *, tree *);
+#ifdef ENABLE_CHECKING
+static bool cpt_same_type (tree, tree);
+static tree check_pointer_types_r (tree *, int *, void *);
+#endif
+
 /* Return a hash value for a formal temporary table entry.  */
 
 static hashval_t
@@ -355,15 +422,11 @@ create_tmp_var (tree type, const char *prefix)
   tree tmp_var;
 
 #if defined ENABLE_CHECKING
-  /* If the type is an array or a type which must be created by the
-     frontend, something is wrong.  */
-  if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type))
-    abort ();
-  if (!COMPLETE_TYPE_P (type))
-    abort ();
-  /* Variable sized types require lots of machinery to create; the
-     optimizers shouldn't be doing anything of the sort.  */
-  if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
+  /* We don't allow types that are addressable (meaning we can't make copies),
+     incomplete, or of variable size.  */
+  if (TREE_ADDRESSABLE (type)
+      || !COMPLETE_TYPE_P (type)
+      || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
     abort ();
 #endif
 
@@ -653,11 +716,19 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
   tree t = *tp;
   enum tree_code code = TREE_CODE (t);
 
-  /* Skip types, decls, and constants.  */
+  /* Skip types, decls, and constants.  But we do want to look at their
+     types and the bounds of types.  Mark them as visited so we properly
+     unmark their subtrees on the unmark pass.  If we've already seen them,
+     don't look down further.  */
   if (TREE_CODE_CLASS (code) == 't'
       || TREE_CODE_CLASS (code) == 'd'
       || TREE_CODE_CLASS (code) == 'c')
-    *walk_subtrees = 0;
+    {
+      if (TREE_VISITED (t))
+	*walk_subtrees = 0;
+      else
+	TREE_VISITED (t) = 1;
+    }
 
   /* Special-case BIND_EXPR.  We should never be copying these, therefore
      we can omit examining BIND_EXPR_VARS.  Which also avoids problems with
@@ -715,6 +786,31 @@ unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
   return NULL_TREE;
 }
 
+/* Unshare all the trees in BODY_P, a pointer to the body of FNDECL, and the
+   bodies of any nested functions.  */
+
+static void
+unshare_body (tree *body_p, tree fndecl)
+{
+  struct cgraph_node *cgn = cgraph_node (fndecl);
+
+  walk_tree (body_p, copy_if_shared_r, NULL, NULL);
+  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+    unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
+/* Likewise, but mark all trees as not visited.  */
+
+static void
+unvisit_body (tree *body_p, tree fndecl)
+{
+  struct cgraph_node *cgn = cgraph_node (fndecl);
+
+  walk_tree (body_p, unmark_visited_r, NULL, NULL);
+  for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+    unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
 /* Unshare T and all the trees reached from T via TREE_CHAIN.  */
 
 void
@@ -1192,7 +1288,7 @@ build_and_jump (tree *label_p)
 {
   if (label_p == NULL)
     /* If there's nowhere to jump, just fall through.  */
-    return build_empty_stmt ();
+    return alloc_stmt_list ();
 
   if (*label_p == NULL_TREE)
     {
@@ -1214,7 +1310,7 @@ gimplify_exit_expr (tree *expr_p)
   tree expr;
 
   expr = build_and_jump (&gimplify_ctxp->exit_label);
-  expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
+  expr = build (COND_EXPR, void_type_node, cond, expr, alloc_stmt_list ());
   *expr_p = expr;
 
   return GS_OK;
@@ -1243,7 +1339,7 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 
 static enum gimplify_status
 gimplify_init_constructor (tree *expr_p, tree *pre_p,
-			   tree *post_p, int want_value)
+			   tree *post_p, bool want_value)
 {
   tree object = TREE_OPERAND (*expr_p, 0);
   tree ctor = TREE_OPERAND (*expr_p, 1);
@@ -1279,7 +1375,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 		return GS_OK;
 	      }
 	    else
-	      return GS_ALL_DONE;
+	      return GS_UNHANDLED;
 	  }
 
 	categorize_ctor_elements (ctor, &num_nonzero_elements,
@@ -1307,7 +1403,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 	       TU-local symbol, we must invoke the lhd version now.  */
 	    lhd_set_decl_assembler_name (object);
 
-	    *expr_p = build_empty_stmt ();
+	    *expr_p = alloc_stmt_list ();
 	    break;
 	  }
 
@@ -1416,13 +1512,11 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 		if (TREE_CODE (purpose) == RANGE_EXPR)
 		  abort ();
 
-		cref = build (ARRAY_REF, t, object, purpose);
+		cref = build (ARRAY_REF, t, object, purpose, NULL_TREE, NULL_TREE);
 	      }
 	    else
-	      {
-		cref = build (COMPONENT_REF, TREE_TYPE (purpose),
-			      object, purpose);
-	      }
+	      cref = build (COMPONENT_REF, TREE_TYPE (purpose), object,
+			    purpose, NULL_TREE);
 
 	    init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
 	    /* Each member initialization is a full-expression.  */
@@ -1430,7 +1524,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
 	    append_to_statement_list (init, pre_p);
 	  }
 
-	*expr_p = build_empty_stmt ();
+	*expr_p = alloc_stmt_list ();
       }
       break;
 
@@ -1552,18 +1646,17 @@ canonicalize_component_ref (tree *expr_p)
 }
 
 /* If a NOP conversion is changing a pointer to array of foo to a pointer
-   to foo, embed that change in the ADDR_EXPR.  Lest we perturb the type
-   system too badly, we must take extra steps to ensure that the ADDR_EXPR
-   and the addressed object continue to agree on types.  */
-/* ??? We might could do better if we recognize
-	T array[N][M];
-	(T *)&array
+   to foo, embed that change in the ADDR_EXPR by converting 
+      T array[U];
+      (T *)&array
    ==>
-	&array[0][0];
-*/
+      &array[L]
+   where L is the lower bound.  Only do this for constant lower bound since
+   we have no place to put any statements made during gimplification of
+   the lower bound.  */
 
 static void
-canonicalize_addr_expr (tree* expr_p)
+canonicalize_addr_expr (tree *expr_p)
 {
   tree expr = *expr_p;
   tree ctype = TREE_TYPE (expr);
@@ -1592,8 +1685,20 @@ canonicalize_addr_expr (tree* expr_p)
   if (!lang_hooks.types_compatible_p (otype, datype))
     return;
 
+  /* The lower bound and element sizes must be constant.  */
+  if (TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
+      || !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
+      || TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
+    return;
+
   /* All checks succeeded.  Build a new node to merge the cast.  */
-  *expr_p = build1 (ADDR_EXPR, ctype, obj_expr);
+  *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
+		    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+		    TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+		    size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
+				size_int (TYPE_ALIGN (dctype)
+					  / BITS_PER_UNIT)));
+  *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
 }
 
 /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
@@ -1666,7 +1771,7 @@ gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
     return GS_OK;
 }
 
-/* Subroutine of gimplify_compound_lval and gimplify_array_ref.
+/* Subroutine of gimplify_compound_lval.
    Converts an ARRAY_REF to the equivalent *(&array + offset) form.  */
 
 static enum gimplify_status
@@ -1675,25 +1780,21 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
   tree array = TREE_OPERAND (*expr_p, 0);
   tree arrtype = TREE_TYPE (array);
   tree elttype = TREE_TYPE (arrtype);
-  tree size = size_in_bytes (elttype);
+  tree size = array_ref_element_size (*expr_p);
   tree ptrtype = build_pointer_type (elttype);
   enum tree_code add_code = PLUS_EXPR;
   tree idx = TREE_OPERAND (*expr_p, 1);
-  tree minidx, offset, addr, result;
+  tree minidx = unshare_expr (array_ref_low_bound (*expr_p));
+  tree offset, addr, result;
   enum gimplify_status ret;
 
   /* If the array domain does not start at zero, apply the offset.  */
-  minidx = TYPE_DOMAIN (arrtype);
-  if (minidx)
+  if (!integer_zerop (minidx))
     {
-      minidx = TYPE_MIN_VALUE (minidx);
-      if (minidx && !integer_zerop (minidx))
-	{
-	  idx = convert (TREE_TYPE (minidx), idx);
-	  idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
-	}
+      idx = convert (TREE_TYPE (minidx), idx);
+      idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
     }
-
+  
   /* If the index is negative -- a technically invalid situation now
      that we've biased the index back to zero -- then casting it to
      unsigned has ill effects.  In particular, -1*4U/4U != -1.
@@ -1707,7 +1808,7 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
     }
 
   /* Pointer arithmetic must be done in sizetype.  */
-  idx = convert (sizetype, idx);
+  idx = fold_convert (sizetype, idx);
 
   /* Convert the index to a byte offset.  */
   offset = size_binop (MULT_EXPR, size, idx);
@@ -1723,6 +1824,44 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
   return GS_OK;
 }
 
+/*  Build an expression for the address of T.  Folds away INDIRECT_REF to
+    avoid confusing the gimplify process.  */
+
+static tree
+build_addr_expr_with_type (tree t, tree ptrtype)
+{
+  if (TREE_CODE (t) == INDIRECT_REF)
+    {
+      t = TREE_OPERAND (t, 0);
+      if (TREE_TYPE (t) != ptrtype)
+	t = build1 (NOP_EXPR, ptrtype, t);
+    }
+  else
+    {
+      tree base = t;
+
+      if (TREE_CODE (base) == REALPART_EXPR
+	  || TREE_CODE (base) == IMAGPART_EXPR)
+	base = TREE_OPERAND (base, 0);
+      else
+	while (handled_component_p (base))
+	  base = TREE_OPERAND (base, 0);
+
+      if (DECL_P (base))
+	TREE_ADDRESSABLE (base) = 1;
+
+      t = build1 (ADDR_EXPR, ptrtype, t);
+    }
+
+  return t;
+}
+
+static tree
+build_addr_expr (tree t)
+{
+  return build_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
+}
+
 /* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
    node pointed by EXPR_P.
 
@@ -1747,63 +1886,49 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
 
 static enum gimplify_status
 gimplify_compound_lval (tree *expr_p, tree *pre_p,
-			tree *post_p, int want_lvalue)
+			tree *post_p, bool want_lvalue)
 {
   tree *p;
-  enum tree_code code;
   varray_type stack;
-  enum gimplify_status ret;
+  enum gimplify_status ret = GS_OK, tret;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (*expr_p) != ARRAY_REF
+      && TREE_CODE (*expr_p) != ARRAY_RANGE_REF
       && TREE_CODE (*expr_p) != COMPONENT_REF
+      && TREE_CODE (*expr_p) != BIT_FIELD_REF
       && TREE_CODE (*expr_p) != REALPART_EXPR
       && TREE_CODE (*expr_p) != IMAGPART_EXPR)
     abort ();
 #endif
 
-  code = ERROR_MARK;	/* [GIMPLE] Avoid uninitialized use warning.  */
-
   /* Create a stack of the subexpressions so later we can walk them in
      order from inner to outer.  */
   VARRAY_TREE_INIT (stack, 10, "stack");
 
-  for (p = expr_p;
-       TREE_CODE (*p) == ARRAY_REF
-       || TREE_CODE (*p) == COMPONENT_REF
-       || TREE_CODE (*p) == REALPART_EXPR
-       || TREE_CODE (*p) == IMAGPART_EXPR;
-       p = &TREE_OPERAND (*p, 0))
-    {
-      code = TREE_CODE (*p);
-      if (code == ARRAY_REF)
-	{
-	  tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*p, 0)));
-	  if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
-	    /* If the size of the array elements is not constant,
-	       computing the offset is non-trivial, so expose it.  */
-	    break;
-	}
+  /* We can either handle one REALPART_EXPR or IMAGEPART_EXPR or
+     nest of handled components.  */
+  if (TREE_CODE (*expr_p) == REALPART_EXPR
+      || TREE_CODE (*expr_p) == IMAGPART_EXPR)
+    p = &TREE_OPERAND (*expr_p, 0);
+  else
+    for (p = expr_p; handled_component_p (*p); p = &TREE_OPERAND (*p, 0))
       VARRAY_PUSH_TREE (stack, *p);
-    }
-
-  /* Now 'p' points to the first bit that isn't a ref, 'code' is the
-     TREE_CODE of the last bit that was, and 'stack' is a stack of pointers
-     to all the refs we've walked through.
 
-     Gimplify the base, and then process each of the outer nodes from left
-     to right.  */
-  ret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
-		       code != ARRAY_REF ? fb_either : fb_lvalue);
+  /* Now STACK is a stack of pointers to all the refs we've walked through
+     and P points to the innermost expression.
 
+     Process each of the outer nodes from left to right, then gimplify the
+     base.  We need to do it in this order so that PLACEHOLDER_EXPRs
+     can be resolved.  */
   for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
     {
       tree t = VARRAY_TOP_TREE (stack);
-      if (TREE_CODE (t) == ARRAY_REF)
+
+      if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
 	{
-	  /* Gimplify the dimension.  */
-	  enum gimplify_status tret;
-	  /* Temporary fix for gcc.c-torture/execute/20040313-1.c.
+	  /* Gimplify the dimension.
+	     Temporary fix for gcc.c-torture/execute/20040313-1.c.
 	     Gimplify non-constant array indices into a temporary
 	     variable.
 	     FIXME - The real fix is to gimplify post-modify
@@ -1815,14 +1940,82 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
 	    {
 	      tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
 				    is_gimple_tmp_var, fb_rvalue);
-	      if (tret == GS_ERROR)
-		ret = GS_ERROR;
+	      ret = MIN (ret, tret);
+	    }
+
+	  /* Gimplify the low bound and element type size and put them into
+	     the ARRAY_REF.  If these values are set, they have already been
+	     gimplified.  */
+	  if (!TREE_OPERAND (t, 2))
+	    {
+	      TREE_OPERAND (t, 2) = unshare_expr (array_ref_low_bound (t));
+	      if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+		{
+		  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+					is_gimple_tmp_var, fb_rvalue);
+		  ret = MIN (ret, tret);
+		}
+	    }
+
+	  if (!TREE_OPERAND (t, 3))
+	    {
+	      tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
+	      tree elmt_size = unshare_expr (array_ref_element_size (t));
+	      tree factor = size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT);
+
+	      /* Divide the element size by the alignment of the element
+		 type (above).  */
+	      elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor);
+
+	      TREE_OPERAND (t, 3) = elmt_size;
+	      if (!is_gimple_min_invariant (TREE_OPERAND (t, 3)))
+		{
+		  tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
+					is_gimple_tmp_var, fb_rvalue);
+		  ret = MIN (ret, tret);
+		}
 	    }
 	}
+      else if (TREE_CODE (t) == COMPONENT_REF)
+	{
+	  /* Set the field offset into T and gimplify it.  */
+	  if (!TREE_OPERAND (t, 2))
+	    {
+	      tree offset = unshare_expr (component_ref_field_offset (t));
+	      tree field = TREE_OPERAND (t, 1);
+	      tree factor
+		= size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT);
+
+	      /* Divide the offset by its alignment.  */
+	      offset = size_binop (EXACT_DIV_EXPR, offset, factor);
+
+	      TREE_OPERAND (t, 2) = offset;
+	      if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+		{
+		  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+					is_gimple_tmp_var, fb_rvalue);
+		  ret = MIN (ret, tret);
+		}
+	    }
+	}
+      else if (TREE_CODE (t) == BIT_FIELD_REF)
+	{
+	  tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
+				is_gimple_val, fb_rvalue);
+	  ret = MIN (ret, tret);
+	  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+				is_gimple_val, fb_rvalue);
+	  ret = MIN (ret, tret);
+	}
+	  
       recalculate_side_effects (t);
       VARRAY_POP (stack);
     }
 
+  tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
+			want_lvalue ? fb_lvalue : fb_rvalue);
+  ret = MIN (ret, tret);
+
   /* If the outermost expression is a COMPONENT_REF, canonicalize its type.  */
   if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF)
     {
@@ -1833,33 +2026,6 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
   return ret;
 }
 
-/*  Re-write the ARRAY_REF node pointed by EXPR_P.
-
-    PRE_P points to the list where side effects that must happen before
-	*EXPR_P should be stored.
-
-    POST_P points to the list where side effects that must happen after
-	*EXPR_P should be stored.
-
-    FIXME: ARRAY_REF currently doesn't accept a pointer as the array
-    argument, so this gimplification uses an INDIRECT_REF of ARRAY_TYPE.
-    ARRAY_REF should be extended.  */
-
-static enum gimplify_status
-gimplify_array_ref (tree *expr_p, tree *pre_p,
-		    tree *post_p, int want_lvalue)
-{
-  tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*expr_p, 0)));
-  if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
-    /* If the size of the array elements is not constant,
-       computing the offset is non-trivial, so expose it.  */
-    return gimplify_array_ref_to_plus (expr_p, pre_p, post_p);
-  else
-    /* Handle array and member refs together for now.  When alias analysis
-       improves, we may want to go back to handling them separately.  */
-    return gimplify_compound_lval (expr_p, pre_p, post_p, want_lvalue);
-}
-
 /*  Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=).
 
     PRE_P points to the list where side effects that must happen before
@@ -1873,7 +2039,7 @@ gimplify_array_ref (tree *expr_p, tree *pre_p,
 
 static enum gimplify_status
 gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
-			int want_value)
+			bool want_value)
 {
   enum tree_code code;
   tree lhs, lvalue, rhs, t1;
@@ -2166,7 +2332,7 @@ shortcut_cond_expr (tree expr)
 	  then_ = shortcut_cond_expr (expr);
 	  pred = TREE_OPERAND (pred, 0);
 	  expr = build (COND_EXPR, void_type_node, pred, then_,
-			build_empty_stmt ());
+			alloc_stmt_list ());
 	}
     }
   if (!TREE_SIDE_EFFECTS (then_))
@@ -2181,7 +2347,7 @@ shortcut_cond_expr (tree expr)
 	  else_ = shortcut_cond_expr (expr);
 	  pred = TREE_OPERAND (pred, 0);
 	  expr = build (COND_EXPR, void_type_node, pred,
-			build_empty_stmt (), else_);
+			alloc_stmt_list (), else_);
 	}
     }
 
@@ -2207,14 +2373,14 @@ shortcut_cond_expr (tree expr)
       && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
     {
       true_label = GOTO_DESTINATION (then_);
-      then_ = build_empty_stmt ();
+      then_ = alloc_stmt_list ();
     }
 
   if (TREE_CODE (else_) == GOTO_EXPR
       && TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
     {
       false_label = GOTO_DESTINATION (else_);
-      else_ = build_empty_stmt ();
+      else_ = alloc_stmt_list ();
     }
 
   /* If we aren't hijacking a label for the 'then' branch, it falls through.  */
@@ -2329,6 +2495,8 @@ gimple_boolify (tree expr)
 
     The second form is used when *EXPR_P is of type void.
 
+    TARGET is the tree for T1 above.
+
     PRE_P points to the list where side effects that must happen before
 	*EXPR_P should be stored.  */
 
@@ -2456,7 +2624,7 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
 {
   tree *from_p = &TREE_OPERAND (*expr_p, 1);
   tree *to_p = &TREE_OPERAND (*expr_p, 0);
-  enum gimplify_status ret;
+  enum gimplify_status ret = GS_UNHANDLED;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (*expr_p) != MODIFY_EXPR && TREE_CODE (*expr_p) != INIT_EXPR)
@@ -2467,40 +2635,51 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   if (TREE_CODE (*expr_p) == INIT_EXPR)
     TREE_SET_CODE (*expr_p, MODIFY_EXPR);
 
-  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
-  if (ret == GS_ERROR)
+  /* See if any simplifications can be done based on what the RHS is.  */
+  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+				  want_value);
+  if (ret != GS_UNHANDLED)
     return ret;
 
-  /* If we are initializing something from a TARGET_EXPR, strip the
-     TARGET_EXPR and initialize it directly, if possible.  This can't
-     be done if the initializer is void, since that implies that the
-     temporary is set in some non-trivial way.  */
-  /* What about code that pulls out the temp and uses it elsewhere?  I
-     think that such code never uses the TARGET_EXPR as an initializer.  If
-     I'm wrong, we'll abort because the temp won't have any RTL.  In that
-     case, I guess we'll need to replace references somehow.  */
-  if (TREE_CODE (*from_p) == TARGET_EXPR)
+  /* If the value being copied is of variable width, expose the length
+     if the copy by converting the whole thing to a memcpy.  Note that
+     we need to do this before gimplifying any of the operands
+     so that we can resolve any PLACEHOLDER_EXPRs in the size.  */
+  if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST)
     {
-      tree init = TARGET_EXPR_INITIAL (*from_p);
-      if (!VOID_TYPE_P (TREE_TYPE (init)))
-        *from_p = init;
+      tree args, t, dest;
+
+      t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
+      t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *to_p);
+      t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *from_p);
+      t = unshare_expr (t);
+      args = tree_cons (NULL, t, NULL);
+      t = build_fold_addr_expr (*from_p);
+      args = tree_cons (NULL, t, args);
+      dest = build_fold_addr_expr (*to_p);
+      args = tree_cons (NULL, dest, args);
+      t = implicit_built_in_decls[BUILT_IN_MEMCPY];
+      t = build_function_call_expr (t, args);
+      if (want_value)
+	{
+	  t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
+	  t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
+	}
+      *expr_p = t;
+      return GS_OK;
     }
 
-  /* If we're assigning from a ?: expression with ADDRESSABLE type, push
-     the assignment down into the branches, since we can't generate a
-     temporary of such a type.  */
-  if (TREE_CODE (*from_p) == COND_EXPR
-      && TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
-    {
-      *expr_p = *from_p;
-      return gimplify_cond_expr (expr_p, pre_p, *to_p);
-    }
+  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+  if (ret == GS_ERROR)
+    return ret;
 
   ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_rhs, fb_rvalue);
   if (ret == GS_ERROR)
     return ret;
 
-  ret = gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
+  /* Now see if the above changed *from_p to something we handle specially.  */
+  ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+				  want_value);
   if (ret != GS_UNHANDLED)
     return ret;
 
@@ -2530,35 +2709,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
 		   && !is_gimple_reg (*to_p)))
 	gimplify_expr (from_p, pre_p, post_p, is_gimple_val, fb_rvalue);
 
-      /* If the value being copied is of variable width, expose the length
-	 if the copy by converting the whole thing to a memcpy.  */
-      /* ??? Except that we can't manage this with VA_ARG_EXPR.  Yes, this
-	 does leave us with an edge condition that doesn't work.  The only
-	 way out is to rearrange how VA_ARG_EXPR works.  */
-      if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST
-	  && TREE_CODE (*from_p) != VA_ARG_EXPR)
-	{
-	  tree args, t, dest;
-
-	  t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
-	  t = unshare_expr (t);
-	  args = tree_cons (NULL, t, NULL);
-	  t = build_fold_addr_expr (*from_p);
-	  args = tree_cons (NULL, t, args);
-	  dest = build_fold_addr_expr (*to_p);
-	  args = tree_cons (NULL, dest, args);
-	  t = implicit_built_in_decls[BUILT_IN_MEMCPY];
-	  t = build_function_call_expr (t, args);
-	  if (want_value)
-	    {
-	      t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
-	      t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
-	    }
-	  *expr_p = t;
-
-	  return GS_OK;
-	}
-
       ret = want_value ? GS_OK : GS_ALL_DONE;
     }
 
@@ -2571,6 +2721,101 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
   return ret;
 }
 
+/*  Subroutine of above to do simplications of MODIFY_EXPRs based on
+    the code of the RHS.  We loop for as long as we can do something.  */
+
+static enum gimplify_status
+gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
+			  tree *post_p, bool want_value)
+{
+  enum gimplify_status ret = GS_OK;
+
+  while (ret != GS_UNHANDLED)
+    switch (TREE_CODE (*from_p))
+      {
+      case TARGET_EXPR:
+	{
+	  /* If we are initializing something from a TARGET_EXPR, strip the
+	     TARGET_EXPR and initialize it directly, if possible.  This can't
+	     be done if the initializer is void, since that implies that the
+	     temporary is set in some non-trivial way.
+
+	     ??? What about code that pulls out the temp and uses it
+	     elsewhere? I think that such code never uses the TARGET_EXPR as
+	     an initializer.  If I'm wrong, we'll abort because the temp won't
+	     have any RTL.  In that case, I guess we'll need to replace
+	     references somehow.  */
+	  tree init = TARGET_EXPR_INITIAL (*from_p);
+
+	  if (!VOID_TYPE_P (TREE_TYPE (init)))
+	    {
+	      *from_p = init;
+	      ret = GS_OK;
+	    }
+	  else
+	    ret = GS_UNHANDLED;
+	}
+	break;
+
+      case COMPOUND_EXPR:
+	/* Remove any COMPOUND_EXPR in the RHS so the following cases will be
+	   caught.  */
+	gimplify_compound_expr (from_p, pre_p, true);
+	ret = GS_OK;
+	break;
+
+      case CONSTRUCTOR:
+	/* If we're initializing from a CONSTRUCTOR, break this into
+	   individual MODIFY_EXPRs.  */
+	return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
+
+      case COND_EXPR:
+	/* If we're assigning from a ?: expression with ADDRESSABLE type, push
+	   the assignment down into the branches, since we can't generate a
+	   temporary of such a type.  */
+	if (TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
+	  {
+	    *expr_p = *from_p;
+	    return gimplify_cond_expr (expr_p, pre_p, *to_p);
+	  }
+	else
+	  ret = GS_UNHANDLED;
+	break;
+
+      default:
+	ret = GS_UNHANDLED;
+	break;
+      }
+
+  return ret;
+}
+
+/*  Gimplify a comparison between two variable-sized objects.  Do this
+    with a call to BUILT_IN_MEMCMP.  */
+
+static enum gimplify_status
+gimplify_variable_sized_compare (tree *expr_p)
+{
+  tree op0 = TREE_OPERAND (*expr_p, 0);
+  tree op1 = TREE_OPERAND (*expr_p, 1);
+  tree args, t, dest;
+
+  t = TYPE_SIZE_UNIT (TREE_TYPE (op0));
+  t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
+  t = unshare_expr (t);
+  args = tree_cons (NULL, t, NULL);
+  t = build_addr_expr (op1);
+  args = tree_cons (NULL, t, args);
+  dest = build_addr_expr (op0);
+  args = tree_cons (NULL, dest, args);
+  t = implicit_built_in_decls[BUILT_IN_MEMCMP];
+  t = build_function_call_expr (t, args);
+  *expr_p
+    = build (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node);
+
+  return GS_OK;
+}
+
 /*  Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions.  EXPR_P
     points to the expression to gimplify.
 
@@ -2696,7 +2941,7 @@ gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p)
       tree body = TREE_OPERAND (*expr_p, 0);
       ret = gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none);
       append_to_statement_list (body, pre_p);
-      *expr_p = build_empty_stmt ();
+      *expr_p = alloc_stmt_list ();
     }
   else
     *expr_p = TREE_OPERAND (*expr_p, 0)
@@ -2742,9 +2987,15 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
 					pre_p, post_p);
 
       /* This added an INDIRECT_REF.  Fold it away.  */
-      op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+      *expr_p = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+      break;
 
-      *expr_p = op0;
+    case VIEW_CONVERT_EXPR:
+      /* Take the address of our operand and then convert it to the type of
+	 this ADDR_EXPR.  */
+      *expr_p = fold_convert (TREE_TYPE (expr),
+			      build_addr_expr (TREE_OPERAND (op0, 0)));
+      ret = GS_OK;
       break;
 
     default:
@@ -2993,7 +3244,7 @@ gimple_push_cleanup (tree var, tree cleanup, tree *pre_p)
       tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
 			  boolean_true_node);
       cleanup = build (COND_EXPR, void_type_node, flag, cleanup,
-		       build_empty_stmt ());
+		       alloc_stmt_list ());
       wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
 		   cleanup, NULL_TREE);
       append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
@@ -3208,10 +3459,9 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 	  break;
 
 	case ARRAY_REF:
-	  ret = gimplify_array_ref (expr_p, pre_p, post_p,
-				    fallback & fb_lvalue);
-	  break;
-
+	case ARRAY_RANGE_REF:
+	case REALPART_EXPR:
+	case IMAGPART_EXPR:
 	case COMPONENT_REF:
 	  ret = gimplify_compound_lval (expr_p, pre_p, post_p,
 					fallback & fb_lvalue);
@@ -3232,12 +3482,6 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 	  ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
 	  break;
 
-	case REALPART_EXPR:
-	case IMAGPART_EXPR:
-	  ret = gimplify_compound_lval (expr_p, pre_p, post_p,
-					fallback & fb_lvalue);
-	  break;
-
 	case MODIFY_EXPR:
 	case INIT_EXPR:
 	  ret = gimplify_modify_expr (expr_p, pre_p, post_p,
@@ -3265,6 +3509,34 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 	  ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
 	  break;
 
+	case VIEW_CONVERT_EXPR:
+	  if (VOID_TYPE_P (TREE_TYPE (*expr_p))
+	      || fallback == fb_none)
+	    {
+	      /* Just strip a conversion to void (or in void context) and
+		 try again.  */
+	      *expr_p = TREE_OPERAND (*expr_p, 0);
+	      break;
+	    }
+
+	  /* If both types are BLKmode or if one type is of variable size,
+	     convert this into a pointer punning operation.  This avoids
+	     copies of large data or making a variable-size temporary.  */
+	  if ((TYPE_MODE (TREE_TYPE (*expr_p)) == BLKmode
+	       && TYPE_MODE (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) == BLKmode)
+	      || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (*expr_p)))
+	      || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE
+					    (TREE_OPERAND (*expr_p,0)))))
+	    {
+	      tree restype = TREE_TYPE (*expr_p);
+	      *expr_p = build1 (INDIRECT_REF, TREE_TYPE (*expr_p),
+				fold_convert (build_pointer_type (restype),
+					      build_addr_expr
+					      (TREE_OPERAND (*expr_p, 0))));
+	      break;
+	    }
+	  goto unary;
+
 	case CONVERT_EXPR:
 	case NOP_EXPR:
 	  if (IS_EMPTY_STMT (*expr_p))
@@ -3293,6 +3565,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 	case FIX_CEIL_EXPR:
 	case FIX_FLOOR_EXPR:
 	case FIX_ROUND_EXPR:
+	unary:
 	  /* unary_expr: ... | '(' cast ')' val | ...  */
 	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 			       is_gimple_val, fb_rvalue);
@@ -3484,9 +3757,18 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 	  break;
 
 	default:
+	  /* If this is a comparison of objects of aggregate type, handle
+	     it specially (by converting to a call to memcmp).  It would be
+	     nice to only have to do this for variable-sized objects, but
+	     then we'd have to allow the same nest of reference nodes we
+	     allow for MODIFY_EXPR and that's too complex.  */
+	  if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
+	      && (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1)))))
+	    ret = gimplify_variable_sized_compare (expr_p);
+
 	  /* If *EXPR_P does not need to be special-cased, handle it
 	     according to its class.  */
-	  if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
+	  else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
 	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
 				 post_p, is_gimple_val, fb_rvalue);
 	  else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2'
@@ -3529,7 +3811,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
   if (ret == GS_ERROR)
     {
       if (is_statement)
-	*expr_p = build_empty_stmt ();
+	*expr_p = alloc_stmt_list ();
       goto out;
     }
 
@@ -3541,17 +3823,37 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 #endif
 
   if (!*expr_p)
-    *expr_p = build_empty_stmt ();
+    *expr_p = alloc_stmt_list ();
   if (fallback == fb_none && !is_gimple_stmt (*expr_p))
     {
       /* We aren't looking for a value, and we don't have a valid
 	 statement.  If it doesn't have side-effects, throw it away.  */
       if (!TREE_SIDE_EFFECTS (*expr_p))
-	*expr_p = build_empty_stmt ();
+	*expr_p = alloc_stmt_list ();
       else if (!TREE_THIS_VOLATILE (*expr_p))
-	/* We only handle volatiles here; anything else with side-effects
-	   must be converted to a valid statement before we get here.  */
-	abort ();
+	{
+	  /* This is probably a _REF that contains something nested that
+	     has side effects.  Recurse through the operands to find it.  */
+	  enum tree_code code = TREE_CODE (*expr_p);
+
+	  if (code == COMPONENT_REF
+	      || code == REALPART_EXPR || code == IMAGPART_EXPR)
+	    gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+			   gimple_test_f, fallback);
+	  else if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
+	    {
+	      gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+			     gimple_test_f, fallback);
+	      gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+			   gimple_test_f, fallback);
+	    }
+	  else
+	    /* Anything else with side-effects
+	       must be converted to a valid statement before we get here.  */
+	    abort ();
+
+	  *expr_p = alloc_stmt_list ();
+	}
       else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
 	{
 	  /* Historically, the compiler has treated a bare
@@ -3562,7 +3864,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
       else
 	/* We can't do anything useful with a volatile reference to
 	   incomplete type, so just throw it away.  */
-	*expr_p = build_empty_stmt ();
+	*expr_p = alloc_stmt_list ();
     }
 
   /* If we are gimplifying at the statement level, we're done.  Tack
@@ -3660,6 +3962,78 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
   return ret;
 }
 
+/* Look through TYPE for variable-sized objects and gimplify each such
+   size that we find.  Return a STATEMENT_LIST containing the result.  */
+
+tree
+gimplify_type_sizes (tree type)
+{
+  tree stmts = NULL_TREE;
+  tree field;
+
+  switch (TREE_CODE (type))
+    {
+    case ERROR_MARK:
+      return alloc_stmt_list ();
+
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case CHAR_TYPE:
+    case REAL_TYPE:
+      gimplify_one_sizepos (&TYPE_MIN_VALUE (type), &stmts);
+      gimplify_one_sizepos (&TYPE_MAX_VALUE (type), &stmts);
+      break;
+
+    case ARRAY_TYPE:
+      /* These anonymous types don't have declarations, so handle them here. */
+      append_to_statement_list (gimplify_type_sizes (TYPE_DOMAIN (type)),
+				&stmts);
+      break;
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+	if (TREE_CODE (field) == FIELD_DECL)
+	  gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), &stmts);
+      break;
+
+    default:
+      break;
+    }
+
+  gimplify_one_sizepos (&TYPE_SIZE (type), &stmts);
+  gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), &stmts);
+
+  if (!stmts)
+    stmts = alloc_stmt_list ();
+
+  return stmts;
+}
+
+/* Subroutine of the above to gimplify one size or position, *EXPR_P.
+   We add any required statements to STMT_P.  */
+
+void
+gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
+{
+  tree pre = NULL_TREE, post = NULL_TREE;
+
+  /* We don't do anything if the value isn't there, is constant, or contains
+     A PLACEHOLDER_EXPR.  */
+  if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)
+      || CONTAINS_PLACEHOLDER_P (*expr_p))
+    return;
+
+  gimplify_expr (expr_p, &pre, &post, is_gimple_val, fb_rvalue);
+
+  if (pre)
+    append_to_statement_list (pre, stmt_p);
+  if (post)
+    append_to_statement_list (post, stmt_p);
+}
+
 #ifdef ENABLE_CHECKING
 /* Compare types A and B for a "close enough" match.  */
 
@@ -3720,8 +4094,10 @@ check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
       dtype = TREE_TYPE (ptype);
       if (!cpt_same_type (otype, dtype))
 	{
-	  /* &array is allowed to produce a pointer to the element,
-	     rather than a pointer to the array type.  */
+	  /* &array is allowed to produce a pointer to the element, rather than
+	     a pointer to the array type.  We must allow this in order to
+	     properly represent assigning the address of an array in C into
+	     pointer to the element type.  */
 	  if (TREE_CODE (otype) == ARRAY_TYPE
 	      && POINTER_TYPE_P (ptype)
 	      && cpt_same_type (TREE_TYPE (otype), dtype))
@@ -3751,8 +4127,12 @@ gimplify_body (tree *body_p, tree fndecl)
   timevar_push (TV_TREE_GIMPLIFY);
   push_gimplify_context ();
 
-  /* Unshare most shared trees in the body.  */
-  unshare_all_trees (*body_p);
+  /* Unshare most shared trees in the body and in that of any nested functions.
+     It would seem we don't have to do this for nested functions because
+     they are supposed to be output and then the outer function gimplified
+     first, but the g++ front end doesn't always do it that way.  */
+  unshare_body (body_p, fndecl);
+  unvisit_body (body_p, fndecl);
 
   /* Make sure input_location isn't set to something wierd.  */
   input_location = DECL_SOURCE_LOCATION (fndecl);
@@ -3764,13 +4144,14 @@ gimplify_body (tree *body_p, tree fndecl)
   /* Unshare again, in case gimplification was sloppy.  */
   unshare_all_trees (body);
 
-  /* If there isn't an outer BIND_EXPR, add one.  */
   if (TREE_CODE (body) == STATEMENT_LIST)
     {
       tree t = expr_only (*body_p);
       if (t)
 	body = t;
     }
+
+  /* If there isn't an outer BIND_EXPR, add one.  */
   if (TREE_CODE (body) != BIND_EXPR)
     {
       tree b = build (BIND_EXPR, void_type_node, NULL_TREE,
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index cd9cffb67d235da1bbe381dd31f93e328caa6862..fd899174028c6c55f2843d8c4e0d76bb60fa34cd 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,16 @@
+2004-06-21  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>
+
+	* class.c (build_class_ref): Add new operand for COMPONENT_REF.
+	(build_static_field_ref): Likewise and add new operands for ARRAY_REF.
+	* constants.c (build_ref_from_constant_pool): Likewise.
+	* expr.c (build_java_array_length_access): Likewise.
+	(build_get_class, build_field_ref, build_known_method_ref): Likewise.
+	(invoke_build_dtable, build_invokevirtual): Likewise.
+	(build_invokeinterface, java_expand_expr): Likewise.
+	(emit_init_test_initialization): Likewise.
+	* java-gimplify.c (java_gimplify_new_array_init): Likewise.
+	* parse.y (make_qualifed_name, build_array_ref): Likewise.
+	
 2004-06-21  Andrew Haley  <aph@redhat.com>
 
 	* java-gimplify.c (java_gimplify_block): set TREE_USED on the new
diff --git a/gcc/java/class.c b/gcc/java/class.c
index cfb3366eeceae112e0da5bc1b6d2d85c433a49ec..ca9d62721c7e62ebce99c91fcf84e2db88ddec97 100644
--- a/gcc/java/class.c
+++ b/gcc/java/class.c
@@ -1023,7 +1023,7 @@ build_class_ref (tree type)
 
 	      prim_class = lookup_class (get_identifier (prim_class_name));
 	      return build (COMPONENT_REF, NULL_TREE,
-			    prim_class, TYPE_identifier_node);
+			    prim_class, TYPE_identifier_node, NULL_TREE);
 	    }
 	  decl_name = TYPE_NAME (type);
 	  if (TREE_CODE (decl_name) == TYPE_DECL)
@@ -1088,7 +1088,8 @@ build_static_field_ref (tree fdecl)
 		       (fdecl, &TYPE_ATABLE_METHODS (output_class)), 0);
       tree field_address
 	= build (ARRAY_REF, build_pointer_type (TREE_TYPE (fdecl)), 
-		 TYPE_ATABLE_DECL (output_class), table_index);
+		 TYPE_ATABLE_DECL (output_class), table_index,
+		 NULL_TREE, NULL_TREE);
       return fold (build1 (INDIRECT_REF, TREE_TYPE (fdecl), 
 			   field_address));
     }
@@ -1101,7 +1102,8 @@ build_static_field_ref (tree fdecl)
       int field_index = 0;
       ref = build1 (INDIRECT_REF, class_type_node, ref);
       ref = build (COMPONENT_REF, field_ptr_type_node, ref,
-		   lookup_field (&class_type_node, fields_ident));
+		   lookup_field (&class_type_node, fields_ident),
+		   NULL_TREE);
 
       for (fld = TYPE_FIELDS (fclass); ; fld = TREE_CHAIN (fld))
 	{
@@ -1118,9 +1120,11 @@ build_static_field_ref (tree fdecl)
 			 ref, build_int_2 (field_index, 0)));
       ref = build1 (INDIRECT_REF, field_type_node, ref);
       ref = build (COMPONENT_REF, field_info_union_node,
-		   ref, lookup_field (&field_type_node, info_ident));
+		   ref, lookup_field (&field_type_node, info_ident),
+		   NULL_TREE);
       ref = build (COMPONENT_REF, ptr_type_node,
-		   ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)));
+		   ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node)),
+		   NULL_TREE);
       return fold (build1 (INDIRECT_REF, TREE_TYPE(fdecl), ref));
     }
 }
diff --git a/gcc/java/constants.c b/gcc/java/constants.c
index 32fc854c9dbe31cf66e24343c8451ef916a14456..98127f590db86c8850b75164037b157ee2a3cc2b 100644
--- a/gcc/java/constants.c
+++ b/gcc/java/constants.c
@@ -424,7 +424,8 @@ build_ref_from_constant_pool (int index)
 {
   tree d = build_constant_data_ref ();
   tree i = build_int_2 (index, 0);
-  return build (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i);
+  return build (ARRAY_REF, TREE_TYPE (TREE_TYPE (d)), d, i,
+		NULL_TREE, NULL_TREE);
 }
 
 /* Build an initializer for the constants field of the current constant pool.
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index 86a7899c9a8d8cac6c39a5d6e9ec091c205ec57d..446f8afe2db45907a6f0e4f62a070bfd6809987a 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -698,7 +698,8 @@ build_java_array_length_access (tree node)
   node = build (COMPONENT_REF, int_type_node,
 		build_java_indirect_ref (array_type, node,
 					 flag_check_references),
-		lookup_field (&array_type, get_identifier ("length")));
+		lookup_field (&array_type, get_identifier ("length")),
+		NULL_TREE);
   IS_ARRAY_LENGTH_ACCESS (node) = 1;
   return node;
 }
@@ -780,9 +781,9 @@ build_java_arrayaccess (tree array, tree type, tree index)
   ref = build (COMPONENT_REF, TREE_TYPE (data_field),    
 	       build_java_indirect_ref (array_type, array, 
 					flag_check_references),
-	       data_field);
+	       data_field, NULL_TREE);
   
-  node = build (ARRAY_REF, type, ref, index);
+  node = build (ARRAY_REF, type, ref, index, NULL_TREE, NULL_TREE);
   return node;
 }
 
@@ -1181,8 +1182,8 @@ build_get_class (tree value)
 			build (COMPONENT_REF, dtable_ptr_type,
 			       build_java_indirect_ref (object_type_node, value,
 							flag_check_references),
-			       vtable_field)),
-		class_field);
+			       vtable_field, NULL_TREE)),
+		class_field, NULL_TREE);
 }
 
 /* This builds the tree representation of the `instanceof' operator.
@@ -1531,13 +1532,16 @@ build_field_ref (tree self_value, tree self_class, tree name)
 	   in the same translation unit as output_class.  If it is,
 	   we can make a direct reference.  */
 	{
-	  tree otable_index =
-	    build_int_2 (get_symbol_table_index 
-			 (field_decl, &TYPE_OTABLE_METHODS (output_class)), 0);
-	  tree field_offset = 
-	    build (ARRAY_REF, integer_type_node, TYPE_OTABLE_DECL (output_class), 
-		   otable_index);
+	  tree otable_index
+	    = build_int_2 (get_symbol_table_index 
+			   (field_decl, &TYPE_OTABLE_METHODS (output_class)),
+			   0);
+	  tree field_offset
+	    = build (ARRAY_REF, integer_type_node,
+		     TYPE_OTABLE_DECL (output_class), otable_index,
+		     NULL_TREE, NULL_TREE);
 	  tree address;
+
 	  field_offset = fold (convert (sizetype, field_offset));
 	  address 
 	    = fold (build (PLUS_EXPR, 
@@ -1549,7 +1553,7 @@ build_field_ref (tree self_value, tree self_class, tree name)
       self_value = build_java_indirect_ref (TREE_TYPE (TREE_TYPE (self_value)),
 					    self_value, check);
       return fold (build (COMPONENT_REF, TREE_TYPE (field_decl),
-			  self_value, field_decl));
+			  self_value, field_decl, NULL_TREE));
     }
 }
 
@@ -1826,12 +1830,12 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
 	}
       else
 	{
-	  tree table_index = 
-	    build_int_2 (get_symbol_table_index 
-			 (method, &TYPE_ATABLE_METHODS (output_class)), 0);
-	  func = 
-	    build (ARRAY_REF,  method_ptr_type_node, 
-		   TYPE_ATABLE_DECL (output_class), table_index);
+	  tree table_index
+	    = build_int_2 (get_symbol_table_index 
+			   (method, &TYPE_ATABLE_METHODS (output_class)), 0);
+	  func = build (ARRAY_REF,  method_ptr_type_node, 
+			TYPE_ATABLE_DECL (output_class), table_index,
+			NULL_TREE, NULL_TREE);
 	}
       func = convert (method_ptr_type_node, func);
     }
@@ -1858,7 +1862,7 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
       if (methods_ident == NULL_TREE)
 	methods_ident = get_identifier ("methods");
       ref = build (COMPONENT_REF, method_ptr_type_node, ref,
-		   lookup_field (&class_type_node, methods_ident));
+		   lookup_field (&class_type_node, methods_ident), NULL_TREE);
       for (meth = TYPE_METHODS (self_type);
 	   ; meth = TREE_CHAIN (meth))
 	{
@@ -1874,8 +1878,8 @@ build_known_method_ref (tree method, tree method_type ATTRIBUTE_UNUSED,
 			 ref, build_int_2 (method_index, 0)));
       ref = build1 (INDIRECT_REF, method_type_node, ref);
       func = build (COMPONENT_REF, nativecode_ptr_type_node,
-		    ref,
-		    lookup_field (&method_type_node, ncode_ident));
+		    ref, lookup_field (&method_type_node, ncode_ident),
+		    NULL_TREE);
     }
   return func;
 }
@@ -1899,7 +1903,7 @@ invoke_build_dtable (int is_invoke_interface, tree arg_list)
   dtable = build_java_indirect_ref (object_type_node, objectref, 
 				    flag_check_references);
   dtable = build (COMPONENT_REF, dtable_ptr_type, dtable,
-		  lookup_field (&object_type_node, dtable_ident));
+		  lookup_field (&object_type_node, dtable_ident), NULL_TREE);
 
   return dtable;
 }
@@ -1955,7 +1959,7 @@ build_invokevirtual (tree dtable, tree method)
 		       (method, &TYPE_OTABLE_METHODS (output_class)), 0);
       method_index = build (ARRAY_REF, integer_type_node, 
 			    TYPE_OTABLE_DECL (output_class), 
-			    otable_index);
+			    otable_index, NULL_TREE, NULL_TREE);
     }
   else
     {
@@ -2001,7 +2005,7 @@ build_invokeinterface (tree dtable, tree method)
   dtable = build_java_indirect_ref (dtable_type, dtable,
 				    flag_check_references);
   dtable = build (COMPONENT_REF, class_ptr_type, dtable,
-		  lookup_field (&dtable_type, class_ident));
+		  lookup_field (&dtable_type, class_ident), NULL_TREE);
 
   interface = DECL_CONTEXT (method);
   if (! CLASS_INTERFACE (TYPE_NAME (interface)))
@@ -2010,17 +2014,15 @@ build_invokeinterface (tree dtable, tree method)
   
   if (flag_indirect_dispatch)
     {
-      otable_index =
-	build_int_2 (get_symbol_table_index 
-		     (method, &TYPE_OTABLE_METHODS (output_class)), 0);
-      idx = 
-	build (ARRAY_REF, integer_type_node, TYPE_OTABLE_DECL (output_class),
-	       otable_index);
+      otable_index
+	= build_int_2 (get_symbol_table_index 
+		       (method, &TYPE_OTABLE_METHODS (output_class)), 0);
+      idx = build (ARRAY_REF, integer_type_node,
+		   TYPE_OTABLE_DECL (output_class), otable_index,
+		   NULL_TREE, NULL_TREE);
     }
   else
-    {
-      idx = build_int_2 (get_interface_method_index (method, interface), 0);
-    }
+    idx = build_int_2 (get_interface_method_index (method, interface), 0);
 
   lookup_arg = tree_cons (NULL_TREE, dtable,
                           tree_cons (NULL_TREE, build_class_ref (interface),
@@ -2577,7 +2579,8 @@ java_expand_expr (tree exp, rtx target, enum machine_mode tmode,
 	expand_assignment (build (COMPONENT_REF, TREE_TYPE (data_fld),
 				  build_java_indirect_ref (array_type, 
 					  array_decl, flag_check_references), 
-				  data_fld), init, 0);
+				  data_fld, NULL_TREE),
+			   init, 0);
 	return tmp;
       }
     case BLOCK:
@@ -3460,7 +3463,8 @@ emit_init_test_initialization (void **entry, void *x ATTRIBUTE_UNUSED)
 		 build (COMPONENT_REF, byte_type_node,
 			build1 (INDIRECT_REF, class_type_node, klass),
 			lookup_field (&class_type_node,
-				      get_identifier ("state"))),
+				      get_identifier ("state")),
+			NULL_TREE),
 		 build_int_2 (JV_STATE_DONE, 0));
 
   expand_expr_stmt (build (MODIFY_EXPR, boolean_type_node, 
diff --git a/gcc/java/java-gimplify.c b/gcc/java/java-gimplify.c
index 3c446672255efec91c0cc73e58516d9a45210108..766995e8254d10378dbed291e57ce907a6993362 100644
--- a/gcc/java/java-gimplify.c
+++ b/gcc/java/java-gimplify.c
@@ -1,5 +1,4 @@
 /* Java(TM) language-specific gimplification routines.
-
    Copyright (C) 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -223,10 +222,11 @@ java_gimplify_new_array_init (tree exp)
 	 bounds checking.  */
       tree lhs = build (COMPONENT_REF, TREE_TYPE (data_field),    
 			build_java_indirect_ref (array_type, tmp, 0),
-			data_field);
+			data_field, NULL_TREE);
       tree assignment = build (MODIFY_EXPR, element_type,
   			       build (ARRAY_REF, element_type, lhs,
-				      build_int_2 (index++, 0)),
+				      build_int_2 (index++, 0),
+				      NULL_TREE, NULL_TREE),
 			       TREE_VALUE (values));
       body = build (COMPOUND_EXPR, element_type, body, assignment);
       values = TREE_CHAIN (values);
diff --git a/gcc/java/parse.y b/gcc/java/parse.y
index dd52a39359d57f659639bb8cba698983d06b4d71..ed1f05040ec9f81cdec2f3561649b3c70ad483a9 100644
--- a/gcc/java/parse.y
+++ b/gcc/java/parse.y
@@ -9254,7 +9254,7 @@ static tree
 make_qualified_name (tree left, tree right, int location)
 {
 #ifdef USE_COMPONENT_REF
-  tree node = build (COMPONENT_REF, NULL_TREE, left, right);
+  tree node = build (COMPONENT_REF, NULL_TREE, left, right, NULL_TREE);
   EXPR_WFL_LINECOL (node) = location;
   return node;
 #else
@@ -14353,7 +14353,7 @@ build_null_of_type (tree type)
 static tree
 build_array_ref (int location, tree array, tree index)
 {
-  tree node = build (ARRAY_REF, NULL_TREE, array, index);
+  tree node = build (ARRAY_REF, NULL_TREE, array, index, NULL_TREE, NULL_TREE);
   EXPR_WFL_LINECOL (node) = location;
   return node;
 }
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 4414309ca7d51cf72c5ba3c0ac181b81c0355d58..bf739565cad9ec47378d68db4d79b31ddd823298 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -1975,7 +1975,7 @@ generate_static_references (void)
       sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class);
       ident = get_identifier (buf);
 
-      expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+      expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE, NULL_TREE, NULL_TREE);
       decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
 			     build_tree_list (NULL_TREE,
 					      ridpointers[(int) RID_STATIC]));
@@ -2014,7 +2014,7 @@ generate_static_references (void)
 
   decls = tree_cons (NULL_TREE, build_int_2 (0, 0), decls);
   ident = get_identifier ("_OBJC_STATIC_INSTANCES");
-  expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+  expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE, NULL_TREE, NULL_TREE);
   decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
 			 build_tree_list (NULL_TREE,
 					  ridpointers[(int) RID_STATIC]));
@@ -2044,7 +2044,8 @@ generate_strings (void)
       sc_spec
 	= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
       decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
-      expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+      expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+			    NULL_TREE, NULL_TREE);
       decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
       DECL_CONTEXT (decl) = NULL_TREE;
       string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
@@ -2059,7 +2060,8 @@ generate_strings (void)
       sc_spec
 	= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
       decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
-      expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+      expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+			    NULL_TREE, NULL_TREE);
       decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
       DECL_CONTEXT (decl) = NULL_TREE;
       string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
@@ -2074,7 +2076,8 @@ generate_strings (void)
       sc_spec
 	= tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
       decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
-      expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+      expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE,
+			    NULL_TREE, NULL_TREE);
       decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE);
       DECL_CONTEXT (decl) = NULL_TREE;
       string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
@@ -3521,7 +3524,7 @@ build_method_prototype_list_template (tree list_type, int size)
 
   decl_specs = build_tree_list (NULL_TREE, list_type);
   field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
-			 build_int_2 (size, 0));
+			 build_int_2 (size, 0), NULL_TREE, NULL_TREE);
   field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
   chainon (field_decl_chain, field_decl);
 
@@ -4405,7 +4408,7 @@ build_ivar_list_template (tree list_type, int size)
 
   decl_specs = build_tree_list (NULL_TREE, list_type);
   field_decl = build_nt (ARRAY_REF, get_identifier ("ivar_list"),
-			 build_int_2 (size, 0));
+			 build_int_2 (size, 0), NULL_TREE, NULL_TREE);
 
   field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
   chainon (field_decl_chain, field_decl);
@@ -4453,7 +4456,7 @@ build_method_list_template (tree list_type, int size)
 
   decl_specs = build_tree_list (NULL_TREE, list_type);
   field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
-			 build_int_2 (size, 0));
+			 build_int_2 (size, 0), NULL_TREE, NULL_TREE);
 
   field_decl = grokfield (field_decl, decl_specs, NULL_TREE);
   chainon (field_decl_chain, field_decl);
@@ -4860,18 +4863,18 @@ generate_protocol_list (tree i_or_p)
     expr_decl = build_nt (ARRAY_REF,
 			  synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS",
 						      i_or_p),
-			  build_int_2 (size + 2, 0));
+			  build_int_2 (size + 2, 0), NULL_TREE, NULL_TREE);
   else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE)
     expr_decl = build_nt (ARRAY_REF,
 			  synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS",
 						      i_or_p),
-			  build_int_2 (size + 2, 0));
+			  build_int_2 (size + 2, 0), NULL_TREE, NULL_TREE);
   else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
     expr_decl
       = build_nt (ARRAY_REF,
 		  synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS",
 					      i_or_p),
-		  build_int_2 (size + 2, 0));
+		  build_int_2 (size + 2, 0), NULL_TREE, NULL_TREE);
   else
     abort ();
 
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 4d878e3b081385acf08870e31000f56f727e045b..5ee55b9e6999c944e0ec00cb8957e84f796f0f3e 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -3391,12 +3391,6 @@ expand_stack_alloc (tree alloc, tree t_size)
 
   type = TREE_TYPE (var);
 
-  /* In function-at-a-time mode, variable_size doesn't expand this,
-     so do it now.  */
-  if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
-    expand_expr (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
-		 const0_rtx, VOIDmode, 0);
-
   /* Compute the variable's size, in bytes.  */
   size = expand_expr (t_size, NULL_RTX, VOIDmode, 0);
   free_temp_slots ();
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index aa452b495fc7926716f41d6ab35e305a6dd56b1f..b2ef41dbda2f473b278f9df5e814bf9939b85dba 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -93,11 +93,6 @@ tree
 get_pending_sizes (void)
 {
   tree chain = pending_sizes;
-  tree t;
-
-  /* Put each SAVE_EXPR into the current function.  */
-  for (t = chain; t; t = TREE_CHAIN (t))
-    SAVE_EXPR_CONTEXT (TREE_VALUE (t)) = current_function_decl;
 
   pending_sizes = 0;
   return chain;
diff --git a/gcc/tree-alias-common.c b/gcc/tree-alias-common.c
index 33ef6d34db3d25f5bf1f230faa600086cd77b72d..561feb5210a57bf2a989b3e57e066c23edd59880 100644
--- a/gcc/tree-alias-common.c
+++ b/gcc/tree-alias-common.c
@@ -207,12 +207,15 @@ get_alias_var (tree expr)
   switch (TREE_CODE (expr))
     {
     case ARRAY_REF:
+    case ARRAY_RANGE_REF:
       {
-	/* Find the first non-array ref, and return it's alias
-	   variable */
+	/* Find the first non-array ref, and return its alias variable.  */
 	tree p;
-	for (p = expr; TREE_CODE (p) == ARRAY_REF;
-	     p = TREE_OPERAND (p, 0));
+
+	for (p = expr;
+	     TREE_CODE (p) == ARRAY_REF || TREE_CODE (p) == ARRAY_RANGE_REF;
+	     p = TREE_OPERAND (p, 0))
+	  ;
 	return get_alias_var (p);
       }
       break;
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 8babdc293c534ff089b35520b344eacc4d63022e..9b42073376631ce4c649706284dcc9490d61dd69 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3156,12 +3156,10 @@ verify_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
       break;
 
     case ADDR_EXPR:
-      x = TREE_OPERAND (t, 0);
-      while (TREE_CODE (x) == ARRAY_REF
-	     || TREE_CODE (x) == COMPONENT_REF
-	     || TREE_CODE (x) == REALPART_EXPR
-	     || TREE_CODE (x) == IMAGPART_EXPR)
-	x = TREE_OPERAND (x, 0);
+      for (x = TREE_OPERAND (t, 0); handled_component_p (x);
+	   x = TREE_OPERAND (x, 0))
+	;
+
       if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
 	return NULL;
       if (!TREE_ADDRESSABLE (x))
@@ -3309,7 +3307,7 @@ tree_node_can_be_shared (tree t)
       || TREE_CODE (t) == SSA_NAME)
     return true;
 
-  while ((TREE_CODE (t) == ARRAY_REF
+  while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
 	  /* We check for constants explicitly since they are not considered
 	     gimple invariants if they overflowed.  */
 	  && (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 1))) == 'c'
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index e1445be48744a44f4eeb6fa62d2ad9951943e4e0..307086bedb776197fae5c04978cb95dfbc5293f2 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -926,24 +926,17 @@ add_referenced_var (tree var, struct walk_state *walk_state)
 tree
 get_virtual_var (tree var)
 {
-  enum tree_code code;
-
   STRIP_NOPS (var);
 
   if (TREE_CODE (var) == SSA_NAME)
     var = SSA_NAME_VAR (var);
 
-  code = TREE_CODE (var);
-
-  while (code == ARRAY_REF
-         || code == COMPONENT_REF
-	 || code == REALPART_EXPR
-	 || code == IMAGPART_EXPR)
-    {
+  if (TREE_CODE (var) == REALPART_EXPR || TREE_CODE (var) == IMAGPART_EXPR)
+    var = TREE_OPERAND (var, 0);
+  else
+    while (handled_component_p (var))
       var = TREE_OPERAND (var, 0);
-      code = TREE_CODE (var);
-    }
-
+    
 #ifdef ENABLE_CHECKING
   /* Treating GIMPLE registers as virtual variables makes no sense.
      Also complain if we couldn't extract a _DECL out of the original
diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c
index 45accaee0ed01f390c108869d80b695307625789..39aeeaddf4163a26a8ffcb8e0e022a9f9f32b415 100644
--- a/gcc/tree-dump.c
+++ b/gcc/tree-dump.c
@@ -536,9 +536,7 @@ dequeue_and_dump (dump_info_p di)
     case TRUTH_ORIF_EXPR:
     case INIT_EXPR:
     case MODIFY_EXPR:
-    case COMPONENT_REF:
     case COMPOUND_EXPR:
-    case ARRAY_REF:
     case PREDECREMENT_EXPR:
     case PREINCREMENT_EXPR:
     case POSTDECREMENT_EXPR:
@@ -548,6 +546,20 @@ dequeue_and_dump (dump_info_p di)
       dump_child ("op 1", TREE_OPERAND (t, 1));
       break;
 
+    case COMPONENT_REF:
+      dump_child ("op 0", TREE_OPERAND (t, 0));
+      dump_child ("op 1", TREE_OPERAND (t, 1));
+      dump_child ("op 2", TREE_OPERAND (t, 2));
+      break;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+      dump_child ("op 0", TREE_OPERAND (t, 0));
+      dump_child ("op 1", TREE_OPERAND (t, 1));
+      dump_child ("op 2", TREE_OPERAND (t, 2));
+      dump_child ("op 3", TREE_OPERAND (t, 3));
+      break;
+
     case COND_EXPR:
       dump_child ("op 0", TREE_OPERAND (t, 0));
       dump_child ("op 1", TREE_OPERAND (t, 1));
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 27f33c9141fa6aff29efa84a5858c321cedc1a9b..21c3a1c3815b23079973d2ffd0233b441804db58 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -1682,6 +1682,7 @@ tree_could_trap_p (tree expr)
   switch (code)
     {
     case ARRAY_REF:
+    case ARRAY_RANGE_REF:
     case COMPONENT_REF:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c
index d3231c01fb68239f49010567c4ed1ac4e1a0ec7a..7c992b36adcdca8d3cd51eb1f8b05c08f4ee339f 100644
--- a/gcc/tree-gimple.c
+++ b/gcc/tree-gimple.c
@@ -119,17 +119,34 @@ Boston, MA 02111-1307, USA.  */
    min-lval: ID | '*' ID
    bitfieldref :
      BIT_FIELD_REF
-       op0 -> compref | min-lval
+       op0 -> inner_compref
        op1 -> CONST
-       op2 -> CONST
+       op2 -> var
    compref :
      COMPONENT_REF
-       op0 -> compref | min-lval
+       op0 -> inner_compref
      | ARRAY_REF
-       op0 -> compref | min-lval
+       op0 -> inner_compref
        op1 -> val
+       op2 -> val
+       op3 -> val
+     | ARRAY_RANGE_REF
+       op0 -> inner_compref
+       op1 -> val
+       op2 -> val
+       op3 -> val
      | REALPART_EXPR
+       op0 -> inner_compref
      | IMAGPART_EXPR
+       op0 -> inner_compref
+
+   inner_compref : compref | min_lval
+     | VIEW_CONVERT_EXPR
+       op0 -> inner_compref
+     | NOP_EXPR
+       op0 -> inner_compref
+     | CONVERT_EXPR
+       op0 -> inner_compref
 
    condition : val | val relop val
    val : ID | CONST
@@ -284,9 +301,11 @@ is_gimple_addr_expr_arg (tree t)
 {
   return (is_gimple_id (t)
 	  || TREE_CODE (t) == ARRAY_REF
+	  || TREE_CODE (t) == ARRAY_RANGE_REF
 	  || TREE_CODE (t) == COMPONENT_REF
 	  || TREE_CODE (t) == REALPART_EXPR
-	  || TREE_CODE (t) == IMAGPART_EXPR);
+	  || TREE_CODE (t) == IMAGPART_EXPR
+	  || TREE_CODE (t) == INDIRECT_REF);
 }
 
 /* Return nonzero if T is function invariant.  Or rather a restricted
@@ -581,19 +600,12 @@ get_base_address (tree t)
 	  || TREE_CODE (t) == INDIRECT_REF)
 	return t;
 
-      switch (TREE_CODE (t))
-	{
-	case ARRAY_REF:
-	case COMPONENT_REF:
-	case REALPART_EXPR:
-	case IMAGPART_EXPR:
-	case BIT_FIELD_REF:
-	  t = TREE_OPERAND (t, 0);
-	  break;
-
-	default:
-	  return NULL_TREE;
-	}
+      if (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR)
+	t = TREE_OPERAND (t, 0);
+      else if (handled_component_p (t))
+	t = get_base_address (TREE_OPERAND (t, 0));
+      else
+	return NULL_TREE;
     }
   while (t);
 
diff --git a/gcc/tree-gimple.h b/gcc/tree-gimple.h
index 29352a54b81290d568a2ec418b2922e7cbcf71aa..98f46951af4b525f1c629d6874a751e7d5ec5ec3 100644
--- a/gcc/tree-gimple.h
+++ b/gcc/tree-gimple.h
@@ -42,45 +42,45 @@ extern void annotate_all_with_locus (tree *, location_t);
    underlying nodes are also of the right form.  */
 
 /* Returns true iff T is a valid GIMPLE statement.  */
-bool is_gimple_stmt (tree);
+extern bool is_gimple_stmt (tree);
 
 /* Returns true iff TYPE is a valid type for a scalar register variable.  */
-bool is_gimple_reg_type (tree);
+extern bool is_gimple_reg_type (tree);
 /* Returns true iff T is a scalar register variable.  */
-bool is_gimple_reg (tree);
+extern bool is_gimple_reg (tree);
 /* Returns true iff T is any sort of variable.  */
-bool is_gimple_variable (tree);
+extern bool is_gimple_variable (tree);
 /* Returns true iff T is a variable or an INDIRECT_REF (of a variable).  */
-bool is_gimple_min_lval (tree);
+extern bool is_gimple_min_lval (tree);
 /* Returns true iff T is an lvalue other than an INDIRECT_REF.  */
-bool is_gimple_addr_expr_arg (tree);
+extern bool is_gimple_addr_expr_arg (tree);
 /* Returns true iff T is any valid GIMPLE lvalue.  */
-bool is_gimple_lvalue (tree);
+extern bool is_gimple_lvalue (tree);
 
 /* Returns true iff T is a GIMPLE restricted function invariant.  */
-bool is_gimple_min_invariant (tree);
+extern bool is_gimple_min_invariant (tree);
 /* Returns true iff T is a GIMPLE rvalue.  */
-bool is_gimple_val (tree);
+extern bool is_gimple_val (tree);
 /* Returns true iff T is a valid rhs for a MODIFY_EXPR.  */
-bool is_gimple_rhs (tree);
+extern bool is_gimple_rhs (tree);
 
 /* Returns true iff T is a valid if-statement condition.  */
-bool is_gimple_condexpr (tree);
+extern bool is_gimple_condexpr (tree);
 
 /* Returns true iff T is a type conversion.  */
-bool is_gimple_cast (tree);
+extern bool is_gimple_cast (tree);
 /* Returns true iff T is a valid CONSTRUCTOR element (either an rvalue or
    another CONSTRUCTOR).  */
-bool is_gimple_constructor_elt (tree);
+extern bool is_gimple_constructor_elt (tree);
 /* Returns true iff T is a variable that does not need to live in memory.  */
-bool is_gimple_non_addressable (tree t);
+extern bool is_gimple_non_addressable (tree t);
 
 /* If T makes a function call, returns the CALL_EXPR operand.  */
-tree get_call_expr_in (tree t);
+extern tree get_call_expr_in (tree t);
 
-void recalculate_side_effects (tree);
+extern void recalculate_side_effects (tree);
 
-void append_to_compound_expr (tree, tree *);
+extern void append_to_compound_expr (tree, tree *);
 
 /* FIXME we should deduce this from the predicate.  */
 typedef enum fallback_t {
@@ -98,29 +98,31 @@ enum gimplify_status {
   GS_ALL_DONE	= 1	/* The expression is fully gimplified.  */
 };
 
-enum gimplify_status gimplify_expr (tree *, tree *, tree *,
-				    bool (*) (tree), fallback_t);
-void gimplify_stmt (tree *);
-void gimplify_to_stmt_list (tree *);
-void gimplify_body (tree *, tree);
-void push_gimplify_context (void);
-void pop_gimplify_context (tree);
-void gimplify_and_add (tree, tree *);
+extern enum gimplify_status gimplify_expr (tree *, tree *, tree *,
+					   bool (*) (tree), fallback_t);
+extern tree gimplify_type_sizes (tree);
+extern void gimplify_one_sizepos (tree *, tree *);
+extern void gimplify_stmt (tree *);
+extern void gimplify_to_stmt_list (tree *);
+extern void gimplify_body (tree *, tree);
+extern void push_gimplify_context (void);
+extern void pop_gimplify_context (tree);
+extern void gimplify_and_add (tree, tree *);
 
 /* Miscellaneous helpers.  */
-tree get_base_address (tree t);
-void gimple_add_tmp_var (tree);
-tree gimple_current_bind_expr (void);
-void gimple_push_bind_expr (tree);
-void gimple_pop_bind_expr (void);
-void unshare_all_trees (tree);
-tree voidify_wrapper_expr (tree, tree);
-tree gimple_build_eh_filter (tree, tree, tree);
-tree build_and_jump (tree *);
-tree alloc_stmt_list (void);
-void free_stmt_list (tree);
-tree force_labels_r (tree *, int *, void *);
-enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
+extern tree get_base_address (tree t);
+extern void gimple_add_tmp_var (tree);
+extern tree gimple_current_bind_expr (void);
+extern void gimple_push_bind_expr (tree);
+extern void gimple_pop_bind_expr (void);
+extern void unshare_all_trees (tree);
+extern tree voidify_wrapper_expr (tree, tree);
+extern tree gimple_build_eh_filter (tree, tree, tree);
+extern tree build_and_jump (tree *);
+extern tree alloc_stmt_list (void);
+extern void free_stmt_list (tree);
+extern tree force_labels_r (tree *, int *, void *);
+extern enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
 
 /* In tree-nested.c.  */
 extern void lower_nested_functions (tree);
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 24bf3d1b2ff3e82cdd0b938d31effb239d5daea5..deb73605ca2591541ac4c3b510ee5e7f64e4df92 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -2054,8 +2054,14 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
 	}
 #endif
     }
-  else if (TREE_CODE_CLASS (code) == 'd')
+
+  /* Look inside the sizes of decls, but we don't ever use the values for
+     FIELD_DECL and RESULT_DECL, so ignore them.  */
+  else if (TREE_CODE_CLASS (code) == 'd'
+	   && code != FIELD_DECL && code != RESULT_DECL)
     {
+      WALK_SUBTREE (DECL_SIZE (*tp));
+      WALK_SUBTREE (DECL_SIZE_UNIT (*tp));
       WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
     }
   else
@@ -2077,23 +2083,20 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
 	case REAL_CST:
 	case VECTOR_CST:
 	case STRING_CST:
-	case REAL_TYPE:
-	case COMPLEX_TYPE:
 	case VECTOR_TYPE:
 	case VOID_TYPE:
-	case BOOLEAN_TYPE:
-	case UNION_TYPE:
-	case ENUMERAL_TYPE:
 	case BLOCK:
-	case RECORD_TYPE:
 	case PLACEHOLDER_EXPR:
 	case SSA_NAME:
+	case FIELD_DECL:
+	case RESULT_DECL:
 	  /* None of thse have subtrees other than those already walked
 	     above.  */
 	  break;
 
 	case POINTER_TYPE:
 	case REFERENCE_TYPE:
+	case COMPLEX_TYPE:
 	  WALK_SUBTREE_TAIL (TREE_TYPE (*tp));
 	  break;
 
@@ -2126,6 +2129,7 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
 
 	case METHOD_TYPE:
 	  WALK_SUBTREE (TYPE_METHOD_BASETYPE (*tp));
+
 	  /* Fall through.  */
 
 	case FUNCTION_TYPE:
@@ -2139,12 +2143,43 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
 	  }
 	  break;
 
+	case RECORD_TYPE:
+	case UNION_TYPE:
+	case QUAL_UNION_TYPE:
+	  {
+	    tree field;
+
+	    for (field = TYPE_FIELDS (*tp); field; field = TREE_CHAIN (field))
+	      {
+		/* We would like to look at the type of the field, but we
+		   can easily get infinite recursion.  So assume it's
+		   pointed to elsewhere in the tree.  Also, ignore things that
+		   aren't fields.  */
+		if (TREE_CODE (field) != FIELD_DECL)
+		  continue;
+
+		WALK_SUBTREE (DECL_FIELD_OFFSET (field));
+		WALK_SUBTREE (DECL_SIZE (field));
+		WALK_SUBTREE (DECL_SIZE_UNIT (field));
+		if (code == QUAL_UNION_TYPE)
+		  WALK_SUBTREE (DECL_QUALIFIER (field));
+	      }
+	  }
+	  break;
+
 	case ARRAY_TYPE:
-	  WALK_SUBTREE (TREE_TYPE (*tp));
+	  /* Don't follow this nodes's type if a pointer for fear that we'll
+	     have infinite recursion.  Those types are uninteresting anyway. */
+	  if (!POINTER_TYPE_P (TREE_TYPE (*tp))
+	      && TREE_CODE (TREE_TYPE (*tp)) != OFFSET_TYPE)
+	    WALK_SUBTREE (TREE_TYPE (*tp));
 	  WALK_SUBTREE_TAIL (TYPE_DOMAIN (*tp));
 
+	case BOOLEAN_TYPE:
+	case ENUMERAL_TYPE:
 	case INTEGER_TYPE:
 	case CHAR_TYPE:
+	case REAL_TYPE:
 	  WALK_SUBTREE (TYPE_MIN_VALUE (*tp));
 	  WALK_SUBTREE_TAIL (TYPE_MAX_VALUE (*tp));
 
@@ -2166,8 +2201,8 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
 		/* Walk the DECL_INITIAL and DECL_SIZE.  We don't want to walk
 		   into declarations that are just mentioned, rather than
 		   declared; they don't really belong to this part of the tree.
-		   And, we can see cycles: the initializer for a declaration can
-		   refer to the declaration itself.  */
+		   And, we can see cycles: the initializer for a declaration
+		   can refer to the declaration itself.  */
 		WALK_SUBTREE (DECL_INITIAL (decl));
 		WALK_SUBTREE (DECL_SIZE (decl));
 		WALK_SUBTREE (DECL_SIZE_UNIT (decl));
@@ -2185,7 +2220,9 @@ walk_tree (tree *tp, walk_tree_fn func, void *data, void *htab_)
 	  break;
 
 	default:
-	  abort ();
+	  /* ??? This could be a language-defined node.  We really should make
+	     a hook for it, but right now just ignore it.  */
+	  break;
 	}
     }
 
diff --git a/gcc/tree-mudflap.c b/gcc/tree-mudflap.c
index 732ef5e4106ba7a89182cd4d7f4e957bc42c3538..6181bb6ab13ad3f3cca282a3848a04490b06dd9e 100644
--- a/gcc/tree-mudflap.c
+++ b/gcc/tree-mudflap.c
@@ -463,7 +463,7 @@ mf_build_check_statement_for (tree addr, tree size,
              (flag_mudflap_threads ? mf_cache_mask_decl : mf_cache_mask_decl_l));
   t = build (ARRAY_REF,
              TREE_TYPE (TREE_TYPE (mf_cache_array_decl)),
-             mf_cache_array_decl, t);
+             mf_cache_array_decl, t, NULL_TREE, NULL_TREE);
   t = build1 (ADDR_EXPR, mf_cache_structptr_type, t);
   t = build (MODIFY_EXPR, void_type_node, mf_elem, t);
   SET_EXPR_LOCUS (t, locus);
@@ -487,7 +487,7 @@ mf_build_check_statement_for (tree addr, tree size,
   /* Construct t <-- '__mf_elem->low  > __mf_base'.  */
   t = build (COMPONENT_REF, mf_uintptr_type,
              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
-             TYPE_FIELDS (mf_cache_struct_type));
+             TYPE_FIELDS (mf_cache_struct_type), NULL_TREE);
   t = build (GT_EXPR, boolean_type_node, t, mf_base);
 
   /* Construct '__mf_elem->high < __mf_base + sizeof(T) - 1'.
@@ -501,7 +501,7 @@ mf_build_check_statement_for (tree addr, tree size,
 
   u = build (COMPONENT_REF, mf_uintptr_type,
              build1 (INDIRECT_REF, mf_cache_struct_type, mf_elem),
-             TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)));
+             TREE_CHAIN (TYPE_FIELDS (mf_cache_struct_type)), NULL_TREE);
 
   v = convert (mf_uintptr_type,
 	       size_binop (MINUS_EXPR, size, size_one_node));
@@ -660,14 +660,14 @@ mf_xform_derefs_1 (block_stmt_iterator *iter, tree *tp,
            things the hard way with PLUS.  */
         if (DECL_BIT_FIELD_TYPE (field))
           {
-            size = bitsize_int (BITS_PER_UNIT);
-            size = size_binop (CEIL_DIV_EXPR, DECL_SIZE (field), size);
-            size = convert (sizetype, size);
+	    if (TREE_CODE (DECL_SIZE_UNIT (field)) == INTEGER_CST)
+	      size = DECL_SIZE_UNIT (field);
 
             addr = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
-            addr = convert (ptr_type_node, addr);
+            addr = fold_convert (ptr_type_node, addr);
             addr = fold (build (PLUS_EXPR, ptr_type_node,
-                                addr, byte_position (field)));
+                                addr, fold_convert (ptr_type_node,
+						    byte_position (field))));
           }
         else
           {
diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c
index 24d3e74b74691ae95897cb8c1abcd1e3517c428f..1f32e1f60f9520564d678c3d0b51bb696532681c 100644
--- a/gcc/tree-nested.c
+++ b/gcc/tree-nested.c
@@ -157,8 +157,13 @@ static tree
 build_addr (tree exp)
 {
   tree base = exp;
-  while (TREE_CODE (base) == COMPONENT_REF || TREE_CODE (base) == ARRAY_REF)
+
+  if (TREE_CODE (base) == REALPART_EXPR || TREE_CODE (base) == IMAGPART_EXPR)
     base = TREE_OPERAND (base, 0);
+  else
+    while (handled_component_p (base))
+      base = TREE_OPERAND (base, 0);
+
   if (DECL_P (base))
     TREE_ADDRESSABLE (base) = 1;
 
@@ -550,6 +555,7 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp)
       break;
     case CATCH_EXPR:
       walk_stmts (wi, &CATCH_BODY (t));
+      break;
     case EH_FILTER_EXPR:
       walk_stmts (wi, &EH_FILTER_FAILURE (t));
       break;
@@ -657,7 +663,7 @@ get_static_chain (struct nesting_info *info, tree target_context,
 	  tree field = get_chain_field (i);
 
 	  x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
-	  x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+	  x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
 	  x = init_tmp_var (info, x, tsi);
 	}
     }
@@ -691,14 +697,14 @@ get_frame_field (struct nesting_info *info, tree target_context,
 	  tree field = get_chain_field (i);
 
 	  x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
-	  x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+	  x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
 	  x = init_tmp_var (info, x, tsi);
 	}
 
       x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x);
     }
 
-  x = build (COMPONENT_REF, TREE_TYPE (field), x, field);
+  x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE);
   return x;
 }
 
@@ -800,10 +806,13 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case ARRAY_REF:
+    case ARRAY_RANGE_REF:
       wi->val_only = false;
       walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL);
       wi->val_only = true;
       walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL);
+      walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, NULL);
+      walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi, NULL);
       break;
 
     case BIT_FIELD_REF:
@@ -932,10 +941,13 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data)
       break;
 
     case ARRAY_REF:
+    case ARRAY_RANGE_REF:
       wi->val_only = false;
       walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL);
       wi->val_only = true;
       walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL);
+      walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, NULL);
+      walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi, NULL);
       break;
 
     case BIT_FIELD_REF:
@@ -1242,7 +1254,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 	    x = p;
 
 	  y = build (COMPONENT_REF, TREE_TYPE (field),
-		     root->frame_decl, field);
+		     root->frame_decl, field, NULL_TREE);
 	  x = build (MODIFY_EXPR, TREE_TYPE (field), y, x);
 	  append_to_statement_list (x, &stmt_list);
 	}
@@ -1252,9 +1264,8 @@ finalize_nesting_tree_1 (struct nesting_info *root)
      from chain_decl.  */
   if (root->chain_field)
     {
-      tree x;
-      x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
-		 root->frame_decl, root->chain_field);
+      tree x = build (COMPONENT_REF, TREE_TYPE (root->chain_field),
+		      root->frame_decl, root->chain_field, NULL_TREE);
       x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root));
       append_to_statement_list (x, &stmt_list);
     }
@@ -1281,7 +1292,7 @@ finalize_nesting_tree_1 (struct nesting_info *root)
 	  arg = tree_cons (NULL, x, arg);
 
 	  x = build (COMPONENT_REF, TREE_TYPE (field),
-		     root->frame_decl, field);
+		     root->frame_decl, field, NULL_TREE);
 	  x = build_addr (x);
 	  arg = tree_cons (NULL, x, arg);
 
diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c
index 28c802381d077dbe9f157fdcb3f8d1fc51e65383..f19afdde6a1a6ce1a982f0b996bc310bea4a4d65 100644
--- a/gcc/tree-outof-ssa.c
+++ b/gcc/tree-outof-ssa.c
@@ -1763,17 +1763,20 @@ discover_nonconstant_array_refs_r (tree * tp, int *walk_subtrees,
 
   if (TYPE_P (t) || DECL_P (t))
     *walk_subtrees = 0;
-  else if (TREE_CODE (t) == ARRAY_REF)
+  else if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
     {
-      while ((TREE_CODE (t) == ARRAY_REF
+      while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
 	      && is_gimple_min_invariant (TREE_OPERAND (t, 1)))
 	     || (TREE_CODE (t) == COMPONENT_REF
 		 || TREE_CODE (t) == BIT_FIELD_REF
 		 || TREE_CODE (t) == REALPART_EXPR
-		 || TREE_CODE (t) == IMAGPART_EXPR))
+		 || TREE_CODE (t) == IMAGPART_EXPR
+		 || TREE_CODE (t) == VIEW_CONVERT_EXPR
+		 || TREE_CODE (t) == NOP_EXPR
+		 || TREE_CODE (t) == CONVERT_EXPR))
 	t = TREE_OPERAND (t, 0);
 
-      if (TREE_CODE (t) == ARRAY_REF)
+      if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
 	{
 	  t = get_base_address (t);
 	  if (t && DECL_P (t))
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 4b8d2d400805a3e9076ae013c63cb0a596122912..52aa18194171c920e6f62fd2dbd412bb03db639f 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -392,6 +392,7 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
 
     case RECORD_TYPE:
     case UNION_TYPE:
+    case QUAL_UNION_TYPE:
       /* Print the name of the structure.  */
       if (TREE_CODE (node) == RECORD_TYPE)
 	pp_string (buffer, "struct ");
@@ -404,11 +405,6 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
 	print_struct_decl (buffer, node, spc, flags);
       break;
 
-    case QUAL_UNION_TYPE:
-      NIY;
-      break;
-
-
     case LANG_TYPE:
       NIY;
       break;
@@ -598,6 +594,14 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
 	pp_character (buffer, ')');
       pp_string (buffer, str);
       dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+      if (TREE_OPERAND (node, 2)
+	  && TREE_CODE (TREE_OPERAND (node, 2)) != INTEGER_CST)
+	{
+	  pp_string (buffer, "{off: ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 2),
+			     spc, flags, false);
+	  pp_character (buffer, '}');
+	}
       break;
 
     case BIT_FIELD_REF:
@@ -615,6 +619,7 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       break;
 
     case ARRAY_REF:
+    case ARRAY_RANGE_REF:
       op0 = TREE_OPERAND (node, 0);
       if (op_prio (op0) < op_prio (node))
 	pp_character (buffer, '(');
@@ -623,11 +628,23 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
 	pp_character (buffer, ')');
       pp_character (buffer, '[');
       dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+      if (TREE_CODE (node) == ARRAY_RANGE_REF)
+	pp_string (buffer, " ...");
       pp_character (buffer, ']');
-      break;
 
-    case ARRAY_RANGE_REF:
-      NIY;
+      if ((TREE_OPERAND (node, 2)
+	   && TREE_CODE (TREE_OPERAND (node, 2)) != INTEGER_CST)
+	  || (TREE_OPERAND (node, 3)
+	      && TREE_CODE (TREE_OPERAND (node, 3)) != INTEGER_CST))
+	{
+	  pp_string (buffer, "{lb: ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 2),
+			     spc, flags, false);
+	  pp_string (buffer, " sz: ");
+	  dump_generic_node (buffer, TREE_OPERAND (node, 3),
+			     spc, flags, false);
+	  pp_character (buffer, '}');
+	}
       break;
 
     case CONSTRUCTOR:
@@ -1490,10 +1507,10 @@ print_struct_decl (pretty_printer *buffer, tree node, int spc, int flags)
       INDENT (spc);
       if (TREE_CODE (node) == RECORD_TYPE)
 	pp_string (buffer, "struct ");
-      else if (TREE_CODE (node) == UNION_TYPE)
+      else if ((TREE_CODE (node) == UNION_TYPE
+		|| TREE_CODE (node) == QUAL_UNION_TYPE))
 	pp_string (buffer, "union ");
-      else
-	NIY;
+
       dump_generic_node (buffer, TYPE_NAME (node), spc, 0, false);
     }
 
@@ -1515,8 +1532,8 @@ print_struct_decl (pretty_printer *buffer, tree node, int spc, int flags)
 	   Maybe this could be solved by looking at the scope in which the
 	   structure was declared.  */
 	if (TREE_TYPE (tmp) != node
-	    || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE &&
-		TREE_TYPE (TREE_TYPE (tmp)) != node))
+	    || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE
+		&& TREE_TYPE (TREE_TYPE (tmp)) != node))
 	  {
 	    print_declaration (buffer, tmp, spc+2, flags);
 	    pp_newline (buffer);
@@ -1656,6 +1673,7 @@ op_prio (tree op)
 
     case CALL_EXPR:
     case ARRAY_REF:
+    case ARRAY_RANGE_REF:
     case COMPONENT_REF:
       return 15;
 
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index b5e4735e29dcf219f49187691e859ac0a6390491..bbb5942db2446ebfc862723ddf302e465e93d219 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -621,7 +621,7 @@ csc_build_component_ref (tree base, tree field)
       break;
     }
 
-  return build (COMPONENT_REF, TREE_TYPE (field), base, field);
+  return build (COMPONENT_REF, TREE_TYPE (field), base, field, NULL_TREE);
 }
 
 /* Similarly for REALPART_EXPR and IMAGPART_EXPR for complex types.  */
@@ -1011,7 +1011,7 @@ scalarize_call_expr (block_stmt_iterator *si_p)
   /* Scalarize the return value, if any.  */
   if (TREE_CODE (stmt) == MODIFY_EXPR)
     {
-      tree var = TREE_OPERAND (stmt, 0);
+      tree var = get_base_address (TREE_OPERAND (stmt, 0));
 
       /* If the LHS of the assignment is a scalarizable structure, insert
 	 copies into the scalar replacements after the call.  */
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index fb7a8258f699af0970063f9ada6040209289d529..658a2cb9061be819002a733aaf293d8f3b4132e5 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -1041,40 +1041,43 @@ dump_lattice_value (FILE *outf, const char *prefix, value val)
 tree
 widen_bitfield (tree val, tree field, tree var)
 {
-  unsigned var_size, field_size;
+  unsigned HOST_WIDE_INT var_size, field_size;
   tree wide_val;
   unsigned HOST_WIDE_INT mask;
-  unsigned i;
+  unsigned int i;
 
-  var_size = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE ((var))));
-  field_size = TREE_INT_CST_LOW (DECL_SIZE (field));
+  /* We can only do this if the size of the type and field and VAL are
+     all constants representable in HOST_WIDE_INT.  */
+  if (!host_integerp (TYPE_SIZE (TREE_TYPE (var)), 1)
+      || !host_integerp (DECL_SIZE (field), 1)
+      || !host_integerp (val, 0))
+    return NULL_TREE;
+
+  var_size = tree_low_cst (TYPE_SIZE (TREE_TYPE (var)), 1);
+  field_size = tree_low_cst (DECL_SIZE (field), 1);
 
   /* Give up if either the bitfield or the variable are too wide.  */
   if (field_size > HOST_BITS_PER_WIDE_INT || var_size > HOST_BITS_PER_WIDE_INT)
-    return NULL;
+    return NULL_TREE;
 
 #if defined ENABLE_CHECKING
   if (var_size < field_size)
     abort ();
 #endif
 
-  /* If VAL is not an integer constant, then give up.  */
-  if (TREE_CODE (val) != INTEGER_CST)
-    return NULL;
-
-  /* If the sign bit of the value is not set, or the field's type is
-     unsigned, then just mask off the high order bits of the value.  */
-  if ((TREE_INT_CST_LOW (val) & (1 << (field_size - 1))) == 0
-      || DECL_UNSIGNED (field))
+  /* If the sign bit of the value is not set or the field's type is unsigned,
+     just mask off the high order bits of the value.  */
+  if (DECL_UNSIGNED (field)
+      || !(tree_low_cst (val, 0) & (((HOST_WIDE_INT)1) << (field_size - 1))))
     {
       /* Zero extension.  Build a mask with the lower 'field_size' bits
 	 set and a BIT_AND_EXPR node to clear the high order bits of
 	 the value.  */
       for (i = 0, mask = 0; i < field_size; i++)
-	mask |= 1 << i;
+	mask |= ((HOST_WIDE_INT) 1) << i;
 
       wide_val = build (BIT_AND_EXPR, TREE_TYPE (var), val, 
-			build_int_2 (mask, 0));
+			fold_convert (TREE_TYPE (var), build_int_2 (mask, 0)));
     }
   else
     {
@@ -1082,10 +1085,10 @@ widen_bitfield (tree val, tree field, tree var)
 	 bits set and a BIT_IOR_EXPR to set the high order bits of the
 	 value.  */
       for (i = 0, mask = 0; i < (var_size - field_size); i++)
-	mask |= 1 << (var_size - i - 1);
+	mask |= ((HOST_WIDE_INT) 1) << (var_size - i - 1);
 
       wide_val = build (BIT_IOR_EXPR, TREE_TYPE (var), val,
-			build_int_2 (mask, 0));
+			fold_convert (TREE_TYPE (var), build_int_2 (mask, 0)));
     }
 
   return fold (wide_val);
@@ -1493,10 +1496,26 @@ likely_value (tree stmt)
 static tree
 maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
 {
-  unsigned HOST_WIDE_INT lquo, lrem;
-  HOST_WIDE_INT hquo, hrem;
-  tree elt_size, min_idx, idx;
-  tree array_type, elt_type;
+  tree min_idx, idx, elt_offset = integer_zero_node;
+  tree array_type, elt_type, elt_size;
+
+  /* If BASE is an ARRAY_REF, we can pick up another offset (this time
+     measured in units of the size of elements type) from that ARRAY_REF).
+     We can't do anything if either is variable.
+
+     The case we handle here is *(&A[N]+O).  */
+  if (TREE_CODE (base) == ARRAY_REF)
+    {
+      tree low_bound = array_ref_low_bound (base);
+
+      elt_offset = TREE_OPERAND (base, 1);
+      if (TREE_CODE (low_bound) != INTEGER_CST
+	  || TREE_CODE (elt_offset) != INTEGER_CST)
+	return NULL_TREE;
+
+      elt_offset = int_const_binop (MINUS_EXPR, elt_offset, low_bound, 0);
+      base = TREE_OPERAND (base, 0);
+    }
 
   /* Ignore stupid user tricks of indexing non-array variables.  */
   array_type = TREE_TYPE (base);
@@ -1506,37 +1525,62 @@ maybe_fold_offset_to_array_ref (tree base, tree offset, tree orig_type)
   if (!lang_hooks.types_compatible_p (orig_type, elt_type))
     return NULL_TREE;
 	
-  /* Whee.  Ignore indexing of variable sized types.  */
+  /* If OFFSET and ELT_OFFSET are zero, we don't care about the size of the
+     element type (so we can use the alignment if it's not constant).
+     Otherwise, compute the offset as an index by using a division.  If the
+     division isn't exact, then don't do anything.  */
   elt_size = TYPE_SIZE_UNIT (elt_type);
-  if (TREE_CODE (elt_size) != INTEGER_CST)
-    return NULL_TREE;
+  if (integer_zerop (offset))
+    {
+      if (TREE_CODE (elt_size) != INTEGER_CST)
+	elt_size = size_int (TYPE_ALIGN (elt_type));
 
-  /* If the division isn't exact, then don't do anything.  Equally
-     invalid as the above indexing of non-array variables.  */
-  if (div_and_round_double (TRUNC_DIV_EXPR, 1,
-			    TREE_INT_CST_LOW (offset),
-			    TREE_INT_CST_HIGH (offset),
-			    TREE_INT_CST_LOW (elt_size),
-			    TREE_INT_CST_HIGH (elt_size),
-			    &lquo, &hquo, &lrem, &hrem)
-      || lrem || hrem)
-    return NULL_TREE;
-  idx = build_int_2_wide (lquo, hquo);
+      idx = integer_zero_node;
+    }
+  else
+    {
+      unsigned HOST_WIDE_INT lquo, lrem;
+      HOST_WIDE_INT hquo, hrem;
+
+      if (TREE_CODE (elt_size) != INTEGER_CST
+	  || div_and_round_double (TRUNC_DIV_EXPR, 1,
+				   TREE_INT_CST_LOW (offset),
+				   TREE_INT_CST_HIGH (offset),
+				   TREE_INT_CST_LOW (elt_size),
+				   TREE_INT_CST_HIGH (elt_size),
+				   &lquo, &hquo, &lrem, &hrem)
+	  || lrem || hrem)
+	return NULL_TREE;
 
-  /* Re-bias the index by the min index of the array type.  */
-  min_idx = TYPE_DOMAIN (TREE_TYPE (base));
-  if (min_idx)
+      idx = build_int_2_wide (lquo, hquo);
+    }
+
+  /* Assume the low bound is zero.  If there is a domain type, get the
+     low bound, if any, convert the index into that type, and add the
+     low bound.  */
+  min_idx = integer_zero_node;
+  if (TYPE_DOMAIN (array_type))
     {
-      min_idx = TYPE_MIN_VALUE (min_idx);
-      if (min_idx)
-	{
-	  idx = convert (TREE_TYPE (min_idx), idx);
-	  if (!integer_zerop (min_idx))
-	    idx = int_const_binop (PLUS_EXPR, idx, min_idx, 1);
-	}
+      if (TYPE_MIN_VALUE (TYPE_DOMAIN (array_type)))
+	min_idx = TYPE_MIN_VALUE (TYPE_DOMAIN (array_type));
+      else
+	min_idx = fold_convert (TYPE_DOMAIN (array_type), min_idx);
+
+      if (TREE_CODE (min_idx) != INTEGER_CST)
+	return NULL_TREE;
+
+      idx = fold_convert (TYPE_DOMAIN (array_type), idx);
+      elt_offset = fold_convert (TYPE_DOMAIN (array_type), elt_offset);
     }
 
-  return build (ARRAY_REF, orig_type, base, idx);
+  if (!integer_zerop (min_idx))
+    idx = int_const_binop (PLUS_EXPR, idx, min_idx, 0);
+  if (!integer_zerop (elt_offset))
+    idx = int_const_binop (PLUS_EXPR, idx, elt_offset, 0);
+
+  return build (ARRAY_REF, orig_type, base, idx, min_idx,
+		size_int (tree_low_cst (elt_size, 1)
+			  / (TYPE_ALIGN (elt_type) / BITS_PER_UNIT)));
 }
 
 /* A subroutine of fold_stmt_r.  Attempts to fold *(S+O) to S.X.
@@ -1617,7 +1661,7 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
 	{
 	  if (base_is_ptr)
 	    base = build1 (INDIRECT_REF, record_type, base);
-	  t = build (COMPONENT_REF, field_type, base, f);
+	  t = build (COMPONENT_REF, field_type, base, f, NULL_TREE);
 	  return t;
 	}
 
@@ -1639,7 +1683,7 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
      nonzero offset into them.  Recurse and hope for a valid match.  */
   if (base_is_ptr)
     base = build1 (INDIRECT_REF, record_type, base);
-  base = build (COMPONENT_REF, field_type, base, f);
+  base = build (COMPONENT_REF, field_type, base, f, NULL_TREE);
 
   t = maybe_fold_offset_to_array_ref (base, offset, orig_type);
   if (t)
@@ -1697,8 +1741,12 @@ maybe_fold_stmt_indirect (tree expr, tree base, tree offset)
       if (t)
 	return t;
 
-      /* Fold *&B to B.  */
-      if (integer_zerop (offset))
+      /* Fold *&B to B.  We can only do this if EXPR is the same type
+	 as BASE.  We can't do this if EXPR is the element type of an array
+	 and BASE is the array.  */
+      if (integer_zerop (offset)
+	  && lang_hooks.types_compatible_p (TREE_TYPE (base),
+					    TREE_TYPE (expr)))
 	return base;
     }
   else
@@ -1803,6 +1851,9 @@ maybe_fold_stmt_addition (tree expr)
 	  min_idx = TYPE_MIN_VALUE (min_idx);
 	  if (min_idx)
 	    {
+	      if (TREE_CODE (min_idx) != INTEGER_CST)
+		break;
+
 	      array_idx = convert (TREE_TYPE (min_idx), array_idx);
 	      if (!integer_zerop (min_idx))
 		array_idx = int_const_binop (MINUS_EXPR, array_idx,
diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c
index 9eb0bd12e11f86e8840072bdbb7ebac5240e195e..08330abd51f9934577a342f9a6565dbadc62c6a6 100644
--- a/gcc/tree-ssa-operands.c
+++ b/gcc/tree-ssa-operands.c
@@ -897,30 +897,18 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops)
   code = TREE_CODE (expr);
   class = TREE_CODE_CLASS (code);
 
-  /* Expressions that make no memory references.  */
-  if (class == 'c'
-      || class == 't'
-      || code == BLOCK
-      || code == FUNCTION_DECL
-      || code == EXC_PTR_EXPR
-      || code == FILTER_EXPR
-      || code == LABEL_DECL)
-    return;
-
   /* We could have the address of a component, array member, etc which
      has interesting variable references.  */
   if (code == ADDR_EXPR)
     {
-      enum tree_code subcode = TREE_CODE (TREE_OPERAND (expr, 0));
-
       /* Taking the address of a variable does not represent a
 	 reference to it, but the fact that STMT takes its address will be
 	 of interest to some passes (e.g. alias resolution).  */
       add_stmt_operand (expr_p, stmt, 0, NULL);
 
-      /* If the address is invariant, there may be no interesting variable
-	 references inside.  */
-      if (is_gimple_min_invariant (expr))
+      /* If the address is constant (invariant is not sufficient), there will
+	 be no interesting variable references inside.  */
+      if (TREE_CONSTANT (expr))
 	return;
 
       /* There should be no VUSEs created, since the referenced objects are
@@ -930,12 +918,22 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops)
       flags |= opf_no_vops;
 
       /* Avoid recursion.  */
-      code = subcode;
-      class = TREE_CODE_CLASS (code);
       expr_p = &TREE_OPERAND (expr, 0);
       expr = *expr_p;
+      code =  TREE_CODE (expr);
+      class = TREE_CODE_CLASS (code);
     }
 
+  /* Expressions that make no memory references.  */
+  if (class == 'c'
+      || class == 't'
+      || code == BLOCK
+      || code == FUNCTION_DECL
+      || code == EXC_PTR_EXPR
+      || code == FILTER_EXPR
+      || code == LABEL_DECL)
+    return;
+
   /* If we found a variable, add it to DEFS or USES depending on the
      operand flags.  */
   if (SSA_VAR_P (expr))
@@ -1043,7 +1041,7 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops)
   /* Treat array references as references to the virtual variable
      representing the array.  The virtual variable for an ARRAY_REF
      is the VAR_DECL for the array.  */
-  if (code == ARRAY_REF)
+  if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
     {
       /* Add the virtual variable for the ARRAY_REF to VDEFS or VUSES
 	 according to the value of IS_DEF.  Recurse if the LHS of the
@@ -1054,6 +1052,8 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops)
 	get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops);
 
       get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_none, prev_vops);
+      get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none, prev_vops);
+      get_expr_operands (stmt, &TREE_OPERAND (expr, 3), opf_none, prev_vops);
       return;
     }
 
@@ -1078,6 +1078,8 @@ get_expr_operands (tree stmt, tree *expr_p, int flags, voperands_t prev_vops)
       else
 	get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags, prev_vops);
 
+      if (code == COMPONENT_REF)
+	get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none, prev_vops);
       return;
     }
 
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 5ba8f65b510cf357df200268f46b6d5688666445..89d40a1b918ee9dc9f3d5d9bfc1a8c1ee8631ac6 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -473,20 +473,11 @@ set_is_used (tree t)
       if (SSA_VAR_P (t))
 	break;
 
-      switch (TREE_CODE (t))
-	{
-	case ARRAY_REF:
-	case COMPONENT_REF:
-	case REALPART_EXPR:
-	case IMAGPART_EXPR:
-	case BIT_FIELD_REF:
-	case INDIRECT_REF:
+      if (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR)
+	t = TREE_OPERAND (t, 0);
+      else
+	while (handled_component_p (t))
 	  t = TREE_OPERAND (t, 0);
-	  break;
-
-	default:
-	  return;
-	}
     }
 
   if (TREE_CODE (t) == SSA_NAME)
diff --git a/gcc/tree.c b/gcc/tree.c
index fb1f4d77b6955520e5c8b6e1cf01994fc7f76bca..716bc35fa70cdf2ca48cbfb5d82f42e4571ecba8 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1927,7 +1927,8 @@ substitute_in_expr (tree exp, tree f, tree r)
      if (op0 == TREE_OPERAND (exp, 0))
        return exp;
 
-     new = fold (build2 (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1)));
+     new = fold (build (code, TREE_TYPE (exp), op0, TREE_OPERAND (exp, 1),
+			NULL_TREE));
    }
   else
     switch (TREE_CODE_CLASS (code))
@@ -2157,7 +2158,7 @@ stabilize_reference (tree ref)
     case COMPONENT_REF:
       result = build_nt (COMPONENT_REF,
 			 stabilize_reference (TREE_OPERAND (ref, 0)),
-			 TREE_OPERAND (ref, 1));
+			 TREE_OPERAND (ref, 1), NULL_TREE);
       break;
 
     case BIT_FIELD_REF:
@@ -2170,13 +2171,15 @@ stabilize_reference (tree ref)
     case ARRAY_REF:
       result = build_nt (ARRAY_REF,
 			 stabilize_reference (TREE_OPERAND (ref, 0)),
-			 stabilize_reference_1 (TREE_OPERAND (ref, 1)));
+			 stabilize_reference_1 (TREE_OPERAND (ref, 1)),
+			 TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
       break;
 
     case ARRAY_RANGE_REF:
       result = build_nt (ARRAY_RANGE_REF,
 			 stabilize_reference (TREE_OPERAND (ref, 0)),
-			 stabilize_reference_1 (TREE_OPERAND (ref, 1)));
+			 stabilize_reference_1 (TREE_OPERAND (ref, 1)),
+			 TREE_OPERAND (ref, 2), TREE_OPERAND (ref, 3));
       break;
 
     case COMPOUND_EXPR:
@@ -2292,41 +2295,77 @@ stabilize_reference_1 (tree e)
 
 /* Low-level constructors for expressions.  */
 
-/* A helper function for build1 and constant folders.
-   Set TREE_CONSTANT and TREE_INVARIANT for an ADDR_EXPR.  */
+/* A helper function for build1 and constant folders.  Set TREE_CONSTANT,
+   TREE_INVARIANT, and TREE_SIDE_EFFECTS for an ADDR_EXPR.  */
 
 void
 recompute_tree_invarant_for_addr_expr (tree t)
 {
-  tree node = TREE_OPERAND (t, 0);
-  bool tc = false, ti = false;
+  tree node;
+  bool tc = true, ti = true, se = false;
 
-  /* Addresses of constants and static variables are constant;
-     all other decl addresses are invariant.  */
-  if (staticp (node))
-    tc = ti = true;
-  else
+  /* We started out assuming this address is both invariant and constant, but
+     does not have side effects.  Now go down any handled components and see if
+     any of them involve offsets that are either non-constant or non-invariant.
+     Also check for side-effects.
+
+     ??? Note that this code makes no attempt to deal with the case where
+     taking the address of something causes a copy due to misalignment.  */
+
+#define UPDATE_TITCSE(NODE)  \
+do { tree _node = (NODE); \
+     if (_node && !TREE_INVARIANT (_node)) ti = false; \
+     if (_node && !TREE_CONSTANT (_node)) tc = false; \
+     if (_node && TREE_SIDE_EFFECTS (_node)) se = true; } while (0)
+
+  for (node = TREE_OPERAND (t, 0); handled_component_p (node);
+       node = TREE_OPERAND (node, 0))
     {
-      /* Step past constant offsets.  */
-      while (1)
+      /* If the first operand doesn't have an ARRAY_TYPE, this is a bogus
+	 array reference (probably made temporarily by the G++ front end),
+	 so ignore all the operands.  */
+      if ((TREE_CODE (node) == ARRAY_REF
+	   || TREE_CODE (node) == ARRAY_RANGE_REF)
+	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (node, 0))) == ARRAY_TYPE)
 	{
-	  if (TREE_CODE (node) == COMPONENT_REF
-	      && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL
-	      && ! DECL_BIT_FIELD (TREE_OPERAND (node, 1)))
-	    ;
-	  else if (TREE_CODE (node) == ARRAY_REF
-	           && TREE_CONSTANT (TREE_OPERAND (node, 1)))
-	    ;
-	  else
-	    break;
-	  node = TREE_OPERAND (node, 0);
+	  UPDATE_TITCSE (TREE_OPERAND (node, 1));
+	  UPDATE_TITCSE (array_ref_low_bound (node));
+	  UPDATE_TITCSE (array_ref_element_size (node));
 	}
-      if (DECL_P (node))
-        ti = true;
+      /* Likewise, just because this is a COMPONENT_REF doesn't mean we have a
+	 FIELD_DECL, apparently.  The G++ front end can put something else
+	 there, at least temporarily.  */
+      else if (TREE_CODE (node) == COMPONENT_REF
+	       && TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL)
+	UPDATE_TITCSE (component_ref_field_offset (node));
+      else if (TREE_CODE (node) == BIT_FIELD_REF)
+	UPDATE_TITCSE (TREE_OPERAND (node, 2));
+    }
+	      
+  /* Now see what's inside.  If it's an INDIRECT_REF, copy our properties from
+     it.  If it's a decl, it's definitely invariant and it's constant if the
+     decl is static.  (Taking the address of a volatile variable is not
+     volatile.)  If it's a constant, the address is both invariant and
+     constant.  Otherwise it's neither.  */
+  if (TREE_CODE (node) == INDIRECT_REF)
+    UPDATE_TITCSE (node);
+  else if (DECL_P (node))
+    {
+      if (!staticp (node))
+	tc = false;
+    }
+  else if (TREE_CODE_CLASS (TREE_CODE (node)) == 'c')
+    ;
+  else
+    {
+      ti = tc = false;
+      se |= TREE_SIDE_EFFECTS (node);
     }
 
   TREE_CONSTANT (t) = tc;
   TREE_INVARIANT (t) = ti;
+  TREE_SIDE_EFFECTS (t) = se;
+#undef UPDATE_TITCSE
 }
 
 /* Build an expression of code CODE, data type TYPE, and operands as
@@ -2429,27 +2468,7 @@ build1_stat (enum tree_code code, tree type, tree node MEM_STAT_DECL)
 
     case ADDR_EXPR:
       if (node)
-	{
-	  recompute_tree_invarant_for_addr_expr (t);
-
-	  /* The address of a volatile decl or reference does not have
-	     side-effects.  But be careful not to ignore side-effects from
-	     other sources deeper in the expression--if node is a _REF and
-	     one of its operands has side-effects, so do we.  */
-	  if (TREE_THIS_VOLATILE (node))
-	    {
-	      TREE_SIDE_EFFECTS (t) = 0;
-	      if (!DECL_P (node))
-		{
-		  int i = first_rtl_op (TREE_CODE (node)) - 1;
-		  for (; i >= 0; --i)
-		    {
-		      if (TREE_SIDE_EFFECTS (TREE_OPERAND (node, i)))
-			TREE_SIDE_EFFECTS (t) = 1;
-		    }
-		}
-	    }
-	}
+	recompute_tree_invarant_for_addr_expr (t);
       break;
 
     default:
@@ -2516,6 +2535,8 @@ build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL)
   TREE_CONSTANT (t) = constant;
   TREE_INVARIANT (t) = invariant;
   TREE_SIDE_EFFECTS (t) = side_effects;  
+  TREE_THIS_VOLATILE (t)
+    = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
 
   return t;
 }
@@ -2565,6 +2586,8 @@ build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
     }
 
   TREE_SIDE_EFFECTS (t) = side_effects;  
+  TREE_THIS_VOLATILE (t)
+    = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
 
   return t;
 }
@@ -2595,6 +2618,8 @@ build4_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
   PROCESS_ARG(3);
 
   TREE_SIDE_EFFECTS (t) = side_effects;  
+  TREE_THIS_VOLATILE (t)
+    = TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
 
   return t;
 }
@@ -4457,8 +4482,8 @@ get_unwidened (tree op, tree for_type)
 	  && (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1)))
 	  && (! uns || final_prec <= innerprec || unsignedp))
 	{
-	  win = build2 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
-			TREE_OPERAND (op, 1));
+	  win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
+			TREE_OPERAND (op, 1), NULL_TREE);
 	  TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
 	  TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
 	}
@@ -4523,7 +4548,8 @@ get_narrower (tree op, int *unsignedp_ptr)
       /* Since type_for_size always gives an integer type.  */
       && TREE_CODE (TREE_TYPE (op)) != REAL_TYPE
       /* Ensure field is laid out already.  */
-      && DECL_SIZE (TREE_OPERAND (op, 1)) != 0)
+      && DECL_SIZE (TREE_OPERAND (op, 1)) != 0
+      && host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
     {
       unsigned HOST_WIDE_INT innerprec
 	= tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
@@ -4546,8 +4572,8 @@ get_narrower (tree op, int *unsignedp_ptr)
 	{
 	  if (first)
 	    uns = DECL_UNSIGNED (TREE_OPERAND (op, 1));
-	  win = build2 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
-			TREE_OPERAND (op, 1));
+	  win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
+			TREE_OPERAND (op, 1), NULL_TREE);
 	  TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
 	  TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
 	}
diff --git a/gcc/tree.def b/gcc/tree.def
index 5afe7658a5e131f65f488152106e25ebb8737d6f..12a6394c5b109ef6936455a9517419b598c4e63c 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -354,9 +354,11 @@ DEFTREECODE (TRANSLATION_UNIT_DECL, "translation_unit_decl", 'd', 0)
 /* References to storage.  */
 
 /* Value is structure or union component.
-   Operand 0 is the structure or union (an expression);
-   operand 1 is the field (a node of type FIELD_DECL).  */
-DEFTREECODE (COMPONENT_REF, "component_ref", 'r', 2)
+   Operand 0 is the structure or union (an expression).
+   Operand 1 is the field (a node of type FIELD_DECL).
+   Operand 2, if present, is the value of DECL_FIELD_OFFSET, measured
+   in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT.  */
+DEFTREECODE (COMPONENT_REF, "component_ref", 'r', 3)
 
 /* Reference to a group of bits within an object.  Similar to COMPONENT_REF
    except the position is given explicitly rather than via a FIELD_DECL.
@@ -374,13 +376,16 @@ DEFTREECODE (INDIRECT_REF, "indirect_ref", 'r', 1)
 DEFTREECODE (BUFFER_REF, "buffer_ref", 'r', 1)
 
 /* Array indexing.
-   Operand 0 is the array; operand 1 is a (single) array index.  */
-DEFTREECODE (ARRAY_REF, "array_ref", 'r', 2)
+   Operand 0 is the array; operand 1 is a (single) array index.
+   Operand 2, if present, is a copy of TYPE_MIN_VALUE of the index.
+   Operand 3, if present, is the element size, measured in units of
+   the alignment of the element type.  */
+DEFTREECODE (ARRAY_REF, "array_ref", 'r', 4)
 
 /* Likewise, except that the result is a range ("slice") of the array.  The
    starting index of the resulting array is taken from operand 1 and the size
    of the range is taken from the type of the expression.  */
-DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", 'r', 2)
+DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", 'r', 4)
 
 /* Vtable indexing.  Carries data useful for emitting information
    for vtable garbage collection.
diff --git a/gcc/tree.h b/gcc/tree.h
index d5d87b69d655959a9a653d64822f9394e483aa53..9b753a341f6ef2d3dad02ce82d8c2697d30ead57 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3166,6 +3166,21 @@ extern tree get_inner_reference (tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
 
 extern int handled_component_p (tree);
 
+/* Return a tree of sizetype representing the size, in bytes, of the element
+   of EXP, an ARRAY_REF.  */
+
+extern tree array_ref_element_size (tree);
+
+/* Return a tree representing the lower bound of the array mentioned in
+   EXP, an ARRAY_REF.  */
+
+extern tree array_ref_low_bound (tree);
+
+/* Return a tree representing the offset, in bytes, of the field referenced
+   by EXP.  This does not include any offset in DECL_FIELD_BIT_OFFSET.  */
+
+extern tree component_ref_field_offset (tree);
+
 /* Given a DECL or TYPE, return the scope in which it was declared, or
    NUL_TREE if there is no containing scope.  */