diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2012-07-25 19:57:51 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2012-07-25 19:57:51 +0000 |
commit | f778c049cd880c4d653ad7ab857e61480d5efd35 (patch) | |
tree | 944a1014b9ea6e467ccae43ae63c6dff60c2c37d /gcc | |
parent | ea814c6675874dae704d3ee33b7146c3f5132688 (diff) | |
download | gcc-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/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/gimple-low.c | 109 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/noreturn5.adb | 30 | ||||
-rw-r--r-- | gcc/testsuite/gnat.dg/noreturn5.ads | 8 |
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; |