--- /dev/null
+--TEST--
+throw expression should not leak temporaries
+--FILE--
+<?php
+
+try {
+ new stdClass(throw new Exception);
+} catch (Exception $e) {
+ echo "Caught\n";
+}
+
+try {
+ $a = [];
+ ($a + [1]) + throw new Exception;
+} catch (Exception $e) {
+ echo "Caught\n";
+}
+
+try {
+ @throw new Exception;
+} catch (Exception $e) {
+ echo "Caught\n";
+}
+var_dump(error_reporting());
+
+?>
+--EXPECT--
+Caught
+Caught
+Caught
+int(32767)
znode expr_node;
zend_compile_expr(&expr_node, expr_ast);
- zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL);
-
- result->op_type = IS_CONST;
- ZVAL_BOOL(&result->u.constant, 1);
+ zend_op *opline = zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL);
+ if (result) {
+ /* Mark this as an "expression throw" for opcache. */
+ opline->extended_value = ZEND_THROW_IS_EXPR;
+ result->op_type = IS_CONST;
+ ZVAL_BOOL(&result->u.constant, 1);
+ }
}
/* }}} */
case ZEND_AST_HALT_COMPILER:
zend_compile_halt_compiler(ast);
break;
+ case ZEND_AST_THROW:
+ zend_compile_throw(NULL, ast);
+ break;
default:
{
znode result;
#define ZEND_SEND_BY_REF 1u
#define ZEND_SEND_PREFER_REF 2u
+#define ZEND_THROW_IS_EXPR 1u
+
/* The send mode and is_variadic flag are stored as part of zend_type */
#define _ZEND_SEND_MODE_SHIFT _ZEND_TYPE_EXTRA_FLAGS_SHIFT
#define _ZEND_IS_VARIADIC_BIT (1 << (_ZEND_TYPE_EXTRA_FLAGS_SHIFT + 2))
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
- case ZEND_THROW:
if (i + 1 < op_array->last) {
BB_START(i + 1);
}
break;
+ case ZEND_THROW:
+ /* Don't treat THROW as terminator if it's used in expression context,
+ * as we may lose live ranges when eliminating unreachable code. */
+ if (opline->extended_value != ZEND_THROW_IS_EXPR && i + 1 < op_array->last) {
+ BB_START(i + 1);
+ }
+ break;
case ZEND_INCLUDE_OR_EVAL:
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
case ZEND_GENERATOR_CREATE: