--- /dev/null
+--TEST--
+Exception inside a foreach loop with return
+--FILE--
+<?php
+class saboteurTestController {
+ public function isConsistent() { throw new \Exception(); }
+}
+
+$controllers = array(new saboteurTestController(),new saboteurTestController());
+foreach ($controllers as $controller) {
+ try {
+ if ($controller->isConsistent()) {
+ return $controller;
+ }
+ } catch (\Exception $e) {
+ echo "Exception\n";
+ }
+}
+?>
+--EXPECT--
+Exception
+Exception
static zend_bool zend_is_call(zend_ast *ast);
-static void generate_free_loop_var(znode *var) /* {{{ */
+static void generate_free_loop_var_ex(znode *var, uint32_t flags) /* {{{ */
{
if (var->op_type != IS_UNUSED) {
zend_op *opline = get_next_op(CG(active_op_array));
opline->opcode = var->flag ? ZEND_FE_FREE : ZEND_FREE;
SET_NODE(opline->op1, var);
SET_UNUSED(opline->op2);
+ opline->extended_value = flags;
}
}
/* }}} */
+static void generate_free_loop_var(znode *var) /* {{{ */
+{
+ generate_free_loop_var_ex(var, 0);
+}
+
static uint32_t zend_add_try_element(uint32_t try_op) /* {{{ */
{
zend_op_array *op_array = CG(active_op_array);
}
/* }}} */
-static void zend_free_foreach_and_switch_variables(void) /* {{{ */
+static void zend_free_foreach_and_switch_variables(uint32_t flags) /* {{{ */
{
int array_offset = CG(context).current_brk_cont;
while (array_offset != -1) {
zend_brk_cont_element *brk_cont = &CG(context).brk_cont_array[array_offset];
- generate_free_loop_var(&brk_cont->loop_var);
+ generate_free_loop_var_ex(&brk_cont->loop_var, flags);
array_offset = brk_cont->parent;
}
}
zend_compile_expr(&expr_node, expr_ast);
}
- zend_free_foreach_and_switch_variables();
+ /* Generator return types are handled separately */
+ if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
+ zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
+ }
+
+ zend_free_foreach_and_switch_variables(ZEND_FREE_ON_RETURN);
if (CG(context).in_finally) {
opline = zend_emit_op(NULL, ZEND_DISCARD_EXCEPTION, NULL, NULL);
opline->op1.var = CG(context).fast_call_var;
}
- /* Generator return types are handled separately */
- if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
- zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
- }
opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
&expr_node, NULL);
&& opline->opcode != ZEND_FETCH_LIST
&& opline->opcode != ZEND_CASE
&& opline->opcode != ZEND_FE_FETCH_R
- && opline->opcode != ZEND_FE_FETCH_RW) {
+ && opline->opcode != ZEND_FE_FETCH_RW
+ /* the following opcodes are not the "final" */
+ && (opline->opcode != ZEND_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
+ && (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
+ ) {
op_live_total += liveliness_kill_var(op_array, opline, var, Tstart, opTs);
}
}
}
} while (++opline != end);
-#if ZEND_DEBUG
+#if 0
/* Check that all TMP variable live-ranges are closed */
for (i = 0; i < op_array->T; i++) {
ZEND_ASSERT(Tstart[i] == (uint32_t)-1);