Skip to content

Commit 5c956f9

Browse files
committed
Avoid capturing nested arrow function parameters
Fixes GH-19867 Closes GH-20041
1 parent d10d188 commit 5c956f9

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

Zend/zend_compile.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8092,6 +8092,8 @@ typedef struct {
80928092
bool varvars_used;
80938093
} closure_info;
80948094

8095+
static void find_implicit_binds(closure_info *info, zend_ast *params_ast, zend_ast *stmt_ast);
8096+
80958097
static void find_implicit_binds_recursively(closure_info *info, zend_ast *ast) {
80968098
if (!ast) {
80978099
return;
@@ -8136,7 +8138,15 @@ static void find_implicit_binds_recursively(closure_info *info, zend_ast *ast) {
81368138
} else if (ast->kind == ZEND_AST_ARROW_FUNC) {
81378139
/* For arrow functions recursively check the expression. */
81388140
zend_ast_decl *closure_ast = (zend_ast_decl *) ast;
8139-
find_implicit_binds_recursively(info, closure_ast->child[2]);
8141+
closure_info inner_info;
8142+
find_implicit_binds(&inner_info, closure_ast->child[0], closure_ast->child[2]);
8143+
if (inner_info.varvars_used) {
8144+
info->varvars_used = true;
8145+
}
8146+
if (zend_hash_num_elements(&inner_info.uses)) {
8147+
zend_hash_copy(&info->uses, &inner_info.uses, NULL);
8148+
}
8149+
zend_hash_destroy(&inner_info.uses);
81408150
} else if (!zend_ast_is_special(ast)) {
81418151
uint32_t i, children = zend_ast_get_num_children(ast);
81428152
for (i = 0; i < children; i++) {

ext/opcache/tests/gh19867.phpt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
GH-19867: Avoid capturing nested arrow function parameters
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.enable=1
7+
opcache.enable_cli=1
8+
opcache.opt_debug_level=0x20000
9+
--FILE--
10+
<?php
11+
fn() => fn($a, $b) => $a + $b;
12+
?>
13+
--EXPECTF--
14+
$_main:
15+
; (lines=%d, args=0, vars=%d, tmps=%d)
16+
; (after optimizer)
17+
; %s
18+
0000 T0 = DECLARE_LAMBDA_FUNCTION 0
19+
0001 FREE T0
20+
0002 RETURN int(1)
21+
22+
{closure:%s:%d}:
23+
; (lines=%d, args=0, vars=%d, tmps=%d)
24+
; (after optimizer)
25+
; %s
26+
0000 T0 = DECLARE_LAMBDA_FUNCTION 0
27+
0001 RETURN T0
28+
29+
{closure:%s:%d}:
30+
; (lines=%d, args=2, vars=%d, tmps=%d)
31+
; (after optimizer)
32+
; %s
33+
0000 CV0($a) = RECV 1
34+
0001 CV1($b) = RECV 2
35+
0002 T2 = ADD CV0($a) CV1($b)
36+
0003 RETURN T2

0 commit comments

Comments
 (0)