diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d043b8f4de793406fbde20a5419ea90ccc2eb437..0ec4ecdaa824e8d881b4bea562fb394b2a3fabef 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2012-03-31  Eric Botcazou  <ebotcazou@adacore.com>
+
+	* tree-cfg.c (call_can_make_abnormal_goto): New predicate.
+	(stmt_can_make_abnormal_goto): Use it.
+	(is_ctrl_altering_stmt): Likewise.
+
 2012-03-30  Naveen H.S  <naveen.S@kpitcummins.com>
 	    Kaz Kojima  <kkojima@gcc.gnu.org>
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 921f2fa9390ddaaedad220797a40211994e778fd..e2fa4a652820a93c44703974dadd946228231ec7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2012-03-31  Eric Botcazou  <ebotcazou@adacore.com>
+
+	* gnat.dg/controlled6.adb: New test.
+	* gnat.dg/controlled6_pkg.ads: New helper.
+	* gnat.dg/controlled6_pkg-iterators.ad[sb]: Likewise.
+
 2012-03-30  Richard Henderson <rth@redhat.com>
 
 	PR debug/52727
diff --git a/gcc/testsuite/gnat.dg/controlled6.adb b/gcc/testsuite/gnat.dg/controlled6.adb
new file mode 100644
index 0000000000000000000000000000000000000000..88640de7beaadac1e722f1778f893884e2b102a2
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled6.adb
@@ -0,0 +1,24 @@
+-- { dg-do compile }
+-- { dg-options "-O -gnatn" }
+
+with Ada.Text_IO; use Ada.Text_IO;
+with Controlled6_Pkg;
+with Controlled6_Pkg.Iterators;
+
+procedure Controlled6 is
+
+   type String_Access is access String;
+
+   package My_Q is new Controlled6_Pkg (String_Access);
+   package My_Iterators is new My_Q.Iterators (0);
+   use My_Iterators;
+
+   Iterator : Iterator_Type := Find;
+
+begin
+   loop
+      exit when Is_Null (Iterator);
+      Put (Current (Iterator).all & ' ');
+      Find_Next (Iterator);
+   end loop;
+end;
diff --git a/gcc/testsuite/gnat.dg/controlled6_pkg-iterators.adb b/gcc/testsuite/gnat.dg/controlled6_pkg-iterators.adb
new file mode 100644
index 0000000000000000000000000000000000000000..201a75c94cce6482cd2c734811a4054f7c829a56
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled6_pkg-iterators.adb
@@ -0,0 +1,21 @@
+package body Controlled6_Pkg.Iterators is
+
+   function Find return Iterator_Type is
+      Iterator : Iterator_Type;
+   begin
+      return Iterator;
+   end Find;
+
+   function Current (Iterator : in Iterator_Type) return T is begin
+      return Iterator.Current.Item;
+   end Current;
+
+   procedure Find_Next (Iterator : in out Iterator_Type) is begin
+      Iterator.Current := null;
+   end Find_Next;
+
+   function Is_Null (Iterator : in Iterator_Type) return Boolean is begin
+      return Iterator.Current = null;
+   end Is_Null;
+
+end Controlled6_Pkg.Iterators;
diff --git a/gcc/testsuite/gnat.dg/controlled6_pkg-iterators.ads b/gcc/testsuite/gnat.dg/controlled6_pkg-iterators.ads
new file mode 100644
index 0000000000000000000000000000000000000000..89330f6a3babd6786a3a1caed1b9db3bf37c206b
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled6_pkg-iterators.ads
@@ -0,0 +1,22 @@
+with Ada.Finalization;
+
+generic
+
+   I : Integer;
+
+package Controlled6_Pkg.Iterators is
+
+   type Iterator_Type is new Ada.Finalization.Controlled with record
+      Current : Node_Access_Type;
+   end record;
+
+   function Find return Iterator_Type;
+
+   function Current (Iterator : in Iterator_Type) return T;
+   pragma Inline (Current);
+
+   procedure Find_Next (Iterator : in out Iterator_Type);
+
+   function Is_Null (Iterator : in Iterator_Type) return Boolean;
+
+end Controlled6_Pkg.Iterators;
diff --git a/gcc/testsuite/gnat.dg/controlled6_pkg.ads b/gcc/testsuite/gnat.dg/controlled6_pkg.ads
new file mode 100644
index 0000000000000000000000000000000000000000..2f1052be98158d4a3836ce6266c3222998fb3f98
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled6_pkg.ads
@@ -0,0 +1,15 @@
+with Ada.Finalization;
+
+generic
+
+   type T is private;
+
+package Controlled6_Pkg is
+
+   type Node_Type is record
+      Item : T;
+   end record;
+
+   type Node_Access_Type is access Node_Type;
+
+end Controlled6_Pkg;
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index eb7b62a72c504999d208dba4f94062daf61eef6a..1f59c03cfcd345a3bb9d7e6d87283fb7518b098d 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -2273,6 +2273,43 @@ gimple_cfg2vcg (FILE *file)
 			     Miscellaneous helpers
 ---------------------------------------------------------------------------*/
 
+/* Return true if T, a GIMPLE_CALL, can make an abnormal transfer of control
+   flow.  Transfers of control flow associated with EH are excluded.  */
+
+static bool
+call_can_make_abnormal_goto (gimple t)
+{
+  /* If the function has no non-local labels, then a call cannot make an
+     abnormal transfer of control.  */
+  if (!cfun->has_nonlocal_label)
+   return false;
+
+  /* Likewise if the call has no side effects.  */
+  if (!gimple_has_side_effects (t))
+    return false;
+
+  /* Likewise if the called function is leaf.  */
+  if (gimple_call_flags (t) & ECF_LEAF)
+    return false;
+
+  return true;
+}
+
+
+/* Return true if T can make an abnormal transfer of control flow.
+   Transfers of control flow associated with EH are excluded.  */
+
+bool
+stmt_can_make_abnormal_goto (gimple t)
+{
+  if (computed_goto_p (t))
+    return true;
+  if (is_gimple_call (t))
+    return call_can_make_abnormal_goto (t);
+  return false;
+}
+
+
 /* Return true if T represents a stmt that always transfers control.  */
 
 bool
@@ -2306,10 +2343,8 @@ is_ctrl_altering_stmt (gimple t)
       {
 	int flags = gimple_call_flags (t);
 
-	/* A non-pure/const call alters flow control if the current
-	   function has nonlocal labels.  */
-	if (!(flags & (ECF_CONST | ECF_PURE | ECF_LEAF))
-	    && cfun->has_nonlocal_label)
+	/* A call alters control flow if it can make an abnormal goto.  */
+	if (call_can_make_abnormal_goto (t))
 	  return true;
 
 	/* A call also alters control flow if it does not return.  */
@@ -2367,21 +2402,6 @@ simple_goto_p (gimple t)
 }
 
 
-/* Return true if T can make an abnormal transfer of control flow.
-   Transfers of control flow associated with EH are excluded.  */
-
-bool
-stmt_can_make_abnormal_goto (gimple t)
-{
-  if (computed_goto_p (t))
-    return true;
-  if (is_gimple_call (t))
-    return (gimple_has_side_effects (t) && cfun->has_nonlocal_label
-	    && !(gimple_call_flags (t) & ECF_LEAF));
-  return false;
-}
-
-
 /* Return true if STMT should start a new basic block.  PREV_STMT is
    the statement preceding STMT.  It is used when STMT is a label or a
    case label.  Labels should only start a new basic block if their