diff options
Diffstat (limited to 'gcc/expr.c')
| -rw-r--r-- | gcc/expr.c | 58 | 
1 files changed, 39 insertions, 19 deletions
| diff --git a/gcc/expr.c b/gcc/expr.c index 7b5810c617c..e70bf905b20 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8965,29 +8965,49 @@ expand_expr (exp, target, tmode, modifier)        {  	tree try_block = TREE_OPERAND (exp, 0);  	tree finally_block = TREE_OPERAND (exp, 1); -	rtx finally_label = gen_label_rtx (); -	rtx done_label = gen_label_rtx (); -	rtx return_link = gen_reg_rtx (Pmode); -	tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node, -			      (tree) finally_label, (tree) return_link); -	TREE_SIDE_EFFECTS (cleanup) = 1; -	/* Start a new binding layer that will keep track of all cleanup -	   actions to be performed.  */ -	expand_start_bindings (2); +        if (unsafe_for_reeval (finally_block) > 1) +	  { +	    /* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR +	       is not sufficient, so we cannot expand the block twice. +	       So we play games with GOTO_SUBROUTINE_EXPR to let us +	       expand the thing only once.  */ + +	    rtx finally_label = gen_label_rtx (); +	    rtx done_label = gen_label_rtx (); +	    rtx return_link = gen_reg_rtx (Pmode); +	    tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node, +			          (tree) finally_label, (tree) return_link); +	    TREE_SIDE_EFFECTS (cleanup) = 1; + +	    /* Start a new binding layer that will keep track of all cleanup +	       actions to be performed.  */ +	    expand_start_bindings (2); +	    target_temp_slot_level = temp_slot_level; + +	    expand_decl_cleanup (NULL_TREE, cleanup); +	    op0 = expand_expr (try_block, target, tmode, modifier); + +	    preserve_temp_slots (op0); +	    expand_end_bindings (NULL_TREE, 0, 0); +	    emit_jump (done_label); +	    emit_label (finally_label); +	    expand_expr (finally_block, const0_rtx, VOIDmode, 0); +	    emit_indirect_jump (return_link); +	    emit_label (done_label); +	  } +	else +	  { +	    expand_start_bindings (2); +	    target_temp_slot_level = temp_slot_level; -	target_temp_slot_level = temp_slot_level; +	    expand_decl_cleanup (NULL_TREE, finally_block); +	    op0 = expand_expr (try_block, target, tmode, modifier); -	expand_decl_cleanup (NULL_TREE, cleanup); -	op0 = expand_expr (try_block, target, tmode, modifier); +	    preserve_temp_slots (op0); +	    expand_end_bindings (NULL_TREE, 0, 0); +	  } -	preserve_temp_slots (op0); -	expand_end_bindings (NULL_TREE, 0, 0); -	emit_jump (done_label); -	emit_label (finally_label); -	expand_expr (finally_block, const0_rtx, VOIDmode, 0); -	emit_indirect_jump (return_link); -	emit_label (done_label);  	return op0;        } | 

