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
This commit is contained in:
parent
ea814c6675
commit
f778c049cd
5 changed files with 132 additions and 24 deletions
|
@ -1,3 +1,10 @@
|
|||
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
|
||||
|
|
107
gcc/gimple-low.c
107
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. */
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
30
gcc/testsuite/gnat.dg/noreturn5.adb
Normal file
30
gcc/testsuite/gnat.dg/noreturn5.adb
Normal file
|
@ -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;
|
8
gcc/testsuite/gnat.dg/noreturn5.ads
Normal file
8
gcc/testsuite/gnat.dg/noreturn5.ads
Normal file
|
@ -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;
|
Loading…
Add table
Reference in a new issue