This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tree-ssa] error reporting patch, redux


So I eventually went with solution #1, as that matched up with
plans that Jason had wrt speeding up the gimplifier.  And in
the process, I think I implemented much of that at the same time.

The patch is generated with -b, since there are several places
where brace levels were insertted or removed.


r~



        * gimplify.c (gimplify_*): Return gimplify_status.
        (gimple_add_tmp_var): Set seen_in_bind_expr.
        (gimplify_bind_expr): Likewise.  Kill if 0 code.
        (gimplify_return_expr): Cope with error marks.
        (gimple_push_cleanup): Do nothing if errors seen.
        (gimplify_expr): Cope with error marks.  Use gimplify_status to
        decide when to exit the main loop.  Zap statements with errors.
        (gimplify_body): Return void.
        (keep_function_tree_in_gimple_form): Don't exit on errors.
        (gimplify_function_tree): Return bool.  Don't exit on errors.
        * langhooks.c (lhd_gimplify_expr): Return GS_UNHANDLED.
        * langhooks.h (struct lang_hooks): Update docs for gimplify_expr.
        * tree-optimize.c (optimize_function_tree): Don't exit on errors.
        Move delete_tree_cfg call outside optimization clause.
        (tree_rest_of_compilation): Don't exit on errors.
        * tree-simple.h (enum gimplify_status): New.
        (gimplify_expr, gimplify_stmt, gimplify_body): Update.
        * tree-ssa.c (rewrite_out_of_ssa): Move delete_tree_cfg call to
        optimize_function_tree.
        * tree.h (struct tree_decl): Add seen_in_bind_expr.
        (gimplify_function_tree): Update.
        * c-common.c (c_add_case_label): Unify three error exit paths.
        Create a normal label, not a case label to suppress unreachable
        code warning.
        * c-simplify.c (c_build_bind_expr): Don't create an empty bind
        body.  Pass entire bind_expr to gimplify_stmt.
        (gimplify_block): Don't abort on mismatches if errors seen.
        (gimplify_expr_stmt): Cope with error marks.
        (gimplify_decl_stmt): Likewise.
        (c_gimplify_expr): Return gimplify_status.
cp/
        * cp-simplify.c (cp_gimplify_expr): Return gimplify_status.
fortran/
        * f95-lang.c (gfc_gimplify_expr): Return gimplify_status.
java/
        * java-gimplify.c (java_gimplify_expr): Return gimplify_status.

Index: gcc/c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.344.2.42
diff -u -p -b -r1.344.2.42 c-common.c
--- gcc/c-common.c	18 Oct 2003 23:59:35 -0000	1.344.2.42
+++ gcc/c-common.c	23 Oct 2003 16:25:26 -0000
@@ -3889,13 +3889,7 @@ c_add_case_label (splay_tree cases, tree
   /* If there was an error processing the switch condition, bail now
      before we get more confused.  */
   if (!cond || cond == error_mark_node)
-    {
-      /* Add a label anyhow so that the back-end doesn't think that
-	 the beginning of the switch is unreachable.  */
-      if (!cases->root)
-	add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
-      return error_mark_node;
-    }
+    goto error_out;
 
   if ((low_value && TREE_TYPE (low_value)
        && POINTER_TYPE_P (TREE_TYPE (low_value)))
@@ -3921,11 +3915,7 @@ c_add_case_label (splay_tree cases, tree
 
   /* If an error has occurred, bail out now.  */
   if (low_value == error_mark_node || high_value == error_mark_node)
-    {
-      if (!cases->root)
-	add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
-      return error_mark_node;
-    }
+    goto error_out;
 
   /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
      really a case range, even though it was written that way.  Remove
@@ -3998,8 +3988,7 @@ c_add_case_label (splay_tree cases, tree
 	  error ("multiple default labels in one switch");
 	  error ("%Jthis is the first default label", duplicate);
 	}
-      if (!cases->root)
-	add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
+      goto error_out;
     }
 
   /* Add a CASE_LABEL to the statement-tree.  */
@@ -4010,6 +3999,17 @@ c_add_case_label (splay_tree cases, tree
 		     (splay_tree_value) case_label);
 
   return case_label;
+
+ error_out:
+  /* Add a label so that the back-end doesn't think that the beginning o
+     the switch is unreachable.  Note that we do not add a case label, as
+     that just leads to duplicates and thence to aborts later on.  */
+  if (!cases->root)
+    {
+      tree t = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+      add_stmt (build_stmt (LABEL_STMT, t));
+    }
+  return error_mark_node;
 }
 
 /* Finish an expression taking the address of LABEL (an
Index: gcc/c-simplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/c-simplify.c,v
retrieving revision 1.1.4.74
diff -u -p -b -r1.1.4.74 c-simplify.c
--- gcc/c-simplify.c	16 Oct 2003 18:39:45 -0000	1.1.4.74
+++ gcc/c-simplify.c	23 Oct 2003 16:25:27 -0000
@@ -359,12 +359,12 @@ c_build_bind_expr (tree block, tree body
 	}
     }
 
+  if (!body)
+    body = build_empty_stmt ();
+
   bind = build (BIND_EXPR, void_type_node, decls, body, block);
   TREE_SIDE_EFFECTS (bind) = 1;
-
-  gimple_push_bind_expr (bind);
-  c_gimplify_stmt (&BIND_EXPR_BODY (bind));
-  gimple_pop_bind_expr ();
+  gimplify_stmt (&bind);
 
   return bind;
 }
@@ -384,13 +384,22 @@ gimplify_block (tree *stmt_p, tree *next
   int stmt_lineno;
 
   if (!SCOPE_BEGIN_P (*stmt_p))
+    {
+      /* Can wind up mismatched with syntax errors.  */
+      if (!errorcount && !sorrycount)
     abort ();
+      *stmt_p = NULL;
+      return;
+    }
 
   block = SCOPE_STMT_BLOCK (*stmt_p);
 
   /* Find the matching ending SCOPE_STMT.  */
   depth = 1;
   for (p = &TREE_CHAIN (*stmt_p);; p = &TREE_CHAIN (*p))
