From f778c049cd880c4d653ad7ab857e61480d5efd35 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 25 Jul 2012 19:57:51 +0000 Subject: [PATCH] gimple-low.c (lower_try_catch): New function. * gimple-low.c (lower_try_catch): New function. (lower_stmt) : Use it to lower GIMPLE_TRY_CATCH. : Delete. : Likewise. From-SVN: r189865 --- gcc/ChangeLog | 7 ++ gcc/gimple-low.c | 107 +++++++++++++++++++++------- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gnat.dg/noreturn5.adb | 30 ++++++++ gcc/testsuite/gnat.dg/noreturn5.ads | 8 +++ 5 files changed, 132 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/gnat.dg/noreturn5.adb create mode 100644 gcc/testsuite/gnat.dg/noreturn5.ads diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d8f220782c0..ff4a09a20ce 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2012-07-25 Eric Botcazou + + * gimple-low.c (lower_try_catch): New function. + (lower_stmt) : Use it to lower GIMPLE_TRY_CATCH. + : Delete. + : Likewise. + 2012-07-25 Eric Botcazou * expr.c (expand_expr_real_1): Do not expand operand #1 and #2 diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 04d4275f75b..bdb6c1e6f9e 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; + 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; - 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; + /* 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 c7496540aa4..495624faf7c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2012-07-25 Eric Botcazou + + * gnat.dg/noreturn5.ad[sb]: New test. + 2012-07-25 Sandra Loosemore Paul Brook diff --git a/gcc/testsuite/gnat.dg/noreturn5.adb b/gcc/testsuite/gnat.dg/noreturn5.adb new file mode 100644 index 00000000000..2f759909769 --- /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 00000000000..4da5c1e0906 --- /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;