[PHP-CVS] [php-src] master: Merge branch 'PHP-8.5'
[email protected] (Arnaud Le Blanc)
| Newsgroups | php.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Arnaud Le Blanc (arnaud-lb)
Date: 2026-08-20T10:31:29+02:00
Commit: https://github.com/php/php-src/commit/623fb7a53be03fcf1ec240acc5dc46a64654389c
Raw diff: https://github.com/php/php-src/commit/623fb7a53be03fcf1ec240acc5dc46a64654389c.diff
Merge branch 'PHP-8.5'
* PHP-8.5:
Fix GH-23301: nested "yield from" repeats a value after "yield from []" (#23302)
Changed paths:
A Zend/tests/generators/gh23301.phpt
M Zend/tests/generators/backtrace_multi_yield_from.phpt
M Zend/tests/generators/gh15375.phpt
M Zend/zend_generators.c
Diff:
diff --git a/Zend/tests/generators/backtrace_multi_yield_from.phpt b/Zend/tests/generators/backtrace_multi_yield_from.phpt
index 4fbaa2f05bb4..2cb898b3aac2 100644
--- a/Zend/tests/generators/backtrace_multi_yield_from.phpt
+++ b/Zend/tests/generators/backtrace_multi_yield_from.phpt
@@ -25,8 +25,8 @@ var_dump($gen2->current());
?>
--EXPECTF--
int(1)
-int(1)
#0 %s(10): gen()
#1 [internal function]: from(Object(Generator))
-#2 %s(19): Generator->next()
+#2 %s(17): Generator->next()
int(2)
+NULL
diff --git a/Zend/tests/generators/gh15375.phpt b/Zend/tests/generators/gh15375.phpt
index 48919083f227..f0a2fe56c16c 100644
--- a/Zend/tests/generators/gh15375.phpt
+++ b/Zend/tests/generators/gh15375.phpt
@@ -46,9 +46,9 @@ foreach (outer(withNext()) as $s) {
echo $s, "\n";
}
-// A shared, pre-primed generator consumed through two nested "yield from"
-// levels must still present its current value once to each consumer (the fix
-// must not over-clear the middle level's first-touch).
+// Reading a pre-primed generator through two nested "yield from" levels primes
+// the whole chain but advances nothing. A later next() on a middle level then
+// advances the shared generator, like any other next() would.
echo "shared primed:\n";
function counter() {
yield 1;
@@ -58,11 +58,11 @@ $gen1 = counter();
$gen1->valid();
$gen2 = outer($gen1);
$gen3 = outer($gen2);
-echo "gen3 current: ", $gen3->current(), "\n";
+var_dump($gen3->current());
$gen2->next();
-echo "gen2 current: ", $gen2->current(), "\n";
+var_dump($gen2->current());
$gen2->next();
-echo "gen2 current: ", $gen2->current(), "\n";
+var_dump($gen2->current());
?>
--EXPECT--
@@ -84,6 +84,6 @@ six
eight
nine
shared primed:
-gen3 current: 1
-gen2 current: 1
-gen2 current: 2
+int(1)
+int(2)
+NULL
diff --git a/Zend/tests/generators/gh23301.phpt b/Zend/tests/generators/gh23301.phpt
new file mode 100644
index 000000000000..02aaf2fe2022
--- /dev/null
+++ b/Zend/tests/generators/gh23301.phpt
@@ -0,0 +1,44 @@
+--TEST--
+GH-23301 (Nested "yield from" yields a value twice when the middle generator delegates again)
+--FILE--
+<?php
+
+function inner() {
+ yield "B";
+}
+
+function middle() {
+ yield "A";
+ yield from inner();
+ yield "C";
+ yield from ["D"];
+}
+
+function delegate($gen) {
+ yield from $gen;
+}
+
+foreach (delegate(middle()) as $value) {
+ echo $value, "\n";
+}
+
+function tail($inner) {
+ yield from $inner;
+ yield from ["E"];
+}
+
+$middle = tail(inner());
+$outer = delegate($middle);
+
+var_dump($outer->current());
+$middle->next();
+var_dump($middle->current());
+
+?>
+--EXPECT--
+A
+B
+C
+D
+string(1) "B"
+string(1) "E"
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 2bfbbf687d3c..b9c77e4f0f6a 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -776,10 +776,12 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
return;
}
- if (UNEXPECTED((delegator->flags & ZEND_GENERATOR_DO_INIT) != 0 && !Z_ISUNDEF(generator->value))) {
- /* We must not advance Generator if we yield from a Generator being currently run */
- orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT;
- return;
+ if (UNEXPECTED((delegator->flags & ZEND_GENERATOR_DO_INIT) != 0)) {
+ delegator->flags &= ~ZEND_GENERATOR_DO_INIT;
+ if (UNEXPECTED(!Z_ISUNDEF(generator->value))) {
+ /* We must not advance an already initialized delegate on first resumption */
+ return;
+ }
}
if (EG(active_fiber)) {
@@ -819,7 +821,7 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
EG(current_execute_data) = original_execute_data;
EG(jit_trace_num) = original_jit_trace_num;
- orig_generator->flags &= ~(ZEND_GENERATOR_DO_INIT | ZEND_GENERATOR_IN_FIBER);
+ orig_generator->flags &= ~ZEND_GENERATOR_IN_FIBER;
generator->flags &= ~(ZEND_GENERATOR_CURRENTLY_RUNNING | ZEND_GENERATOR_IN_FIBER);
return;
}
@@ -882,7 +884,6 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
} else {
generator = zend_generator_get_current(orig_generator);
zend_generator_throw_exception(generator, NULL);
- orig_generator->flags &= ~ZEND_GENERATOR_DO_INIT;
delegator = orig_generator;
goto try_again;
}
@@ -900,7 +901,7 @@ ZEND_API void zend_generator_resume(zend_generator *orig_generator) /* {{{ */
goto try_again;
}
- orig_generator->flags &= ~(ZEND_GENERATOR_DO_INIT | ZEND_GENERATOR_IN_FIBER);
+ orig_generator->flags &= ~ZEND_GENERATOR_IN_FIBER;
}
/* }}} */