]> granicus.if.org Git - php/commitdiff
Fix return from by-ref generators
authorNikita Popov <nikic@php.net>
Thu, 14 Jul 2016 13:44:04 +0000 (15:44 +0200)
committerNikita Popov <nikic@php.net>
Thu, 14 Jul 2016 13:44:04 +0000 (15:44 +0200)
Zend/tests/generators/return_from_by_ref_generator.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/Zend/tests/generators/return_from_by_ref_generator.phpt b/Zend/tests/generators/return_from_by_ref_generator.phpt
new file mode 100644 (file)
index 0000000..32bebfb
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Return from by-ref generator
+--FILE--
+<?php
+
+function &gen() {
+    yield;
+    $arr = [42];
+    return $arr[0];
+}
+
+function gen2() {
+    var_dump(yield from gen());
+}
+
+gen2()->next();
+
+?>
+--EXPECT--
+int(42)
index 9a4ff33950b18c4c777b8bc57adef049f2e902a5..ec95fd0d9c27c6d949e7ef97c117532b6af0adc4 100644 (file)
@@ -4120,11 +4120,17 @@ static int zend_has_finally(void) /* {{{ */
 void zend_compile_return(zend_ast *ast) /* {{{ */
 {
        zend_ast *expr_ast = ast->child[0];
+       zend_bool is_generator = (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0;
        zend_bool by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
 
        znode expr_node;
        zend_op *opline;
 
+       if (is_generator) {
+               /* For generators the by-ref flag refers to yields, not returns */
+               by_ref = 0;
+       }
+
        if (!expr_ast) {
                expr_node.op_type = IS_CONST;
                ZVAL_NULL(&expr_node.u.constant);
@@ -4146,7 +4152,7 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
        }
 
        /* 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) {
+       if (!is_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, 0);
        }
@@ -4156,10 +4162,10 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
        opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
                &expr_node, NULL);
 
-       if (expr_ast) {
+       if (by_ref && expr_ast) {
                if (zend_is_call(expr_ast)) {
                        opline->extended_value = ZEND_RETURNS_FUNCTION;
-               } else if (by_ref && !zend_is_variable(expr_ast)) {
+               } else if (!zend_is_variable(expr_ast)) {
                        opline->extended_value = ZEND_RETURNS_VALUE;
                }
        }