+    {
+      if (*p == NULL)
+	break;
     if (TREE_CODE (*p) == SCOPE_STMT)
       {
 	if (SCOPE_BEGIN_P (*p))
@@ -398,13 +407,23 @@ gimplify_block (tree *stmt_p, tree *next
 	else if (--depth == 0)
 	  break;
       }
+    }
+  if (*p)
+    {
   if (SCOPE_STMT_BLOCK (*p) != block)
     abort ();
 
   stmt_lineno = STMT_LINENO (*p);
-
   *next_p = TREE_CHAIN (*p);
   *p = NULL_TREE;
+    }
+  else
+    {
+      /* Can wind up mismatched with syntax errors.  */
+      if (!errorcount && !sorrycount)
+	abort ();
+      stmt_lineno = input_line;
+    }
 
   bind = c_build_bind_expr (block, TREE_CHAIN (*stmt_p));
   *stmt_p = bind;
@@ -445,6 +464,9 @@ gimplify_expr_stmt (tree *stmt_p)
 {
   tree stmt = EXPR_STMT_EXPR (*stmt_p);
 
+  if (stmt == error_mark_node)
+    stmt = NULL;
+
   /* Gimplification of a statement expression will nullify the
      statement if all its side effects are moved to *PRE_P and *POST_P.
 
@@ -826,6 +848,12 @@ gimplify_decl_stmt (tree *stmt_p)
   tree pre = NULL_TREE;
   tree post = NULL_TREE;
 
+  if (TREE_TYPE (decl) == error_mark_node)
+    {
+      *stmt_p = NULL;
+      return;
+    }
+
   if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
     {
       tree init = DECL_INITIAL (decl);
@@ -903,23 +931,22 @@ c_gimplify_expr (tree *expr_p, tree *pre
   enum tree_code code = TREE_CODE (*expr_p);
 
   if (STATEMENT_CODE_P (code))
-    {
       c_gimplify_stmt (expr_p);
-      return 1;
-    }
   else switch (code)
     {
     case COMPOUND_LITERAL_EXPR:
       gimplify_compound_literal_expr (expr_p);
-      return 1;
+      break;
 
     case STMT_EXPR:
       gimplify_stmt_expr (expr_p);
-      return 1;
+      break;
 
     default:
-      return 0;
+      return GS_UNHANDLED;
     }
+
+  return GS_OK;
 }
 
 /* Gimplify a STMT_EXPR.  EXPR_P points to the expression to gimplify.
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimplify.c,v
retrieving revision 1.1.2.100
diff -u -p -b -r1.1.2.100 gimplify.c
--- gcc/gimplify.c	22 Oct 2003 20:01:56 -0000	1.1.2.100
+++ gcc/gimplify.c	23 Oct 2003 16:25:29 -0000
@@ -322,7 +322,6 @@ create_tmp_alias_var (tree type, const c
   TREE_USED (tmp_var) = 1;
   TREE_THIS_VOLATILE (tmp_var) = TYPE_VOLATILE (type);
 
-
   return tmp_var;
 }
 
@@ -486,6 +485,8 @@ gimple_add_tmp_var (tree tmp)
     abort ();
 
   DECL_CONTEXT (tmp) = current_function_decl;
+  tmp->decl.seen_in_bind_expr = 1;
+
   if (gimplify_ctxp)
     {
       TREE_CHAIN (tmp) = gimplify_ctxp->temps;
@@ -705,8 +706,8 @@ voidify_wrapper_expr (tree wrapper)
   return NULL_TREE;
 }
 
-/* Prepare calls to builtins to SAVE and RESTORE the stack as well as temporary
-   through that they comunicate.  */
+/* Prepare calls to builtins to SAVE and RESTORE the stack as well as
+   temporary through that they comunicate.  */
 
 static void
 build_stack_save_restore (tree *save, tree *restore)
@@ -726,12 +727,17 @@ build_stack_save_restore (tree *save, tr
 
 /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
 
-static void
+static enum gimplify_status
 gimplify_bind_expr (tree *expr_p, tree *pre_p)
 {
   tree bind_expr = *expr_p;
   tree temp = voidify_wrapper_expr (bind_expr);
   bool old_save_stack = gimplify_ctxp->save_stack;
+  tree t;
+
+  /* Mark variables seen in this bind expr.  */
+  for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
+    t->decl.seen_in_bind_expr = 1;
 
   gimple_push_bind_expr (bind_expr);
   gimplify_ctxp->save_stack = false;
@@ -759,14 +765,10 @@ gimplify_bind_expr (tree *expr_p, tree *
     {
       *expr_p = temp;
       add_tree (bind_expr, pre_p);
+      return GS_OK;
     }
-
-#if 0
-  if (!BIND_EXPR_VARS (bind_expr))
-    *expr_p = BIND_EXPR_BODY (bind_expr);
   else
-    recalculate_side_effects (bind_expr);
-#endif
+    return GS_ALL_DONE;
 }
 
 /* Gimplify a RETURN_EXPR.  If the expression to be returned is not a
@@ -776,16 +778,19 @@ gimplify_bind_expr (tree *expr_p, tree *
    PRE_P points to the list where side effects that must happen before
    STMT should be stored.  */
 
-static void
+static enum gimplify_status
 gimplify_return_expr (tree stmt, tree *pre_p)
 {
   tree ret_expr = TREE_OPERAND (stmt, 0);
   tree_stmt_iterator si;
-
-  if (ret_expr && TREE_CODE (ret_expr) != RESULT_DECL)
-    {
       tree result;
 
+  if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
+    return GS_ALL_DONE;
+
+  if (ret_expr == error_mark_node)
+    return GS_ERROR;
+
       if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
 	result = NULL_TREE;
       else
@@ -807,7 +812,7 @@ gimplify_return_expr (tree stmt, tree *p
 	TREE_OPERAND (stmt, 0) = NULL_TREE;
       else if (ret_expr == TREE_OPERAND (stmt, 0))
 	/* It was already GIMPLE.  */
-	return;
+    return GS_ALL_DONE;
       else
 	{
 	  /* If there's still a MODIFY_EXPR of the RESULT_DECL after
@@ -850,14 +855,14 @@ gimplify_return_expr (tree stmt, tree *p
 	}
 
       add_tree (ret_expr, pre_p);
-    }
+  return GS_ALL_DONE;
 }
 
 /* Gimplify a LOOP_EXPR.  Normally this just involves gimplifying the body
-   and replacing the LOOP_EXPR with goto, but if the loop contains an EXIT_EXPR,
-   we need to append a label for it to jump to.  */
+   and replacing the LOOP_EXPR with goto, but if the loop contains an
+   EXIT_EXPR, we need to append a label for it to jump to.  */
 
-static void
+static enum gimplify_status
 gimplify_loop_expr (tree *expr_p)
 {
   tree saved_label = gimplify_ctxp->exit_label;
@@ -878,18 +883,21 @@ gimplify_loop_expr (tree *expr_p)
     }
 
   gimplify_ctxp->exit_label = saved_label;
+
+  return GS_ALL_DONE;
 }
 
 /* Gimplify a SWITCH_EXPR, and collect a TREE_VEC of the labels it can
    branch to.  */
 
-static void
+static enum gimplify_status
 gimplify_switch_expr (tree *expr_p, tree *pre_p)
 {
   tree label_vec;
   int i, len;
   varray_type labels;
   tree switch_expr = *expr_p;
+  enum gimplify_status ret;
 
   varray_type saved_labels = gimplify_ctxp->case_labels;
   if (SWITCH_LABELS (switch_expr))
@@ -901,10 +909,10 @@ gimplify_switch_expr (tree *expr_p, tree
   /* We don't want to risk changing the type of the switch condition,
      lest stmt.c get the wrong impression about enumerations.  */
   if (TREE_CODE (SWITCH_COND (switch_expr)) == NOP_EXPR)
-    gimplify_expr (&TREE_OPERAND (SWITCH_COND (switch_expr), 0), pre_p,
-		   NULL, is_gimple_val, fb_rvalue);
+    ret = gimplify_expr (&TREE_OPERAND (SWITCH_COND (switch_expr), 0),
+			 pre_p, NULL, is_gimple_val, fb_rvalue);
   else
-    gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL,
+    ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL,
 		   is_gimple_val, fb_rvalue);
 
   gimplify_stmt (&SWITCH_BODY (switch_expr));
@@ -919,6 +927,8 @@ gimplify_switch_expr (tree *expr_p, tree
       SWITCH_LABELS (*expr_p) = label_vec;
     }
   gimplify_ctxp->case_labels = saved_labels;
+
+  return ret;
 }
 
 static void
@@ -931,7 +941,7 @@ gimple_add_case_label (tree expr)
 /* Gimplify a LABELED_BLOCK_EXPR into a LABEL_EXPR following
    a (possibly empty) body.  */
 
-static void
+static enum gimplify_status
 gimplify_labeled_block_expr (tree *expr_p)
 {
   tree body = LABELED_BLOCK_BODY (*expr_p);
@@ -943,11 +953,13 @@ gimplify_labeled_block_expr (tree *expr_
   if (body != NULL_TREE)
     t = build (COMPOUND_EXPR, void_type_node, body, t);
   *expr_p = t;
+
+  return GS_OK;
 }
 
 /* Gimplify a EXIT_BLOCK_EXPR into a GOTO_EXPR.  */
 
-static void
+static enum gimplify_status
 gimplify_exit_block_expr (tree *expr_p)
 {
   tree labeled_block = TREE_OPERAND (*expr_p, 0);
@@ -962,6 +974,8 @@ gimplify_exit_block_expr (tree *expr_p)
 
   label = LABELED_BLOCK_LABEL (labeled_block);
   *expr_p = build1 (GOTO_EXPR, void_type_node, label);
+
+  return GS_OK;
 }
 
 /* Build a GOTO to the LABEL_DECL pointed to by LABEL_P, building it first
@@ -989,7 +1003,7 @@ build_and_jump (tree *label_p)
    This also involves building a label to jump to and communicating it to
    gimplify_loop_expr through gimplify_ctxp->exit_label.  */
 
-static void
+static enum gimplify_status
 gimplify_exit_expr (tree *expr_p)
 {
   tree cond = TREE_OPERAND (*expr_p, 0);
@@ -998,6 +1012,8 @@ gimplify_exit_expr (tree *expr_p)
   expr = build_and_jump (&gimplify_ctxp->exit_label);
   expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
   *expr_p = expr;
+
+  return GS_OK;
 }
 
 /* Gimplifies a CONSTRUCTOR node at *EXPR_P.
@@ -1006,15 +1022,23 @@ gimplify_exit_expr (tree *expr_p)
      vals: aggr_init_elt | vals ',' aggr_init_elt
      aggr_init_elt: val | aggr_init  */
 
-static void
+static enum gimplify_status
 gimplify_constructor (tree t, tree *pre_p, tree *post_p)
 {
+  enum gimplify_status ret, tret;
   tree elt_list;
 
+  ret = GS_ALL_DONE;
   for (elt_list = CONSTRUCTOR_ELTS (t); elt_list;
        elt_list = TREE_CHAIN (elt_list))
-    gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
+    {
+      tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
 		   is_gimple_constructor_elt, fb_rvalue);
+      if (tret == GS_ERROR)
+	ret = GS_ERROR;
+    }
+
+  return ret;
 }
 
 /* Break out elements of a constructor used as an initializer into separate
@@ -1023,11 +1047,10 @@ gimplify_constructor (tree t, tree *pre_
    Note that we still need to clear any elements that don't have explicit
    initializers, so if not all elements are initialized we keep the
    original MODIFY_EXPR, we just remove all of the constructor
-   elements.
+   elements.  */
+/* FIXME should also handle vectors.  */
 
-   FIXME should also handle vectors.  */
-
-static int
+static enum gimplify_status
 gimplify_init_constructor (tree *expr_p, tree *pre_p, int want_value)
 {
   tree object = TREE_OPERAND (*expr_p, 0);
@@ -1035,9 +1058,10 @@ gimplify_init_constructor (tree *expr_p,
   tree type = TREE_TYPE (ctor);
 
   if (TREE_CODE (ctor) != CONSTRUCTOR)
-    return 0;
+    return GS_UNHANDLED;
 
-  if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
+  if (TREE_CODE (type) == RECORD_TYPE
+      || TREE_CODE (type) == UNION_TYPE
       || TREE_CODE (type) == QUAL_UNION_TYPE
       || TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -1079,12 +1103,13 @@ gimplify_init_constructor (tree *expr_p,
 
 	      if (TREE_CODE (type) == ARRAY_TYPE)
 		{
-		  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
-		  cref = build (ARRAY_REF, type, object, build_int_2 (i, 0));
+		  tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
+		  cref = build (ARRAY_REF, t, object, build_int_2 (i, 0));
 		}
 	      else
 		{
-		  cref = build (COMPONENT_REF, TREE_TYPE (purpose), object, purpose);
+		  cref = build (COMPONENT_REF, TREE_TYPE (purpose),
+				object, purpose);
 		}
 
 	      init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
@@ -1092,17 +1117,23 @@ gimplify_init_constructor (tree *expr_p,
 	      gimplify_stmt (&init);
 	      add_tree (init, pre_p);
 	    }
+
 	  if (want_value)
+	    {
 	    *expr_p = object;
+	      return GS_OK;
+	    }
 	  else
+	    {
 	    *expr_p = build_empty_stmt ();
-
-	  return 1;
+	      return GS_ALL_DONE;
+	    }
 	}
     }
   else
-    gimplify_constructor (ctor, pre_p, NULL);
-  return 0;
+    return gimplify_constructor (ctor, pre_p, NULL);
+
+  return GS_UNHANDLED;
 }
 
 /* *EXPR_P is a COMPONENT_REF being used as an rvalue.  If its type is
@@ -1147,7 +1178,7 @@ canonicalize_component_ref (tree *expr_p
 /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
    underneath as appropriate.  */
 
-static void
+static enum gimplify_status
 gimplify_conversion (tree *expr_p)
 {  
   /* If a NOP conversion is changing the type of a COMPONENT_REF
@@ -1173,28 +1204,36 @@ gimplify_conversion (tree *expr_p)
 	  == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (*expr_p, 0))))
 	*expr_p = TREE_OPERAND (*expr_p, 0);
     }
+
+  return GS_OK;
 }
 
 /* Reduce MIN/MAX_EXPR to a COND_EXPR for further gimplification.  */
 
-static void
+static enum gimplify_status
 gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
 {
   tree op1 = TREE_OPERAND (*expr_p, 0);
   tree op2 = TREE_OPERAND (*expr_p, 1);
   enum tree_code code;
+  enum gimplify_status r0, r1;
 
   if (TREE_CODE (*expr_p) == MIN_EXPR)
     code = LE_EXPR;
   else
     code = GE_EXPR;
 
-  gimplify_expr (&op1, pre_p, post_p, is_gimple_val, fb_rvalue);
-  gimplify_expr (&op2, pre_p, post_p, is_gimple_val, fb_rvalue);
+  r0 = gimplify_expr (&op1, pre_p, post_p, is_gimple_val, fb_rvalue);
+  r1 = gimplify_expr (&op2, pre_p, post_p, is_gimple_val, fb_rvalue);
 
   *expr_p = build (COND_EXPR, TREE_TYPE (*expr_p),
 		   build (code, boolean_type_node, op1, op2),
 		   op1, op2);
+
+  if (r0 == GS_ERROR || r1 == GS_ERROR)
+    return GS_ERROR;
+  else
+    return GS_OK;
 }
 
 /*  Build an expression for the address of T.  Folds away INDIRECT_REF to
@@ -1221,10 +1260,10 @@ build_addr_expr (tree t)
   return build_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
 }
 
-/* Subroutine of gimplify_compound_lval.  Converts an ARRAY_REF to the
-   equivalent *(&array + offset) form.  */
+/* Subroutine of gimplify_compound_lval and gimplify_array_ref.
+   Converts an ARRAY_REF to the equivalent *(&array + offset) form.  */
 
-static void
+static enum gimplify_status
 gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
 {
   tree array = TREE_OPERAND (*expr_p, 0);
@@ -1235,6 +1274,7 @@ gimplify_array_ref_to_plus (tree *expr_p
   enum tree_code add_code = PLUS_EXPR;
   tree idx = TREE_OPERAND (*expr_p, 1);
   tree minidx, offset, addr, result;
+  enum gimplify_status ret;
 
   /* If the array domain does not start at zero, apply the offset.  */
   minidx = TYPE_DOMAIN (arrtype);
@@ -1266,11 +1306,15 @@ gimplify_array_ref_to_plus (tree *expr_p
   /* Convert the index to a byte offset.  */
   offset = size_binop (MULT_EXPR, size, idx);
 
-  gimplify_expr (&array, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
+  ret = gimplify_expr (&array, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
+  if (ret == GS_ERROR)
+    return ret;
 
   addr = build_addr_expr_with_type (array, ptrtype);
   result = fold (build (add_code, ptrtype, addr, offset));
   *expr_p = build1 (INDIRECT_REF, elttype, result);
+
+  return GS_OK;
 }
 
 /* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
@@ -1295,16 +1339,18 @@ gimplify_array_ref_to_plus (tree *expr_p
    POST_P points to the list where side effects that must happen after
      *EXPR_P should be stored.  */
 
-static void
+static enum gimplify_status
 gimplify_compound_lval (tree *expr_p, tree *pre_p,
 			tree *post_p, int want_lvalue)
 {
   tree *p;
   enum tree_code code;
   varray_type stack;
+  enum gimplify_status ret;
 
 #if defined ENABLE_CHECKING
-  if (TREE_CODE (*expr_p) != ARRAY_REF && TREE_CODE (*expr_p) != COMPONENT_REF
+  if (TREE_CODE (*expr_p) != ARRAY_REF
+      && TREE_CODE (*expr_p) != COMPONENT_REF
       && TREE_CODE (*expr_p) != REALPART_EXPR
       && TREE_CODE (*expr_p) != IMAGPART_EXPR)
     abort ();
@@ -1317,8 +1363,10 @@ gimplify_compound_lval (tree *expr_p, tr
   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;
+       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);
@@ -1339,25 +1387,32 @@ gimplify_compound_lval (tree *expr_p, tr
 
      Gimplify the base, and then process each of the outer nodes from left
      to right.  */
-  gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
+  ret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
 		 code != ARRAY_REF ? fb_either : fb_lvalue);
 
   for (; VARRAY_ACTIVE_SIZE (stack) > 0; VARRAY_POP (stack))
     {
       tree t = VARRAY_TOP_TREE (stack);
       if (TREE_CODE (t) == ARRAY_REF)
+	{
 	/* Gimplify the dimension.  */
-	gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p, is_gimple_val,
-		       fb_rvalue);
-      /* Update TREE_SIDE_EFFECTS.  */
+	  enum gimplify_status tret;
+	  tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
+				is_gimple_val, fb_rvalue);
+	  if (tret == GS_ERROR)
+	    ret = GS_ERROR;
+	}
       recalculate_side_effects (t);
     }
 
-  /* If the outermost expression is a COMPONENT_REF, canonicalize its
-     type.  */
-  if (! want_lvalue
-      && TREE_CODE (*expr_p) == COMPONENT_REF)
+  /* If the outermost expression is a COMPONENT_REF, canonicalize its type.  */
+  if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF)
+    {
     canonicalize_component_ref (expr_p);
+      ret = MIN (ret, GS_OK);
+    }
+
+  return ret;
 }
 
 /*  Re-write the ARRAY_REF node pointed by EXPR_P.
@@ -1372,7 +1427,7 @@ gimplify_compound_lval (tree *expr_p, tr
     argument, so this gimplification uses an INDIRECT_REF of ARRAY_TYPE.
     ARRAY_REF should be extended.  */
 
-static void
+static enum gimplify_status
 gimplify_array_ref (tree *expr_p, tree *pre_p,
 		    tree *post_p, int want_lvalue)
 {
@@ -1380,11 +1435,11 @@ gimplify_array_ref (tree *expr_p, tree *
   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.  */
-    gimplify_array_ref_to_plus (expr_p, pre_p, post_p);
+    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.  */
-    gimplify_compound_lval (expr_p, pre_p, post_p, want_lvalue);
+    return gimplify_compound_lval (expr_p, pre_p, post_p, want_lvalue);
 }
 
 /*  Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=).
@@ -1398,7 +1453,7 @@ gimplify_array_ref (tree *expr_p, tree *
     WANT_VALUE is nonzero iff we want to use the value of this expression
         in another expression.  */
 
-static void
+static enum gimplify_status
 gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
 			int want_value)
 {
@@ -1406,6 +1461,7 @@ gimplify_self_mod_expr (tree *expr_p, tr
   tree lhs, lvalue, rhs, t1;
   bool postfix;
   enum tree_code arith_code;
+  enum gimplify_status ret;
 
   code = TREE_CODE (*expr_p);
 
@@ -1432,30 +1488,38 @@ gimplify_self_mod_expr (tree *expr_p, tr
 
   /* Gimplify the LHS into a GIMPLE lvalue.  */
   lvalue = TREE_OPERAND (*expr_p, 0);
-  gimplify_expr (&lvalue, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+  ret = gimplify_expr (&lvalue, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+  if (ret == GS_ERROR)
+    return ret;
 
   /* Extract the operands to the arithmetic operation.  */
   lhs = lvalue;
   rhs = TREE_OPERAND (*expr_p, 1);
 
+  /* For postfix operator, we evaluate the LHS to an rvalue and then use
+     that as the result value and in the postqueue operation.  */
   if (postfix)
-    /* We want to return the original value.  */
-    gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue);
+    {
+      ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue);
+      if (ret == GS_ERROR)
+	return ret;
+    }
 
   t1 = build (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
   t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
 
   if (postfix)
-    /* If this is a postfix operator, put the assignment in the postqueue
-       and replace the original expression with the (rvalue) LHS.  */
     {
       gimplify_stmt (&t1);
       add_tree (t1, post_p);
       *expr_p = lhs;
+      return GS_ALL_DONE;
     }
   else
-    /* Otherwise, just plug in the assignment and continue.  */
+    {
     *expr_p = t1;
+      return GS_OK;
+    }
 }
 
 /*  Gimplify the CALL_EXPR node pointed by EXPR_P.
@@ -1473,12 +1537,13 @@ gimplify_self_mod_expr (tree *expr_p, tr
     POST_P points to the list where side effects that must happen after
 	*EXPR_P should be stored.  */
 
-static void
+static enum gimplify_status
 gimplify_call_expr (tree *expr_p, tree *pre_p, tree *post_p,
 		    int (*gimple_test_f) (tree))
 {
   tree decl;
   tree arglist;
+  enum gimplify_status ret;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (*expr_p) != CALL_EXPR)
@@ -1517,7 +1582,7 @@ gimplify_call_expr (tree *expr_p, tree *
 	     assume anything about it.  FIXME: Maybe we should add a target
 	     hook for allowing this in the future?  */
 	  mark_not_gimple (expr_p);
-	  return;
+	  return GS_ALL_DONE;
 	}
 
       /* If it is allocation of stack, record the need to restore the memory
@@ -1539,24 +1604,29 @@ gimplify_call_expr (tree *expr_p, tree *
 	     same value, but in a more efficient way.  Return and try
 	     again.  */
 	  *expr_p = new;
-	  return;
+	  return GS_OK;
 	}
     }
 
-  gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 		 is_gimple_val, fb_rvalue);
 
   if (PUSH_ARGS_REVERSED)
     TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
   for (arglist = TREE_OPERAND (*expr_p, 1); arglist;
        arglist = TREE_CHAIN (arglist))
-    gimplify_expr (&TREE_VALUE (arglist), pre_p, post_p, is_gimple_val,
-		   fb_rvalue);
+    {
+      enum gimplify_status t;
+      t = gimplify_expr (&TREE_VALUE (arglist), pre_p, post_p,
+			 is_gimple_val, fb_rvalue);
+      if (t == GS_ERROR)
+	ret = GS_ERROR;
+    }
   if (PUSH_ARGS_REVERSED)
     TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
 
   /* Try this again in case gimplification exposed something.  */
-  if (decl && DECL_BUILT_IN (decl))
+  if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
     {
       tree new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
 
@@ -1566,7 +1636,7 @@ gimplify_call_expr (tree *expr_p, tree *
 	     same value, but in a more efficient way.  Return and try
 	     again.  */
 	  *expr_p = new;
-	  return;
+	  return GS_OK;
 	}
     }
 
@@ -1576,6 +1646,8 @@ gimplify_call_expr (tree *expr_p, tree *
   if (TREE_CODE (*expr_p) == CALL_EXPR
       && (call_expr_flags (*expr_p) & ECF_CONST))
     TREE_SIDE_EFFECTS (*expr_p) = 0;
+
+  return ret;
 }
 
 /* Handle shortcut semantics in the predicate operand of a COND_EXPR by
@@ -1804,8 +1876,12 @@ gimple_boolify (tree expr)
     case TRUTH_ORIF_EXPR:
       /* Also boolify the arguments of truth exprs.  */
       TREE_OPERAND (expr, 1) = gimple_boolify (TREE_OPERAND (expr, 1));
+      /* FALLTHRU */
+
     case TRUTH_NOT_EXPR:
       TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+      /* FALLTHRU */
+
     case EQ_EXPR: case NE_EXPR:
     case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
       /* These expressions always produce boolean results.  */
@@ -1833,20 +1909,27 @@ gimple_boolify (tree expr)
     PRE_P points to the list where side effects that must happen before
         *EXPR_P should be stored.  */
 
-static void
+static enum gimplify_status
 gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
 {
   tree expr = *expr_p;
   tree tmp;
+  enum gimplify_status ret;
 
   /* If this COND_EXPR has a value, copy the values into a temporary within
      the arms.  */
   if (! VOID_TYPE_P (TREE_TYPE (expr)))
     {
       if (target)
+	{
 	tmp = target;
+	  ret = GS_OK;
+	}
       else
+	{
 	tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+	  ret = GS_ALL_DONE;
+	}
 
       /* Build the then clause, 't1 = a;'.  But don't build an assignment
 	 if this branch is void; in C++ it can be, if it's a throw.  */
@@ -1867,7 +1950,7 @@ gimplify_cond_expr (tree *expr_p, tree *
       add_tree (expr, pre_p);
       *expr_p = tmp;
 
-      return;
+      return ret;
     }
 
   /* Make sure the condition has BOOLEAN_TYPE.  */
@@ -1890,12 +1973,13 @@ gimplify_cond_expr (tree *expr_p, tree *
 	  gimple_push_condition ();
 	  gimplify_stmt (expr_p);
 	  gimple_pop_condition (pre_p);
-	  return;
+
+	  return GS_ALL_DONE;
 	}
     }
 
   /* Now do the normal gimplification.  */
-  gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+  ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
 		 is_gimple_condexpr, fb_rvalue);
 
   gimple_push_condition ();
@@ -1905,13 +1989,15 @@ gimplify_cond_expr (tree *expr_p, tree *
 
   gimple_pop_condition (pre_p);
 
-  if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
-    /* OK */;
+  if (ret == GS_ERROR)
+    ;
+  else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+    ret = GS_ALL_DONE;
   else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
     /* Rewrite "if (a); else b" to "if (!a) b"  */
     {
       TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
-      gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+      ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
 		     is_gimple_condexpr, fb_rvalue);
 
       tmp = TREE_OPERAND (expr, 1);
@@ -1923,6 +2009,7 @@ gimplify_cond_expr (tree *expr_p, tree *
     expr = TREE_OPERAND (expr, 0);
 
   *expr_p = expr;
+  return ret;
 }
 
 /*  Gimplify the MODIFY_EXPR node pointed by EXPR_P.
@@ -1940,11 +2027,12 @@ gimplify_cond_expr (tree *expr_p, tree *
     WANT_VALUE is nonzero iff we want to use the value of this expression
         in another expression.  */
 
-static void
-gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, int want_value)
+static enum gimplify_status
+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;
 
 #if defined ENABLE_CHECKING
   if (TREE_CODE (*expr_p) != MODIFY_EXPR
@@ -1952,7 +2040,9 @@ gimplify_modify_expr (tree *expr_p, tree
     abort ();
 #endif
 
-  gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+  ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+  if (ret == GS_ERROR)
+    return ret;
 
   /* If we are initializing something from a TARGET_EXPR, strip the
      TARGET_EXPR and initialize it directly.  */
@@ -1969,10 +2059,8 @@ gimplify_modify_expr (tree *expr_p, tree
   if (TREE_CODE (*from_p) == COND_EXPR
       && TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
     {
-      gimplify_cond_expr (from_p, pre_p, *to_p);
       *expr_p = *from_p;
-      /* Try again.  */
-      return;
+      return gimplify_cond_expr (expr_p, pre_p, *to_p);
     }
 
   /* The distinction between MODIFY_EXPR and INIT_EXPR is no longer
@@ -1980,10 +2068,13 @@ gimplify_modify_expr (tree *expr_p, tree
   if (TREE_CODE (*expr_p) == INIT_EXPR)
     TREE_SET_CODE (*expr_p, MODIFY_EXPR);
 
-  gimplify_expr (from_p, pre_p, post_p, is_gimple_rhs, fb_rvalue);
-
-  if (gimplify_init_constructor (expr_p, pre_p, want_value))
-    return;
+  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, want_value);
+  if (ret != GS_UNHANDLED)
+    return ret;
 
   /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto and
      the LHS is a user variable, then we need to introduce a temporary.
@@ -1993,20 +2084,29 @@ gimplify_modify_expr (tree *expr_p, tree
      only modified if evaluation of the RHS does not throw.
 
      FIXME this should be handled by the is_gimple_rhs predicate.  */
-  if (! is_gimple_tmp_var (*to_p)
-      && (TREE_CODE (*from_p) == CALL_EXPR
+
+  if (is_gimple_tmp_var (*to_p))
+    ret = GS_ALL_DONE;
+  else
+    {
+      if (TREE_CODE (*from_p) == CALL_EXPR
 	  || (flag_non_call_exceptions && tree_could_trap_p (*from_p))
 	  /* If we're dealing with a renamable type, either source or dest
 	     must be a renamed variable.  */
 	  || (is_gimple_reg_type (TREE_TYPE (*from_p))
-	      && !is_gimple_reg (*to_p))))
+	      && !is_gimple_reg (*to_p)))
     gimplify_expr (from_p, pre_p, post_p, is_gimple_val, fb_rvalue);
 
+      ret = want_value ? GS_OK : GS_ALL_DONE;
+    }
+
   if (want_value)
     {
       add_tree (*expr_p, pre_p);
       *expr_p = *to_p;
     }
+
+  return ret;
 }
 
 /*  Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions.  EXPR_P
@@ -2021,16 +2121,18 @@ gimplify_modify_expr (tree *expr_p, tree
     PRE_P points to the list where side effects that must happen before
         *EXPR_P should be stored.  */
 
-static void
+static enum gimplify_status
 gimplify_boolean_expr (tree *expr_p)
 {
   /* Preserve the original type of the expression.  */
   tree type = TREE_TYPE (*expr_p);
+
   *expr_p = build (COND_EXPR, type, *expr_p,
 		   convert (type, boolean_true_node),
 		   convert (type, boolean_false_node));
-}
 
+  return GS_OK;
+}
 
 /*  Gimplifies an expression sequence.  This function gimplifies each
     expression and re-writes the original expression with the last
@@ -2042,7 +2144,7 @@ gimplify_boolean_expr (tree *expr_p)
     POST_P points to the list where the post side effects for the last
         expression in the sequence are emitted.  */
 
-static void
+static enum gimplify_status
 gimplify_compound_expr (tree *expr_p, tree *pre_p)
 {
   tree t;
@@ -2054,6 +2156,7 @@ gimplify_compound_expr (tree *expr_p, tr
     }
 
   *expr_p = t;
+  return GS_OK;
 }
 
 /*  Gimplify a SAVE_EXPR node.  EXPR_P points to the expression to
@@ -2063,9 +2166,10 @@ gimplify_compound_expr (tree *expr_p, tr
     PRE_P points to the list where side effects that must happen before
         *EXPR_P should be stored.  */
 
-static void
+static enum gimplify_status
 gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p)
 {
+  enum gimplify_status ret = GS_ALL_DONE;
   tree val;
 
 #if defined ENABLE_CHECKING
@@ -2085,13 +2189,15 @@ gimplify_save_expr (tree *expr_p, tree *
   else if (TREE_TYPE (val) == void_type_node)
     {
       tree body = TREE_OPERAND (*expr_p, 0);
-      gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none);
+      ret = gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none);
       add_tree (body, pre_p);
       *expr_p = build_empty_stmt ();
     }
   else
     *expr_p = TREE_OPERAND (*expr_p, 0)
       = get_initialized_tmp_var (val, pre_p, post_p);
+
+  return ret;
 }
 
 /*  Re-write the ADDR_EXPR node pointed by EXPR_P
@@ -2107,11 +2213,12 @@ gimplify_save_expr (tree *expr_p, tree *
     POST_P points to the list where side effects that must happen after
 	*EXPR_P should be stored.  */
 
-static void
+static enum gimplify_status
 gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
 {
   tree expr = *expr_p;
   tree op0 = TREE_OPERAND (expr, 0);
+  enum gimplify_status ret;
 
   switch (TREE_CODE (op0))
     {
@@ -2121,11 +2228,13 @@ gimplify_addr_expr (tree *expr_p, tree *
 	 expressions may be generated internally by the compiler (e.g.,
 	 builtins like __builtin_va_end).  */
       *expr_p = TREE_OPERAND (op0, 0);
+      ret = GS_OK;
       break;
 
     case ARRAY_REF:
       /* Fold &a[6] to (&a + 6).  */
-      gimplify_array_ref_to_plus (&TREE_OPERAND (expr, 0), pre_p, post_p);
+      ret = gimplify_array_ref_to_plus (&TREE_OPERAND (expr, 0),
+					pre_p, post_p);
 
       /* This added an INDIRECT_REF.  Fold it away.  */
       op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
@@ -2138,7 +2247,11 @@ gimplify_addr_expr (tree *expr_p, tree *
 	 cast if necessary.  */
       if (TYPE_MAIN_VARIANT (TREE_TYPE (expr))
 	  != TYPE_MAIN_VARIANT (TREE_TYPE (op0)))
+	{
 	op0 = build1 (NOP_EXPR, TREE_TYPE (expr), op0);
+	  if (ret != GS_ERROR)
+	    ret = GS_OK;
+	}
 
       *expr_p = op0;
       break;
@@ -2146,21 +2259,25 @@ gimplify_addr_expr (tree *expr_p, tree *
     default:
       /* We use fb_either here because the C frontend sometimes takes
 	 the address of a call that returns a struct.  */
-      gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p,
+      ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p,
 		     is_gimple_addr_expr_arg, fb_either);
+      if (ret != GS_ERROR)
+	{
       TREE_SIDE_EFFECTS (expr)
 	= TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0));
-
       /* Mark the RHS addressable.  */
       (*lang_hooks.mark_addressable) (TREE_OPERAND (expr, 0));
+	}
       break;
     }
+
+  return ret;
 }
 
 /* Gimplify the operands of an ASM_EXPR.  Input operands should be a gimple
    value; output operands should be a gimple lvalue.  */
 
-static void
+static enum gimplify_status
 gimplify_asm_expr (tree *expr_p, tree *pre_p, tree *post_p)
 {
   tree expr = *expr_p;
@@ -2170,13 +2287,14 @@ gimplify_asm_expr (tree *expr_p, tree *p
   int i;
   tree link;
   const char *constraint;
-  bool allows_mem, allows_reg, is_inout, success;
+  bool allows_mem, allows_reg, is_inout;
+  enum gimplify_status ret, tret;
 
   ASM_STRING (expr)
     = resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr),
 				 ASM_INPUTS (expr));
 
-  success = true;
+  ret = GS_ALL_DONE;
   for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = TREE_CHAIN (link))
     {
       oconstraints[i] = constraint
@@ -2188,11 +2306,12 @@ gimplify_asm_expr (tree *expr_p, tree *p
       if (!allows_reg && allows_mem)
 	(*lang_hooks.mark_addressable) (TREE_VALUE (link));
 
-      if (!gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
-			  is_gimple_lvalue, fb_lvalue | fb_mayfail))
+      tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
+			    is_gimple_lvalue, fb_lvalue | fb_mayfail);
+      if (tret == GS_ERROR)
 	{
 	  error ("invalid lvalue in asm output %d", i);
-	  success = false;
+	  ret = tret;
 	}
 
       if (is_inout && allows_reg)
@@ -2228,21 +2347,24 @@ gimplify_asm_expr (tree *expr_p, tree *p
       if (!allows_reg && allows_mem)
 	{
 	  (*lang_hooks.mark_addressable) (TREE_VALUE (link));
-	  if (!gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
-			      is_gimple_lvalue, fb_lvalue | fb_mayfail))
+	  tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
+			        is_gimple_lvalue, fb_lvalue | fb_mayfail);
+	  if (tret == GS_ERROR)
 	    {
 	      error ("memory input %d is not directly addressable", i);
-	      success = false;
+	      ret = tret;
 	    }
 	}
       else
-	gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
+	{
+	  tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
 		       is_gimple_val, fb_rvalue);
+	  if (tret == GS_ERROR)
+	    ret = tret;
+	}
     }
 
-  /* If we encountered an invalid asm, don't hork the optimizers.  */
-  if (!success)
-    *expr_p = build_empty_stmt ();
+  return ret;
 }
 
 /* Gimplify a CLEANUP_POINT_EXPR.  Currently this works by adding
@@ -2259,7 +2381,7 @@ gimplify_asm_expr (tree *expr_p, tree *p
    having an optimizer to tighten up try/finally regions would be a Good
    Thing.  */
 
-static void
+static enum gimplify_status
 gimplify_cleanup_point_expr (tree *expr_p, tree *pre_p)
 {
   tree_stmt_iterator iter;
@@ -2303,9 +2425,13 @@ gimplify_cleanup_point_expr (tree *expr_
     {
       *expr_p = temp;
       add_tree (body, pre_p);
+      return GS_OK;
     }
   else
+    {
     *expr_p = body;
+      return GS_ALL_DONE;
+    }
 }
 
 /* Insert a cleanup marker for gimplify_cleanup_point_expr.  CLEANUP
@@ -2316,6 +2442,11 @@ gimple_push_cleanup (tree cleanup, tree 
 {
   tree wce;
 
+  /* Errors can result in improperly nested cleanups.  Which results in
+     confusion when trying to resolve the WITH_CLEANUP_EXPR.  */
+  if (errorcount || sorrycount)
+    return;
+
   if (gimple_conditional_context ())
     {
       /* If we're in a conditional context, this is more complex.  We only
@@ -2362,12 +2493,13 @@ gimple_push_cleanup (tree cleanup, tree 
 
 /* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR.  */
 
-static void
+static enum gimplify_status
 gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
 {
   tree targ = *expr_p;
   tree temp = TARGET_EXPR_SLOT (targ);
   tree init = TARGET_EXPR_INITIAL (targ);
+  enum gimplify_status ret;
 
   /* TARGET_EXPR temps aren't part of the enclosing block, so add it to the
      temps list.  */
@@ -2375,7 +2507,10 @@ gimplify_target_expr (tree *expr_p, tree
 
   /* Build up the initialization and add it to pre_p.  */
   init = build (MODIFY_EXPR, void_type_node, temp, init);
-  gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
+  ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
+  if (ret == GS_ERROR)
+    return GS_ERROR;
+
   add_tree (init, pre_p);
 
   /* If needed, push the cleanup for the temp.  */
@@ -2386,6 +2521,7 @@ gimplify_target_expr (tree *expr_p, tree
     }
 
   *expr_p = temp;
+  return GS_OK;
 }
 
 /* Gimplification of expression trees.  */
@@ -2393,10 +2529,10 @@ gimplify_target_expr (tree *expr_p, tree
 /* Gimplify an expression which appears at statement context; usually, this
    means replacing it with a suitably gimple COMPOUND_EXPR.  */
 
-int
+void
 gimplify_stmt (tree *stmt_p)
 {
-  return gimplify_expr (stmt_p, NULL, NULL, is_gimple_stmt, fb_none);
+  gimplify_expr (stmt_p, NULL, NULL, is_gimple_stmt, fb_none);
 }
 
 /*  Gimplifies the expression tree pointed by EXPR_P.  Return 0 if
@@ -2423,9 +2559,12 @@ gimplify_stmt (tree *stmt_p)
 
     FALLBACK tells the function what sort of a temporary we want.  If the 1
         bit is set, an rvalue is OK.  If the 2 bit is set, an lvalue is OK.
-        If both are set, either is OK, but an lvalue is preferable.  */
+        If both are set, either is OK, but an lvalue is preferable.
 
-bool
+    The return value is either GS_ERROR or GS_ALL_DONE, since this function
+    iterates until solution.  */
+
+enum gimplify_status
 gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
 	       int (* gimple_test_f) (tree), fallback_t fallback)
 {
@@ -2436,10 +2575,14 @@ gimplify_expr (tree *expr_p, tree *pre_p
   int is_statement = (pre_p == NULL);
   location_t *locus;
   location_t saved_location;
-  bool ret_ok = true;
+  enum gimplify_status ret;
 
   if (*expr_p == NULL_TREE)
-    return true;
+    return GS_ALL_DONE;
+
+  /* Die, die, die, my darling.  */
+  if (*expr_p == error_mark_node || TREE_TYPE (*expr_p) == error_mark_node)
+    return GS_ERROR;
 
   /* We used to check the predicate here and return immediately if it
      succeeds.  This is wrong; the design is for gimplification to be
@@ -2468,12 +2611,18 @@ gimplify_expr (tree *expr_p, tree *pre_p
       save_expr = *expr_p;
 
       /* Do any language-specific gimplification.  */
-      (*lang_hooks.gimplify_expr) (expr_p, pre_p, post_p);
+      ret = (*lang_hooks.gimplify_expr) (expr_p, pre_p, post_p);
+      if (ret == GS_OK)
+	{
       if (*expr_p == NULL_TREE)
 	break;
       if (*expr_p != save_expr)
 	continue;
+	}
+      else if (ret != GS_UNHANDLED)
+	break;
 
+      ret = GS_OK;
       switch (TREE_CODE (*expr_p))
 	{
 	  /* First deal with the special cases.  */
@@ -2482,23 +2631,26 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	case POSTDECREMENT_EXPR:
 	case PREINCREMENT_EXPR:
 	case PREDECREMENT_EXPR:
-	  gimplify_self_mod_expr (expr_p, pre_p, post_p, fallback != fb_none);
+	  ret = gimplify_self_mod_expr (expr_p, pre_p, post_p,
+					fallback != fb_none);
 	  break;
 
 	case ARRAY_REF:
-	  gimplify_array_ref (expr_p, pre_p, post_p, fallback & fb_lvalue);
+	  ret = gimplify_array_ref (expr_p, pre_p, post_p,
+				    fallback & fb_lvalue);
 	  break;
 
 	case COMPONENT_REF:
-	  gimplify_compound_lval (expr_p, pre_p, post_p, fallback & fb_lvalue);
+	  ret = gimplify_compound_lval (expr_p, pre_p, post_p,
+					fallback & fb_lvalue);
 	  break;
 
 	case COND_EXPR:
-	  gimplify_cond_expr (expr_p, pre_p, NULL_TREE);
+	  ret = gimplify_cond_expr (expr_p, pre_p, NULL_TREE);
 	  break;
 
 	case CALL_EXPR:
-	  gimplify_call_expr (expr_p, pre_p, post_p, gimple_test_f);
+	  ret = gimplify_call_expr (expr_p, pre_p, post_p, gimple_test_f);
 	  break;
 
 	case TREE_LIST:
@@ -2506,46 +2658,55 @@ gimplify_expr (tree *expr_p, tree *pre_p
 
 	case COMPOUND_EXPR:
 	  if (is_statement)
+	    {
 	    foreach_stmt (expr_p, (foreach_stmt_fn *)gimplify_stmt);
+	      ret = GS_ALL_DONE;
+	    }
 	  else
-	    gimplify_compound_expr (expr_p, pre_p);
+	    ret = gimplify_compound_expr (expr_p, pre_p);
 	  break;
 
 	case REALPART_EXPR:
 	case IMAGPART_EXPR:
-	  gimplify_compound_lval (expr_p, pre_p, post_p, fallback & fb_lvalue);
+	  ret = gimplify_compound_lval (expr_p, pre_p, post_p,
+					fallback & fb_lvalue);
 	  break;
 
 	case MODIFY_EXPR:
 	case INIT_EXPR:
-	  gimplify_modify_expr (expr_p, pre_p, post_p, fallback != fb_none);
+	  ret = gimplify_modify_expr (expr_p, pre_p, post_p,
+				      fallback != fb_none);
 	  break;
 
 	case TRUTH_ANDIF_EXPR:
 	case TRUTH_ORIF_EXPR:
-	  gimplify_boolean_expr (expr_p);
+	  ret = gimplify_boolean_expr (expr_p);
 	  break;
 
 	case TRUTH_NOT_EXPR:
 	  TREE_OPERAND (*expr_p, 0)
 	    = gimple_boolify (TREE_OPERAND (*expr_p, 0));
-	  gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 			 is_gimple_val, fb_rvalue);
 	  recalculate_side_effects (*expr_p);
 	  break;
 
 	case ADDR_EXPR:
-	  gimplify_addr_expr (expr_p, pre_p, post_p);
+	  ret = gimplify_addr_expr (expr_p, pre_p, post_p);
 	  break;
 
-	/* va_arg expressions are in GIMPLE form already.  */
 	case VA_ARG_EXPR:
+	  /* va_arg expressions are in GIMPLE form already.  */
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case CONVERT_EXPR:
 	case NOP_EXPR:
 	  if (IS_EMPTY_STMT (*expr_p))
+	    {
+	      ret = GS_ALL_DONE;
 	    break;
+	    }
 
 	  if (VOID_TYPE_P (TREE_TYPE (*expr_p))
 	      || fallback == fb_none)
@@ -2556,24 +2717,26 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	      break;
 	    }
 
-	  gimplify_conversion (expr_p);
+	  ret = gimplify_conversion (expr_p);
+	  if (ret == GS_ERROR)
+	    break;
 	  if (*expr_p != save_expr)
 	    break;
+	  /* FALLTHRU */
 
 	case FIX_TRUNC_EXPR:
 	case FIX_CEIL_EXPR:
 	case FIX_FLOOR_EXPR:
 	case FIX_ROUND_EXPR:
 	  /* unary_expr: ... | '(' cast ')' val | ...  */
-	  gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 			 is_gimple_val, fb_rvalue);
 	  recalculate_side_effects (*expr_p);
 	  break;
 
 	case INDIRECT_REF:
-	  gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 			 is_gimple_reg, fb_rvalue);
-
 	  recalculate_side_effects (*expr_p);
 	  break;
 
@@ -2583,38 +2746,40 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	case STRING_CST:
 	case COMPLEX_CST:
 	case VECTOR_CST:
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case CONST_DECL:
 	  *expr_p = DECL_INITIAL (*expr_p);
 	  break;
 
-	  /* FIXME make this a decl.  */
 	case EXC_PTR_EXPR:
+	  /* FIXME make this a decl.  */
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case BIND_EXPR:
-	  gimplify_bind_expr (expr_p, pre_p);
+	  ret = gimplify_bind_expr (expr_p, pre_p);
 	  break;
 
 	case LOOP_EXPR:
-	  gimplify_loop_expr (expr_p);
+	  ret = gimplify_loop_expr (expr_p);
 	  break;
 
 	case SWITCH_EXPR:
-	  gimplify_switch_expr (expr_p, pre_p);
+	  ret = gimplify_switch_expr (expr_p, pre_p);
 	  break;
 
 	case LABELED_BLOCK_EXPR:
-	  gimplify_labeled_block_expr (expr_p);
+	  ret = gimplify_labeled_block_expr (expr_p);
 	  break;
 
 	case EXIT_BLOCK_EXPR:
-	  gimplify_exit_block_expr (expr_p);
+	  ret = gimplify_exit_block_expr (expr_p);
 	  break;
 
 	case EXIT_EXPR:
-	  gimplify_exit_expr (expr_p);
+	  ret = gimplify_exit_expr (expr_p);
 	  break;
 
 	case GOTO_EXPR:
@@ -2624,37 +2789,40 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	    /* If the target is not LABEL, then it is a computed jump
 	       and the target needs to be gimplified.  */
 	    if (TREE_CODE (GOTO_DESTINATION (*expr_p)) != LABEL_DECL)
-	      gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p, NULL,
-			     is_gimple_val, fb_rvalue);
-
+	      ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p,
+				   NULL, is_gimple_val, fb_rvalue);
+	    else
+	      {
 	    /* If this label is in a different context (function), then
 	       mark it as a nonlocal label and mark its context as
 	       receiving nonlocal gotos.  */
-	    else if (current_function_decl != decl_function_context (dest))
-	      {
 		tree context = decl_function_context (dest);
-
+		if (current_function_decl != context)
+		  {
 		NONLOCAL_LABEL (dest) = 1;
 		FUNCTION_RECEIVES_NONLOCAL_GOTO (context) = 1;
 	      }
-
+	      }
 	    break;
 	  }
 
 	case LABEL_EXPR:
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case CASE_LABEL_EXPR:
 	  gimple_add_case_label (*expr_p);
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case RETURN_EXPR:
-	  gimplify_return_expr (*expr_p, pre_p);
+	  ret = gimplify_return_expr (*expr_p, pre_p);
 	  break;
 
 	case CONSTRUCTOR:
 	  /* Don't reduce this in place; let gimplify_init_constructor work
 	     its magic.  */
+	  ret = GS_ALL_DONE;
 	  break;
 
 	  /* The following are special cases that are not handled by the
@@ -2663,17 +2831,23 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	  /* SAVE_EXPR nodes are converted into a GIMPLE identifier and
 	     eliminated.  */
 	case SAVE_EXPR:
-	  gimplify_save_expr (expr_p, pre_p, post_p);
+	  ret = gimplify_save_expr (expr_p, pre_p, post_p);
 	  break;
 
 	case BIT_FIELD_REF:
-	  gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+	  {
+	    enum gimplify_status r0, r1, r2;
+
+	    r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 		         is_gimple_min_lval, fb_either);
-	  gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+	    r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
 			 is_gimple_val, fb_rvalue);
-	  gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p,
+	    r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p,
 			 is_gimple_val, fb_rvalue);
 	  recalculate_side_effects (*expr_p);
+
+	    ret = MIN (r0, MIN (r1, r2));
+	  }
 	  break;
 
 	case NON_LVALUE_EXPR:
@@ -2682,85 +2856,133 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	  break;
 
 	case ASM_EXPR:
-	  gimplify_asm_expr (expr_p, pre_p, post_p);
+	  ret = gimplify_asm_expr (expr_p, pre_p, post_p);
 	  break;
 
 	case TRY_FINALLY_EXPR:
 	case TRY_CATCH_EXPR:
 	  gimplify_stmt (&TREE_OPERAND (*expr_p, 0));
 	  gimplify_stmt (&TREE_OPERAND (*expr_p, 1));
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case CLEANUP_POINT_EXPR:
-	  gimplify_cleanup_point_expr (expr_p, pre_p);
+	  ret = gimplify_cleanup_point_expr (expr_p, pre_p);
 	  break;
 
 	case TARGET_EXPR:
-	  gimplify_target_expr (expr_p, pre_p, post_p);
+	  ret = gimplify_target_expr (expr_p, pre_p, post_p);
 	  break;
 
 	case CATCH_EXPR:
 	  gimplify_stmt (&CATCH_BODY (*expr_p));
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case EH_FILTER_EXPR:
 	  gimplify_stmt (&EH_FILTER_FAILURE (*expr_p));
+	  ret = GS_ALL_DONE;
 	  break;
 
 	case VTABLE_REF:
 	  /* This moves much of the actual computation out of the
 	     VTABLE_REF.  Perhaps this should be revisited once we want to
 	     do clever things with VTABLE_REFs.  */
-	  gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 			 is_gimple_min_lval, fb_lvalue);
 	  break;
 
 	case MIN_EXPR:
 	case MAX_EXPR:
-	  gimplify_minimax_expr (expr_p, pre_p, post_p);
+	  ret = gimplify_minimax_expr (expr_p, pre_p, post_p);
+	  break;
 
 	case LABEL_DECL:
 	  /* We get here when taking the address of a label.  We mark
 	     the label as "forced"; meaning it can never be removed and
 	     it is a potential target for any computed goto.  */
 	  FORCED_LABEL (*expr_p) = 1;
+	  ret = GS_ALL_DONE;
+	  break;
+
+        case VAR_DECL:
+	  /* ??? If this is a local variable, and it has not been seen in any
+	     outer BIND_EXPR, then it's probably the result of a duplicate
+	     declaration, for which we've already issued an error.  It would
+	     be really nice if the front end wouldn't leak these at all. 
+	     Currently the only known culprit is C++ destructors, as seen
+	     in g++.old-deja/g++.jason/binding.C.  */
+	  tmp = *expr_p;
+	  if (!TREE_STATIC (tmp) && !DECL_EXTERNAL (tmp)
+	      && decl_function_context (tmp) == current_function_decl
+	      && !tmp->decl.seen_in_bind_expr)
+	    {
+#ifdef ENABLE_CHECKING
+	      if (!errorcount && !sorrycount)
+		abort ();
+#endif
+	      ret = GS_ERROR;
+	    }
+	  else
+	    ret = GS_ALL_DONE;
 	  break;
 
 	default:
 	  /* 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')
-	      {
-		gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-			       is_gimple_val, fb_rvalue);
-		recalculate_side_effects (*expr_p);
-	      }
+	    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'
 		     || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
 		     || TREE_CODE (*expr_p) == TRUTH_AND_EXPR
 		     || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
 		     || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR)
 	      {
-		/* binary_expr : val binop val  */
-		gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
-			       is_gimple_val, fb_rvalue);
+	      enum gimplify_status r0, r1;
 
-		gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
-			       is_gimple_val, fb_rvalue);
-		recalculate_side_effects (*expr_p);
+	      r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+				  post_p, is_gimple_val, fb_rvalue);
+	      r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
+				  post_p, is_gimple_val, fb_rvalue);
+
+	      ret = MIN (r0, r1);
 	      }
 	    else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'd'
 		     || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'c')
