diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ba76cb6a52b282bdc58912563f1ede4a4d71342a..53aa00c82b36ea84eed4bddf10f205d04096b8c8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2005-04-14  Alexandre Oliva  <aoliva@redhat.com>
+
+	* tree-eh.c (lower_try_finally_copy): Generate new code in
+	response to goto_queue entries as if the queue was sorted by
+	index, not pointers.
+	(lower_try_finally_switch): Likewise.
+
 2005-04-14  Richard Henderson  <rth@redhat.com>
 
 	* config/i386/i386.c (ix86_expand_sse_cmp): Split out from ...
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 3dbcfa87ef9ab110fee9757dd79f98fa9dd6808e..90f90611d019b5056358677091bb6f445a64d3fe 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -1038,47 +1038,72 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
     {
       struct goto_queue_node *q, *qe;
       tree return_val = NULL;
-      int return_index;
-      tree *labels;
+      int return_index, index;
+      struct
+      {
+	struct goto_queue_node *q;
+	tree label;
+      } *labels;
 
       if (tf->dest_array)
 	return_index = VARRAY_ACTIVE_SIZE (tf->dest_array);
       else
 	return_index = 0;
-      labels = xcalloc (sizeof (tree), return_index + 1);
+      labels = xcalloc (sizeof (*labels), return_index + 1);
 
       q = tf->goto_queue;
       qe = q + tf->goto_queue_active;
       for (; q < qe; q++)
 	{
-	  int index = q->index < 0 ? return_index : q->index;
-	  tree lab = labels[index];
-	  bool build_p = false;
+	  index = q->index < 0 ? return_index : q->index;
 
-	  if (!lab)
-	    {
-	      labels[index] = lab = create_artificial_label ();
-	      build_p = true;
-	    }
+	  if (!labels[index].q)
+	    labels[index].q = q;
+	}
+
+      for (index = 0; index < return_index + 1; index++)
+	{
+	  tree lab;
+
+	  q = labels[index].q;
+	  if (! q)
+	    continue;
+
+	  lab = labels[index].label = create_artificial_label ();
 
 	  if (index == return_index)
 	    do_return_redirection (q, lab, NULL, &return_val);
 	  else
 	    do_goto_redirection (q, lab, NULL);
 
-	  if (build_p)
-	    {
-	      x = build1 (LABEL_EXPR, void_type_node, lab);
-	      append_to_statement_list (x, &new_stmt);
+	  x = build1 (LABEL_EXPR, void_type_node, lab);
+	  append_to_statement_list (x, &new_stmt);
 
-	      x = lower_try_finally_dup_block (finally, state);
-	      lower_eh_constructs_1 (state, &x);
-	      append_to_statement_list (x, &new_stmt);
+	  x = lower_try_finally_dup_block (finally, state);
+	  lower_eh_constructs_1 (state, &x);
+	  append_to_statement_list (x, &new_stmt);
 
-	      append_to_statement_list (q->cont_stmt, &new_stmt);
-	      maybe_record_in_goto_queue (state, q->cont_stmt);
-	    }
+	  append_to_statement_list (q->cont_stmt, &new_stmt);
+	  maybe_record_in_goto_queue (state, q->cont_stmt);
+	}
+
+      for (q = tf->goto_queue; q < qe; q++)
+	{
+	  tree lab;
+
+	  index = q->index < 0 ? return_index : q->index;
+
+	  if (labels[index].q == q)
+	    continue;
+
+	  lab = labels[index].label;
+
+	  if (index == return_index)
+	    do_return_redirection (q, lab, NULL, &return_val);
+	  else
+	    do_goto_redirection (q, lab, NULL);
 	}
+	
       replace_goto_queue (tf);
       free (labels);
     }
@@ -1194,7 +1219,6 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   q = tf->goto_queue;
   qe = q + tf->goto_queue_active;
   j = last_case_index + tf->may_return;
-  last_case_index += nlabels;
   for (; q < qe; ++q)
     {
       tree mod;
@@ -1217,20 +1241,37 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
 
       case_index = j + q->index;
       if (!TREE_VEC_ELT (case_label_vec, case_index))
-	{
-	  last_case = build (CASE_LABEL_EXPR, void_type_node,
-			     build_int_cst (NULL_TREE, switch_id), NULL,
-			     create_artificial_label ());
-	  TREE_VEC_ELT (case_label_vec, case_index) = last_case;
-
-	  x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case));
-	  append_to_statement_list (x, &switch_body);
-	  append_to_statement_list (q->cont_stmt, &switch_body);
-	  maybe_record_in_goto_queue (state, q->cont_stmt);
-	}
+	TREE_VEC_ELT (case_label_vec, case_index)
+	  = build (CASE_LABEL_EXPR, void_type_node,
+		   build_int_cst (NULL_TREE, switch_id), NULL,
+		   /* We store the cont_stmt in the
+		      CASE_LABEL, so that we can recover it
+		      in the loop below.  We don't create
+		      the new label while walking the
+		      goto_queue because pointers don't
+		      offer a stable order.  */
+		   q->cont_stmt);
+    }
+  for (j = last_case_index; j < last_case_index + nlabels; j++)
+    {
+      tree label;
+      tree cont_stmt;
+
+      last_case = TREE_VEC_ELT (case_label_vec, j);
+
+      gcc_assert (last_case);
+
+      cont_stmt = CASE_LABEL (last_case);
+
+      label = create_artificial_label ();
+      CASE_LABEL (last_case) = label;
+
+      x = build (LABEL_EXPR, void_type_node, label);
+      append_to_statement_list (x, &switch_body);
+      append_to_statement_list (cont_stmt, &switch_body);
+      maybe_record_in_goto_queue (state, cont_stmt);
     }
   replace_goto_queue (tf);
-  last_case_index += nlabels;
 
   /* Make sure that the last case is the default label, as one is required.
      Then sort the labels, which is also required in GIMPLE.  */