Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add support by yielding by-reference

  • Loading branch information...
commit 85f077cea13b3cb4927453b8a2f8ce51a9461bbb 1 parent 5a9bddb
Nikita Popov nikic authored
13 Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt
View
@@ -0,0 +1,13 @@
+--TEST--
+Non-ref generators cannot be iterated by-ref
+--FILE--
+<?php
+
+function *gen() { }
+
+$gen = gen();
+foreach ($gen as &$value) { }
+
+?>
+--EXPECTF--
+Fatal error: You can only iterate a generator by-reference if it declared that it yields by-reference in %s on line %d
16 Zend/tests/generators/errors/yield_const_by_ref_error.phpt
View
@@ -0,0 +1,16 @@
+--TEST--
+A notice is thrown when yielding a constant value by reference
+--FILE--
+<?php
+
+function *&gen() {
+ yield "foo";
+}
+
+$gen = gen();
+var_dump($gen->current());
+
+?>
+--EXPECTF--
+Notice: Only variable references should be yielded by reference in %s on line %d
+string(3) "foo"
20 Zend/tests/generators/errors/yield_non_ref_function_call_by_ref_error.phpt
View
@@ -0,0 +1,20 @@
+--TEST--
+Yielding the result of a non-ref function call throw a notice
+--FILE--
+<?php
+
+function foo() {
+ return "bar";
+}
+
+function *&gen() {
+ yield foo();
+}
+
+$gen = gen();
+var_dump($gen->current());
+
+?>
+--EXPECTF--
+Notice: Only variable references should be yielded by reference in %s on line %d
+string(3) "bar"
44 Zend/tests/generators/generator_method_by_ref.phpt
View
@@ -0,0 +1,44 @@
+--TEST--
+Generator methods can yield by reference
+--FILE--
+<?php
+
+class Test implements IteratorAggregate {
+ protected $data;
+
+ public function __construct(array $data) {
+ $this->data = $data;
+ }
+
+ public function getData() {
+ return $this->data;
+ }
+
+ public function *&getIterator() {
+ foreach ($this->data as $key => &$value) {
+ yield $key => $value;
+ }
+ }
+}
+
+$test = new Test([1, 2, 3, 4, 5]);
+foreach ($test as &$value) {
+ $value *= -1;
+}
+
+var_dump($test->getData());
+
+?>
+--EXPECT--
+array(5) {
+ [0]=>
+ int(-1)
+ [1]=>
+ int(-2)
+ [2]=>
+ int(-3)
+ [3]=>
+ int(-4)
+ [4]=>
+ &int(-5)
+}
32 Zend/tests/generators/yield_by_reference.phpt
View
@@ -0,0 +1,32 @@
+--TEST--
+Generators can yield by-reference
+--FILE--
+<?php
+
+function *&iter(array &$array) {
+ foreach ($array as $key => &$value) {
+ yield $key => $value;
+ }
+}
+
+$array = [1, 2, 3, 4, 5];
+$iter = iter($array);
+foreach ($iter as &$value) {
+ $value *= -1;
+}
+var_dump($array);
+
+?>
+--EXPECT--
+array(5) {
+ [0]=>
+ int(-1)
+ [1]=>
+ int(-2)
+ [2]=>
+ int(-3)
+ [3]=>
+ int(-4)
+ [4]=>
+ &int(-5)
+}
24 Zend/tests/generators/yield_ref_function_call_by_reference.phpt
View
@@ -0,0 +1,24 @@
+--TEST--
+The result of a by-ref function call can be yielded just fine
+--FILE--
+<?php
+
+function &nop(&$var) {
+ return $var;
+}
+
+function *&gen(&$var) {
+ yield nop($var);
+}
+
+$var = "foo";
+$gen = gen($var);
+foreach ($gen as &$varRef) {
+ $varRef = "bar";
+}
+
+var_dump($var);
+
+?>
+--EXPECT--
+string(3) "bar"
12 Zend/zend_compile.c
View
@@ -2615,12 +2615,16 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
zend_op *opline;
int start_op_number, end_op_number;
+ /* For generators the & modifier applies to the yielded values, not the
+ * return value. */
+ zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR);
+
if ((CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && expr != NULL) {
zend_error(E_COMPILE_ERROR, "Generators cannot return values using \"return\"");
}
if (do_end_vparse) {
- if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(expr)) {
+ if (returns_reference && !zend_is_function_or_method_call(expr)) {
zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC);
} else {
zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC);
@@ -2645,7 +2649,7 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) ? ZEND_RETURN_BY_REF : ZEND_RETURN;
+ opline->opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN;
if (expr) {
SET_NODE(opline->op1, expr);
@@ -2676,6 +2680,10 @@ void zend_do_yield(znode *result, const znode *value, const znode *key TSRMLS_DC
if (value) {
SET_NODE(opline->op1, value);
+
+ if (zend_is_function_or_method_call(value)) {
+ opline->extended_value = ZEND_RETURNS_FUNCTION;
+ }
} else {
SET_UNUSED(opline->op1);
}
8 Zend/zend_generators.c
View
@@ -661,12 +661,12 @@ zend_object_iterator *zend_generator_get_iterator(zend_class_entry *ce, zval *ob
zend_generator_iterator *iterator;
zend_generator *generator;
- if (by_ref) {
- zend_error(E_ERROR, "By reference iteration of generators is currently not supported");
- }
-
generator = (zend_generator *) zend_object_store_get_object(object TSRMLS_CC);
+ if (by_ref && !(generator->execute_data->op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
+ zend_error(E_ERROR, "You can only iterate a generator by-reference if it declared that it yields by-reference");
+ }
+
iterator = emalloc(sizeof(zend_generator_iterator));
iterator->intern.funcs = &zend_generator_iterator_functions;
iterator->intern.data = (void *) generator;
81 Zend/zend_vm_def.h
View
@@ -5316,6 +5316,7 @@ ZEND_VM_HANDLER(159, ZEND_SUSPEND_AND_RETURN_GENERATOR, ANY, ANY)
ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -5332,30 +5333,74 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
/* Set the new yielded value */
if (OP1_TYPE != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = GET_OP1_ZVAL_PTR(BP_VAR_R);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!IS_OP1_TMP_FREE()) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!IS_OP1_TMP_FREE()) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
- generator->value = copy;
+ if (OP1_TYPE == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (OP1_TYPE == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ FREE_OP1_IF_VAR();
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R);
- FREE_OP1_IF_VAR();
+ /* Consts, temporary variables and references need copying */
+ if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!IS_OP1_TMP_FREE()) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ FREE_OP1_IF_VAR();
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
1,935 Zend/zend_vm_execute.h
View
<
@@ -4118,6 +4118,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -4133,29 +4134,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE
/* Set the new yielded value */
if (IS_CONST != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = opline->op1.zv;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = opline->op1.zv;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_CONST == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CONST == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
- generator->value = copy;
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = opline->op1.zv;
+ /* Consts, temporary variables and references need copying */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -4759,6 +4803,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -4774,29 +4819,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_
/* Set the new yielded value */
if (IS_CONST != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = opline->op1.zv;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = opline->op1.zv;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_CONST == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CONST == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- generator->value = copy;
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = opline->op1.zv;
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -5725,6 +5813,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -5740,29 +5829,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_
/* Set the new yielded value */
if (IS_CONST != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = opline->op1.zv;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = opline->op1.zv;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
- generator->value = copy;
+ if (IS_CONST == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CONST == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = opline->op1.zv;
+ /* Consts, temporary variables and references need copying */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -6386,6 +6518,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -6401,29 +6534,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL
/* Set the new yielded value */
if (IS_CONST != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = opline->op1.zv;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = opline->op1.zv;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_CONST == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CONST == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- generator->value = copy;
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = opline->op1.zv;
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -7086,6 +7262,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -7101,29 +7278,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A
/* Set the new yielded value */
if (IS_CONST != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = opline->op1.zv;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = opline->op1.zv;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
- generator->value = copy;
+ if (IS_CONST == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CONST == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = opline->op1.zv;
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -9093,6 +9313,7 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_CONST_HANDLER(ZEND_OPC
static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -9109,29 +9330,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_
/* Set the new yielded value */
if (IS_TMP_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!1) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_TMP_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_TMP_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
- generator->value = copy;
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -9734,6 +9998,7 @@ static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDL
static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -9750,29 +10015,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
/* Set the new yielded value */
if (IS_TMP_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!1) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_TMP_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_TMP_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
- generator->value = copy;
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -10700,6 +11008,7 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_VAR_HANDLER(ZEND_OPCOD
static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -10716,29 +11025,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
/* Set the new yielded value */
if (IS_TMP_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!1) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_TMP_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_TMP_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
- generator->value = copy;
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -11227,6 +11579,7 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_VAR_SPEC_TMP_UNUSED_HANDLER(ZEND_OP
static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -11243,29 +11596,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
/* Set the new yielded value */
if (IS_TMP_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!1) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_TMP_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_TMP_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
- generator->value = copy;
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -11865,6 +12261,7 @@ static int ZEND_FASTCALL ZEND_INIT_ARRAY_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLE
static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -11881,29 +12278,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
/* Set the new yielded value */
if (IS_TMP_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!1) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
- generator->value = copy;
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_TMP_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_TMP_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!1) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -15729,6 +16169,7 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_CONST_HANDLER(ZEN
static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -15745,30 +16186,74 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_
/* Set the new yielded value */
if (IS_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- generator->value = copy;
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ if (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
- if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ /* Consts, temporary variables and references need copying */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -17757,6 +18242,7 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_TMP_HANDLER(ZEND_
static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -17773,30 +18259,74 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
/* Set the new yielded value */
if (IS_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
- generator->value = copy;
+ if (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
- if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ /* Consts, temporary variables and references need copying */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -20165,6 +20695,7 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_VAR_HANDLER(ZEND_
static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -20181,30 +20712,74 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
/* Set the new yielded value */
if (IS_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
- generator->value = copy;
+ if (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
- if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ /* Consts, temporary variables and references need copying */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -21252,6 +21827,7 @@ static int ZEND_FASTCALL ZEND_SEPARATE_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HAND
static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -21268,30 +21844,74 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
/* Set the new yielded value */
if (IS_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ if (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
- generator->value = copy;
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
- if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ /* Consts, temporary variables and references need copying */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -23329,6 +23949,7 @@ static int ZEND_FASTCALL ZEND_ISSET_ISEMPTY_PROP_OBJ_SPEC_VAR_CV_HANDLER(ZEND_O
static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
+ zend_free_op free_op1;
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -23345,30 +23966,74 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
/* Set the new yielded value */
if (IS_VAR != IS_UNUSED) {
- zend_free_op free_op1;
- zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
+ zval *value, *copy;
- /* Consts, temporary variables and references need copying */
- if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
+
+ if (IS_VAR == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_VAR == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- generator->value = copy;
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC);
- if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ /* Consts, temporary variables and references need copying */
+ if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -24766,6 +25431,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -24781,29 +25447,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL
/* Set the new yielded value */
if (IS_UNUSED != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = NULL;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = NULL;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_UNUSED == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
- generator->value = copy;
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_UNUSED == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = NULL;
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -26025,6 +26734,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -26040,29 +26750,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER
/* Set the new yielded value */
if (IS_UNUSED != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = NULL;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = NULL;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
- generator->value = copy;
+ if (IS_UNUSED == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_UNUSED == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = NULL;
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -27284,6 +28037,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -27299,29 +28053,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER
/* Set the new yielded value */
if (IS_UNUSED != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = NULL;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = NULL;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
- generator->value = copy;
+ if (IS_UNUSED == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_UNUSED == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = NULL;
+ /* Consts, temporary variables and references need copying */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -27655,6 +28452,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -27670,29 +28468,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND
/* Set the new yielded value */
if (IS_UNUSED != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = NULL;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = NULL;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_UNUSED == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_UNUSED == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
- generator->value = copy;
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = NULL;
+ /* Consts, temporary variables and references need copying */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -28911,6 +29752,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -28926,29 +29768,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_
/* Set the new yielded value */
if (IS_UNUSED != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = NULL;
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = NULL;
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = NULL;
+
+ if (IS_UNUSED == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
- generator->value = copy;
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_UNUSED == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
+
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = NULL;
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_UNUSED == IS_CONST || IS_UNUSED == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -32376,6 +33261,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -32391,29 +33277,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
/* Set the new yielded value */
if (IS_CV != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ if (IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CV == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- generator->value = copy;
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -34274,6 +35203,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -34289,29 +35219,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
/* Set the new yielded value */
if (IS_CV != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ if (IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CV == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- generator->value = copy;
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -36551,6 +37524,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -36566,29 +37540,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
/* Set the new yielded value */
if (IS_CV != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ if (IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CV == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- generator->value = copy;
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -37498,6 +38515,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_
{
USE_OPLINE
+
/* The generator object is stored in return_value_ptr_ptr */
zend_generator *generator = (zend_generator *) EG(return_value_ptr_ptr);
@@ -37513,29 +38531,72 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_
/* Set the new yielded value */
if (IS_CV != IS_UNUSED) {
+ if (EX(op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
+ /* Constants and temporary variables aren't yieldable by reference,
+ * but we still allow them with a notice. */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) {
+ zval *value, *copy;
- zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- /* Consts, temporary variables and references need copying */
- if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
- || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
- ) {
- zval *copy;
+ value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
- ALLOC_ZVAL(copy);
- INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
- /* Temporary variables don't need ctor copying */
- if (!0) {
- zval_copy_ctor(copy);
- }
+ generator->value = copy;
+ } else {
+ zval **value_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ if (IS_CV == IS_VAR && UNEXPECTED(value_ptr == NULL)) {
+ zend_error_noreturn(E_ERROR, "Cannot yield string offsets by reference");
+ }
+
+ /* If a function call result is yielded and the function did
+ * not return by reference we throw a notice. */
+ if (IS_CV == IS_VAR && !Z_ISREF_PP(value_ptr)
+ && !(opline->extended_value == ZEND_RETURNS_FUNCTION
+ && EX_T(opline->op1.var).var.fcall_returned_reference)
+ && EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) {
+ zend_error(E_NOTICE, "Only variable references should be yielded by reference");
- generator->value = copy;
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ } else {
+ SEPARATE_ZVAL_TO_MAKE_IS_REF(value_ptr);
+ Z_ADDREF_PP(value_ptr);
+ generator->value = *value_ptr;
+ }
+
+ }
} else {
- Z_ADDREF_P(value);
- generator->value = value;
- }
+ zval *value = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC);
+
+ /* Consts, temporary variables and references need copying */
+ if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR
+ || (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0)
+ ) {
+ zval *copy;
+
+ ALLOC_ZVAL(copy);
+ INIT_PZVAL_COPY(copy, value);
+ /* Temporary variables don't need ctor copying */
+ if (!0) {
+ zval_copy_ctor(copy);
+ }
+
+ generator->value = copy;
+ } else {
+ Z_ADDREF_P(value);
+ generator->value = value;
+ }
+
+ }
} else {
/* If no value was specified yield null */
Z_ADDREF(EG(uninitialized_zval));
@@ -39444,6 +40505,7 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
{
USE_OPLINE