* gimple-low.c (lower_try_catch): New function.
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 25 Jul 2012 19:57:51 +0000 (19:57 +0000)
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 25 Jul 2012 19:57:51 +0000 (19:57 +0000)
(lower_stmt) <GIMPLE_TRY>: Use it to lower GIMPLE_TRY_CATCH.
<GIMPLE_CATCH>: Delete.
<GIMPLE_EH_FILTER>: Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@189865 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/gimple-low.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/noreturn5.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/noreturn5.ads [new file with mode: 0644]

index d8f2207..ff4a09a 100644 (file)
@@ -1,5 +1,12 @@
 2012-07-25  Eric Botcazou  <ebotcazou@adacore.com>
 
+       * gimple-low.c (lower_try_catch): New function.
+       (lower_stmt) <GIMPLE_TRY>: Use it to lower GIMPLE_TRY_CATCH.
+       <GIMPLE_CATCH>: Delete.
+       <GIMPLE_EH_FILTER>: Likewise.
+
+2012-07-25  Eric Botcazou  <ebotcazou@adacore.com>
+
        * expr.c (expand_expr_real_1): Do not expand operand #1 and #2
        of BIT_FIELD_REF for ignored results.
        * fold-const.c (fold_ternary_loc) <BIT_FIELD_REF>: Check that the
index 04d4275..bdb6c1e 100644 (file)
@@ -76,6 +76,7 @@ struct lower_data
 
 static void lower_stmt (gimple_stmt_iterator *, struct lower_data *);
 static void lower_gimple_bind (gimple_stmt_iterator *, struct lower_data *);
+static void lower_try_catch (gimple_stmt_iterator *, struct lower_data *);
 static void lower_gimple_return (gimple_stmt_iterator *, struct lower_data *);
 static void lower_builtin_setjmp (gimple_stmt_iterator *);
 
@@ -373,31 +374,28 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data)
       return;
 
     case GIMPLE_TRY:
-      {
-       bool try_cannot_fallthru;
-       lower_sequence (gimple_try_eval_ptr (stmt), data);
-       try_cannot_fallthru = data->cannot_fallthru;
-       data->cannot_fallthru = false;
-       lower_sequence (gimple_try_cleanup_ptr (stmt), data);
-       /* See gimple_stmt_may_fallthru for the rationale.  */
-       if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
-         {
-           data->cannot_fallthru |= try_cannot_fallthru;
-           gsi_next (gsi);
-           return;
-         }
-      }
-      break;
-
-    case GIMPLE_CATCH:
-      data->cannot_fallthru = false;
-      lower_sequence (gimple_catch_handler_ptr (stmt), data);
-      break;
-
-    case GIMPLE_EH_FILTER:
-      data->cannot_fallthru = false;
-      lower_sequence (gimple_eh_filter_failure_ptr (stmt), data);
-      break;
+      if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
+       lower_try_catch (gsi, data);
+      else
+       {
+         /* It must be a GIMPLE_TRY_FINALLY.  */
+         bool cannot_fallthru;
+         lower_sequence (gimple_try_eval_ptr (stmt), data);
+         cannot_fallthru = data->cannot_fallthru;
+
+         /* The finally clause is always executed after the try clause,
+            so if it does not fall through, then the try-finally will not
+            fall through.  Otherwise, if the try clause does not fall
+            through, then when the finally clause falls through it will
+            resume execution wherever the try clause was going.  So the
+            whole try-finally will only fall through if both the try
+            clause and the finally clause fall through.  */
+         data->cannot_fallthru = false;
+         lower_sequence (gimple_try_cleanup_ptr (stmt), data);
+         data->cannot_fallthru |= cannot_fallthru;
+         gsi_next (gsi);
+       }
+      return;
 
     case GIMPLE_EH_ELSE:
       lower_sequence (gimple_eh_else_n_body_ptr (stmt), data);
@@ -520,6 +518,67 @@ lower_gimple_bind (gimple_stmt_iterator *gsi, struct lower_data *data)
   gsi_remove (gsi, false);
 }
 