-	      /* OK */;
+	    {
+	      ret = GS_ALL_DONE;
+	      break;
+	    }
 	    else
 	      /* Fail if we don't know how to handle this tree code.  */
 	      abort ();
+
+	  recalculate_side_effects (*expr_p);
+	  break;
 	  }
+
+      /* If we replaced *expr_p, gimplify again.  */
+      if (ret == GS_OK && (*expr_p == NULL || *expr_p == save_expr))
+	ret = GS_ALL_DONE;
 	}
+  while (ret == GS_OK);
+
+  /* If we encountered an error_mark somewhere nested inside, either
+     stub out the statement or propagate the error back out.  */
+  if (ret == GS_ERROR)
+    {
+      if (is_statement)
+	*expr_p = build_empty_stmt ();
+      goto out;
     }
-  /* If we replaced *expr_p, gimplify again.  */
-  while (*expr_p && *expr_p != save_expr);
+
+#ifdef ENABLE_CHECKING
+  /* This was only valid as a return value from the langhook, which
+     we handled.  Make sure it doesn't escape from any other context.  */
+  if (ret == GS_UNHANDLED)
+    abort ();
+#endif
 
   if (fallback == fb_none && !is_gimple_stmt (*expr_p))
     {
@@ -2848,7 +3070,7 @@ gimplify_expr (tree *expr_p, tree *pre_p
     {
       /* If this is an asm statement, and the user asked for the impossible,
 	 don't abort.  Fail and let gimplify_asm_expr issue an error.  */
-      ret_ok = false;
+      ret = GS_ERROR;
       goto out;
     }
   else
@@ -2873,16 +3095,15 @@ gimplify_expr (tree *expr_p, tree *pre_p
 
  out:
   input_location = saved_location;
-  return ret_ok;
+  return ret;
 }
 
 /* Gimplify the body of statements pointed by BODY_P.  FNDECL is the
    function decl containing BODY.  */
 
-int
+void
 gimplify_body (tree *body_p, tree fndecl)
 {
-  int done;
   location_t saved_location = input_location;
 
   timevar_push (TV_TREE_GIMPLIFY);
@@ -2895,7 +3116,7 @@ gimplify_body (tree *body_p, tree fndecl
   input_location = DECL_SOURCE_LOCATION (fndecl);
 
   /* Gimplify the function's body.  */
-  done = gimplify_stmt (body_p);
+  gimplify_stmt (body_p);
 
   /* Unshare again, in case gimplification was sloppy.  */
   unshare_all_trees (*body_p);
@@ -2914,8 +3135,6 @@ gimplify_body (tree *body_p, tree fndecl
   pop_gimplify_context ();
   timevar_pop (TV_TREE_GIMPLIFY);
   input_location = saved_location;
-
-  return done;
 }
 
 /* Return nonzero if we should keep FNDECL in gimple form during inlining.  */
@@ -2925,11 +3144,6 @@ keep_function_tree_in_gimple_form (tree 
 {
   tree fnbody;
 
-  /* If the program has had errors, then keeping gimple form is not
-     necessary.  */
-  if (errorcount || sorrycount)
-    return 0;
-
   /* If the front-end does not support gimplification, then this
      function was never in gimple form to begin with.  */
   if (lang_hooks.gimplify_expr == lhd_gimplify_expr)
@@ -2947,33 +3161,28 @@ keep_function_tree_in_gimple_form (tree 
 /*  Entry point to the gimplification pass.  FNDECL is the FUNCTION_DECL
     node for the function we want to gimplify.  */
 
-int
+bool
 gimplify_function_tree (tree fndecl)
 {
-  int done;
   tree fnbody;
   tree oldfn;
 
-  /* Don't bother doing anything if the program has errors.  */
-  if (errorcount || sorrycount)
-    return 0;
-
   /* FIXME.  Hack.  If this front end does not support gimplification,
      do nothing.  */
   if (lang_hooks.gimplify_expr == lhd_gimplify_expr)
-    return 0;
+    return false;
 
   fnbody = DECL_SAVED_TREE (fndecl);
   if (fnbody == NULL_TREE)
-    return 0;
+    return false;
 
   oldfn = current_function_decl;
   current_function_decl = fndecl;
 
-  done = gimplify_body (&fnbody, fndecl);
+  gimplify_body (&fnbody, fndecl);
 
   DECL_SAVED_TREE (fndecl) = fnbody;
   current_function_decl = oldfn;
 
-  return done;
+  return true;
 }
Index: gcc/langhooks-def.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/langhooks-def.h,v
retrieving revision 1.34.2.20
diff -u -p -b -r1.34.2.20 langhooks-def.h
--- gcc/langhooks-def.h	18 Oct 2003 23:59:47 -0000	1.34.2.20
+++ gcc/langhooks-def.h	23 Oct 2003 16:25:29 -0000
@@ -90,7 +90,7 @@ extern tree lhd_callgraph_analyze_expr (
 
 
 /* Declarations for tree gimplification hooks.  */
-int lhd_gimplify_expr (tree *, tree *, tree *);
+extern int lhd_gimplify_expr (tree *, tree *, tree *);
 
 #define LANG_HOOKS_NAME			"GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct lang_identifier)
Index: gcc/langhooks.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/langhooks.c,v
retrieving revision 1.31.2.17
diff -u -p -b -r1.31.2.17 langhooks.c
--- gcc/langhooks.c	28 Sep 2003 06:06:29 -0000	1.31.2.17
+++ gcc/langhooks.c	23 Oct 2003 16:25:30 -0000
@@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA.  */
 #include "toplev.h"
 #include "tree.h"
 #include "tree-inline.h"
+#include "tree-simple.h"
 #include "rtl.h"
 #include "insn-config.h"
 #include "integrate.h"
@@ -484,7 +485,7 @@ int
 lhd_gimplify_expr (tree *expr_p ATTRIBUTE_UNUSED, tree *pre_p ATTRIBUTE_UNUSED,
 		   tree *post_p ATTRIBUTE_UNUSED)
 {
-  return 0;
+  return GS_UNHANDLED;
 }
 
 /* lang_hooks.tree_size: Determine the size of a tree with code C,
Index: gcc/langhooks.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/langhooks.h,v
retrieving revision 1.42.2.21
diff -u -p -b -r1.42.2.21 langhooks.h
--- gcc/langhooks.h	18 Oct 2003 23:59:47 -0000	1.42.2.21
+++ gcc/langhooks.h	23 Oct 2003 16:25:30 -0000
@@ -422,9 +422,8 @@ struct lang_hooks
 
   struct lang_hooks_for_rtl_expansion rtl_expand;
 
-  /* Perform language-specific gimplification on the argument.  Returns
-     1 if gimplification is complete, or 0 to use default gimplification
-     semantics.  */
+  /* Perform language-specific gimplification on the argument.  Returns an
+     enum gimplify_status, though we can't see that type here.  */
   int (*gimplify_expr) (tree *, tree *, tree *);
 
   /* Whenever you add entries here, make sure you adjust langhooks-def.h
Index: gcc/tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.57
diff -u -p -b -r1.1.4.57 tree-optimize.c
--- gcc/tree-optimize.c	18 Oct 2003 18:58:41 -0000	1.1.4.57
+++ gcc/tree-optimize.c	23 Oct 2003 16:25:30 -0000
@@ -68,7 +68,7 @@ optimize_function_tree (tree fndecl)
      it in SSA form.  If a pass exposes new symbols or invalidates the SSA
      numbering for existing variables, it should add them to the
      VARS_TO_RENAME bitmap and call rewrite_into_ssa() afterwards.  */
-  if (n_basic_blocks > 0 && ! (errorcount || sorrycount))
+  if (n_basic_blocks > 0)
     {
       sbitmap vars_to_rename;
 
@@ -169,6 +169,8 @@ optimize_function_tree (tree fndecl)
 
       sbitmap_free (vars_to_rename);
     }
+
+  delete_tree_cfg ();
 }
 
 
@@ -236,13 +238,6 @@ tree_rest_of_compilation (tree fndecl, b
 {
   location_t saved_loc;
   tree saved_tree = NULL;
-
-  /* Don't bother doing anything if there are errors.  */
-  if (errorcount || sorrycount)
-    {
-      TREE_ASM_WRITTEN (fndecl) = 1;
-      return;
-    }
 
   timevar_push (TV_EXPAND);
 
Index: gcc/tree-simple.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.h,v
retrieving revision 1.1.4.35
diff -u -p -b -r1.1.4.35 tree-simple.h
--- gcc/tree-simple.h	16 Oct 2003 18:39:45 -0000	1.1.4.35
+++ gcc/tree-simple.h	23 Oct 2003 16:25:30 -0000
@@ -88,9 +88,18 @@ typedef enum fallback_t {
   fb_mayfail = 4,
   fb_either= fb_rvalue | fb_lvalue
 } fallback_t;
-bool gimplify_expr (tree *, tree *, tree *, int (*) (tree), fallback_t);
-int gimplify_stmt (tree *);
-int gimplify_body (tree *, tree);
+
+enum gimplify_status {
+  GS_ERROR	= -2,	/* Something Bad Seen.  */
+  GS_UNHANDLED	= -1,	/* A langhook result for "I dunno".  */
+  GS_OK		= 0,	/* We did something, maybe more to do.  */
+  GS_ALL_DONE	= 1	/* The expression is fully gimplified.  */
+};
+
+enum gimplify_status gimplify_expr (tree *, tree *, tree *,
+				    int (*) (tree), fallback_t);
+void gimplify_stmt (tree *);
+void gimplify_body (tree *, tree);
 
 /* Miscellaneous helpers.  */
 tree get_base_symbol (tree);
Index: gcc/tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.139
diff -u -p -b -r1.1.4.139 tree-ssa.c
--- gcc/tree-ssa.c	22 Oct 2003 20:28:25 -0000	1.1.4.139
+++ gcc/tree-ssa.c	23 Oct 2003 16:25:32 -0000
@@ -1838,7 +1838,6 @@ rewrite_out_of_ssa (tree fndecl, enum tr
 
   /* Flush out flow graph and SSA data.  */
   delete_tree_ssa (fndecl);
-  delete_tree_cfg ();
   delete_var_map (map);
   timevar_pop (TV_TREE_SSA_TO_NORMAL);
 
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.111
diff -u -p -b -r1.342.2.111 tree.h
--- gcc/tree.h	22 Oct 2003 19:38:52 -0000	1.342.2.111
+++ gcc/tree.h	23 Oct 2003 16:25:35 -0000
@@ -2062,8 +2062,9 @@ struct tree_decl GTY(())
   unsigned uninlinable : 1;
   unsigned thread_local_flag : 1;
   unsigned declared_inline_flag : 1;
-  unsigned unused : 3;
-  /* three unused bits.  */
+  unsigned seen_in_bind_expr : 1;
+  unsigned unused : 2;
+  /* two unused bits.  */
 
   unsigned lang_flag_0 : 1;
   unsigned lang_flag_1 : 1;
@@ -3430,7 +3431,7 @@ extern int containing_blocks_have_cleanu
 void optimize_function_tree (tree);
 
 /* In gimplify.c.  */
-extern int gimplify_function_tree (tree);
+extern bool gimplify_function_tree (tree);
 extern const char *get_name (tree);
 extern tree unshare_expr (tree);
 extern int keep_function_tree_in_gimple_form (tree);
Index: gcc/cp/cp-simplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/Attic/cp-simplify.c,v
retrieving revision 1.1.4.16
diff -u -p -b -r1.1.4.16 cp-simplify.c
--- gcc/cp/cp-simplify.c	22 Aug 2003 20:30:20 -0000	1.1.4.16
+++ gcc/cp/cp-simplify.c	23 Oct 2003 16:25:36 -0000
@@ -125,26 +125,26 @@ cp_gimplify_expr (tree *expr_p, tree *pr
     {
     case PTRMEM_CST:
       *expr_p = cplus_expand_constant (*expr_p);
-      return 1;
+      return GS_OK;
 
     case AGGR_INIT_EXPR:
       simplify_aggr_init_expr (expr_p);
-      return 1;
+      return GS_OK;
 
     case THROW_EXPR:
       /* FIXME communicate throw type to backend, probably by moving
 	 THROW_EXPR into ../tree.def.  */
       *expr_p = TREE_OPERAND (*expr_p, 0);
-      return 1;
+      return GS_OK;
 
     case MUST_NOT_THROW_EXPR:
       gimplify_must_not_throw_expr (expr_p, pre_p);
-      return 1;
+      return GS_OK;
 
     case INIT_EXPR:
     case MODIFY_EXPR:
       cp_gimplify_init_expr (expr_p, pre_p, post_p);
-      break;
+      return GS_OK;
 
     case EMPTY_CLASS_EXPR:
       {
@@ -153,17 +153,15 @@ cp_gimplify_expr (tree *expr_p, tree *pr
 	TREE_TYPE (i) = TREE_TYPE (*expr_p);
 	*expr_p = i;
       }
-      return 1;
+      return GS_OK;
 
     case BASELINK:
       *expr_p = BASELINK_FUNCTIONS (*expr_p);
-      return 1;
+      return GS_OK;
 
     default:
-      break;
-    }
-
   return c_gimplify_expr (expr_p, pre_p, post_p);
+    }
 }
 
 /* Gimplify initialization from an AGGR_INIT_EXPR.  */
Index: gcc/fortran/f95-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/Attic/f95-lang.c,v
retrieving revision 1.1.2.12
diff -u -p -b -r1.1.2.12 f95-lang.c
--- gcc/fortran/f95-lang.c	17 Oct 2003 06:44:01 -0000	1.1.2.12
+++ gcc/fortran/f95-lang.c	23 Oct 2003 16:25:36 -0000
@@ -371,7 +371,7 @@ gfc_gimplify_expr (tree * expr_p ATTRIBU
                    tree *post_p ATTRIBUTE_UNUSED)
 {
   /* Just let the gimplifier handle everything.  */
-  return 0;
+  return GS_UNHANDLED;
 }
 
 
Index: gcc/java/java-gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/Attic/java-gimplify.c,v
retrieving revision 1.1.2.6
diff -u -p -b -r1.1.2.6 java-gimplify.c
--- gcc/java/java-gimplify.c	14 Oct 2003 07:14:23 -0000	1.1.2.6
+++ gcc/java/java-gimplify.c	23 Oct 2003 16:25:36 -0000
@@ -67,38 +67,38 @@ java_gimplify_expr (tree *expr_p, tree *
     {
     case BLOCK:
       *expr_p = java_gimplify_block (*expr_p);
-      return 1;
+      break;
 
     case EXPR_WITH_FILE_LOCATION:
       input_location.file = EXPR_WFL_FILENAME (*expr_p);
       input_location.line = EXPR_WFL_LINENO (*expr_p);
       *expr_p = EXPR_WFL_NODE (*expr_p);
       annotate_all_with_locus (expr_p, input_location);
-      return 1;
+      break;
 
     case CASE_EXPR:
       *expr_p = java_gimplify_case_expr (*expr_p);
-      return 1;
+      break;
 
     case DEFAULT_EXPR:
       *expr_p = java_gimplify_default_expr (*expr_p);
-      return 1;
+      break;
 
     case NEW_ARRAY_INIT:
       *expr_p = java_gimplify_new_array_init (*expr_p);
-      return 1;
+      break;
 
     case TRY_EXPR:
       *expr_p = java_gimplify_try_expr (*expr_p);
-      return 1;
+      break;
 
     case JAVA_CATCH_EXPR:
       *expr_p = TREE_OPERAND (*expr_p, 0);
-      return 1;
+      break;
 
     case JAVA_EXC_OBJ_EXPR:
       *expr_p = build_exception_object_ref (TREE_TYPE (*expr_p));
-      return 1;
+      break;
 
     /* These should already be lowered before we get here.  */
     case URSHIFT_EXPR:
@@ -118,15 +118,17 @@ java_gimplify_expr (tree *expr_p, tree *
 
     case COMPOUND_EXPR:
       cleanup_compound_expr (expr_p);
-      return 0;
+      break;
 
     case TRY_FINALLY_EXPR:
       cleanup_try_finally_expr (expr_p);
-      return 0;
+      break;
 
     default:
-      return 0;
+      return GS_UNHANDLED;
     }
+
+  return GS_OK;
 }
 
 static tree


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]