aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2012-07-25 19:57:51 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2012-07-25 19:57:51 +0000
commitf778c049cd880c4d653ad7ab857e61480d5efd35 (patch)
tree944a1014b9ea6e467ccae43ae63c6dff60c2c37d /gcc
parentea814c6675874dae704d3ee33b7146c3f5132688 (diff)
downloadgcc-f778c049cd880c4d653ad7ab857e61480d5efd35.zip
gcc-f778c049cd880c4d653ad7ab857e61480d5efd35.tar.gz
gcc-f778c049cd880c4d653ad7ab857e61480d5efd35.tar.bz2
gimple-low.c (lower_try_catch): New function.
* 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. From-SVN: r189865
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/gimple-low.c109
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gnat.dg/noreturn5.adb30
-rw-r--r--gcc/testsuite/gnat.dg/noreturn5.ads8
5 files changed, 133 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d8f2207..ff4a09a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c
index 04d4275..bdb6c1e 100644
--- a/gcc/gimple-low.c
+++ b/gcc/gimple-low.c
@@ -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. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c749654..495624f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..2f75990
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/noreturn5.adb
@@ -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
index 0000000..4da5c1e
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/noreturn5.ads
@@ -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;