+/* Same as above, but for a GIMPLE_TRY_CATCH.  */
+
+static void
+lower_try_catch (gimple_stmt_iterator *gsi, struct lower_data *data)
+{
+  bool cannot_fallthru;
+  gimple stmt = gsi_stmt (*gsi);
+  gimple_stmt_iterator i;
+
+  /* We don't handle GIMPLE_TRY_FINALLY.  */
+  gcc_assert (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH);
+
+  lower_sequence (gimple_try_eval_ptr (stmt), data);
+  cannot_fallthru = data->cannot_fallthru;
+
+  i = gsi_start (*gimple_try_cleanup_ptr (stmt));
+  switch (gimple_code (gsi_stmt (i)))
+    {
+    case GIMPLE_CATCH:
+      /* We expect to see a sequence of GIMPLE_CATCH stmts, each with a
+        catch expression and a body.  The whole try/catch may fall
+        through iff any of the catch bodies falls through.  */
+      for (; !gsi_end_p (i); gsi_next (&i))
+       {
+         data->cannot_fallthru = false;
+         lower_sequence (gimple_catch_handler_ptr (gsi_stmt (i)), data);
+         if (!data->cannot_fallthru)
+           cannot_fallthru = false;
+       }
+      break;
+
+    case GIMPLE_EH_FILTER:
+      /* The exception filter expression only matters if there is an
+        exception.  If the exception does not match EH_FILTER_TYPES,
+        we will execute EH_FILTER_FAILURE, and we will fall through
+        if that falls through.  If the exception does match
+        EH_FILTER_TYPES, the stack unwinder will continue up the
+        stack, so we will not fall through.  We don't know whether we
+        will throw an exception which matches EH_FILTER_TYPES or not,
+        so we just ignore EH_FILTER_TYPES and assume that we might
+        throw an exception which doesn't match.  */
+      data->cannot_fallthru = false;
+      lower_sequence (gimple_eh_filter_failure_ptr (gsi_stmt (i)), data);
+      if (!data->cannot_fallthru)
+       cannot_fallthru = false;
+      break;
+
+    default:
+      /* This case represents statements to be executed when an
+        exception occurs.  Those statements are implicitly followed
+        by a GIMPLE_RESX to resume execution after the exception.  So
+        in this case the try/catch never falls through.  */
+      data->cannot_fallthru = false;
+      lower_sequence (gimple_try_cleanup_ptr (stmt), data);
+      break;
+    }
+
+  data->cannot_fallthru = cannot_fallthru;
+  gsi_next (gsi);
+}
+
 /* Try to determine whether a TRY_CATCH expression can fall through.
    This is a subroutine of block_may_fallthru.  */
 
index c749654..495624f 100644 (file)
@@ -1,3 +1,7 @@
+2012-07-25  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gnat.dg/noreturn5.ad[sb]: New test.
+
 2012-07-25  Sandra Loosemore  <sandra@codesourcery.com>
            Paul Brook  <paul@codesourcery.com>
 
diff --git a/gcc/testsuite/gnat.dg/noreturn5.adb b/gcc/testsuite/gnat.dg/noreturn5.adb
new file mode 100644 (file)
index 0000000..2f75990
--- /dev/null
@@ -0,0 +1,30 @@
+with Ada.Characters.Handling; use Ada.Characters.Handling;
+with GNAT.OS_Lib;             use GNAT.OS_Lib;
+with Text_IO;                 use Text_IO;
+
+package body Noreturn5 is
+
+   procedure Proc (Arg_Line : Wide_String; Keep_Going : Boolean) is
+   begin
+      Put (To_String (Arg_Line));
+
+      if Keep_Going then
+         raise Constraint_Error;
+      else
+         OS_Exit (1);
+      end if;
+
+   exception
+      when Constraint_Error =>
+         raise;
+
+      when others =>
+         if Keep_Going then
+            raise Constraint_Error;
+         else
+            OS_Exit (1);
+         end if;
+
+   end;
+
+end Noreturn5;
diff --git a/gcc/testsuite/gnat.dg/noreturn5.ads b/gcc/testsuite/gnat.dg/noreturn5.ads
new file mode 100644 (file)
index 0000000..4da5c1e
--- /dev/null
@@ -0,0 +1,8 @@
+-- { dg-do compile }
+
+package Noreturn5 is
+
+   procedure Proc (Arg_Line : Wide_String; Keep_Going : Boolean);
+   pragma No_Return (Proc);
+
+end Noreturn5;