diff options
Diffstat (limited to 'gcc/tree.c')
-rw-r--r-- | gcc/tree.c | 122 |
1 files changed, 122 insertions, 0 deletions
@@ -12125,4 +12125,126 @@ contains_bitfld_component_ref_p (const_tree ref) return false; } +/* Try to determine whether a TRY_CATCH expression can fall through. + This is a subroutine of block_may_fallthru. */ + +static bool +try_catch_may_fallthru (const_tree stmt) +{ + tree_stmt_iterator i; + + /* If the TRY block can fall through, the whole TRY_CATCH can + fall through. */ + if (block_may_fallthru (TREE_OPERAND (stmt, 0))) + return true; + + i = tsi_start (TREE_OPERAND (stmt, 1)); + switch (TREE_CODE (tsi_stmt (i))) + { + case CATCH_EXPR: + /* We expect to see a sequence of CATCH_EXPR trees, each with a + catch expression and a body. The whole TRY_CATCH may fall + through iff any of the catch bodies falls through. */ + for (; !tsi_end_p (i); tsi_next (&i)) + { + if (block_may_fallthru (CATCH_BODY (tsi_stmt (i)))) + return true; + } + return false; + + case EH_FILTER_EXPR: + /* 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. */ + return block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i))); + + default: + /* This case represents statements to be executed when an + exception occurs. Those statements are implicitly followed + by a RESX statement to resume execution after the exception. + So in this case the TRY_CATCH never falls through. */ + return false; + } +} + +/* Try to determine if we can fall out of the bottom of BLOCK. This guess + need not be 100% accurate; simply be conservative and return true if we + don't know. This is used only to avoid stupidly generating extra code. + If we're wrong, we'll just delete the extra code later. */ + +bool +block_may_fallthru (const_tree block) +{ + /* This CONST_CAST is okay because expr_last returns its argument + unmodified and we assign it to a const_tree. */ + const_tree stmt = expr_last (CONST_CAST_TREE (block)); + + switch (stmt ? TREE_CODE (stmt) : ERROR_MARK) + { + case GOTO_EXPR: + case RETURN_EXPR: + /* Easy cases. If the last statement of the block implies + control transfer, then we can't fall through. */ + return false; + + case SWITCH_EXPR: + /* If SWITCH_LABELS is set, this is lowered, and represents a + branch to a selected label and hence can not fall through. + Otherwise SWITCH_BODY is set, and the switch can fall + through. */ + return SWITCH_LABELS (stmt) == NULL_TREE; + + case COND_EXPR: + if (block_may_fallthru (COND_EXPR_THEN (stmt))) + return true; + return block_may_fallthru (COND_EXPR_ELSE (stmt)); + + case BIND_EXPR: + return block_may_fallthru (BIND_EXPR_BODY (stmt)); + + case TRY_CATCH_EXPR: + return try_catch_may_fallthru (stmt); + + case TRY_FINALLY_EXPR: + /* 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. */ + return (block_may_fallthru (TREE_OPERAND (stmt, 0)) + && block_may_fallthru (TREE_OPERAND (stmt, 1))); + + case MODIFY_EXPR: + if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) + stmt = TREE_OPERAND (stmt, 1); + else + return true; + /* FALLTHRU */ + + case CALL_EXPR: + /* Functions that do not return do not fall through. */ + return (call_expr_flags (stmt) & ECF_NORETURN) == 0; + + case CLEANUP_POINT_EXPR: + return block_may_fallthru (TREE_OPERAND (stmt, 0)); + + case TARGET_EXPR: + return block_may_fallthru (TREE_OPERAND (stmt, 1)); + + case ERROR_MARK: + return true; + + default: + return lang_hooks.block_may_fallthru (stmt); + } +} + #include "gt-tree.h" |