Skip to content

Commit 4bce23f

Browse files
committed
Merge branch 'master' of https://github.com/php/php-src
2 parents cb63e4f + ebef772 commit 4bce23f

17 files changed

Lines changed: 238 additions & 27 deletions

UPGRADING.INTERNALS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES
5252
. zend_function.arg_info is now always a zend_arg_info*. Before, it was a
5353
zend_internal_arg_info on internal functions, unless the
5454
ZEND_ACC_USER_ARG_INFO flag was set.
55+
. Added zend_ast_call_get_args() to fetch the argument node from any call
56+
node.
5557

5658
========================
5759
2. Build system changes
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
First class callable error: more than one argument
3+
--FILE--
4+
<?php
5+
6+
foo(1, ...);
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Cannot create a Closure for call expression with more than one argument, or non-variadic placeholders in %s on line %d
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
First class callable error: non-variadic placeholder
3+
--FILE--
4+
<?php
5+
6+
foo(?);
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Cannot create a Closure for call expression with more than one argument, or non-variadic placeholders in %s on line %d

Zend/zend_ast.c

Lines changed: 131 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,14 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_znode(const znode *node) {
5454
return (zend_ast *) ast;
5555
}
5656

57-
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(void) {
57+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(zend_ast *args) {
5858
zend_ast_fcc *ast;
5959

6060
ast = zend_ast_alloc(sizeof(zend_ast_fcc));
6161
ast->kind = ZEND_AST_CALLABLE_CONVERT;
6262
ast->attr = 0;
6363
ast->lineno = CG(zend_lineno);
64+
ast->args = args;
6465
ZEND_MAP_PTR_INIT(ast->fptr, NULL);
6566

6667
return (zend_ast *) ast;
@@ -157,6 +158,12 @@ ZEND_API zend_ast *zend_ast_create_decl(
157158
return (zend_ast *) ast;
158159
}
159160

161+
static bool zend_ast_is_placeholder_arg(zend_ast *arg) {
162+
return arg->kind == ZEND_AST_PLACEHOLDER_ARG
163+
|| (arg->kind == ZEND_AST_NAMED_ARG
164+
&& arg->child[1]->kind == ZEND_AST_PLACEHOLDER_ARG);
165+
}
166+
160167
#if ZEND_AST_SPEC
161168
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_0(zend_ast_kind kind) {
162169
zend_ast *ast;
@@ -400,6 +407,30 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zen
400407

401408
return ast;
402409
}
410+
411+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_0(zend_ast_kind kind) {
412+
return zend_ast_create_list(0, kind);
413+
}
414+
415+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_1(zend_ast_kind kind, zend_ast *arg) {
416+
zend_ast *list = zend_ast_create_list(1, kind, arg);
417+
418+
if (zend_ast_is_placeholder_arg(arg)) {
419+
return zend_ast_create_fcc(list);
420+
}
421+
422+
return list;
423+
}
424+
425+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_2(zend_ast_kind kind, zend_ast *arg1, zend_ast *arg2) {
426+
zend_ast *list = zend_ast_create_list(2, kind, arg1, arg2);
427+
428+
if (zend_ast_is_placeholder_arg(arg1) || zend_ast_is_placeholder_arg(arg2)) {
429+
return zend_ast_create_fcc(list);
430+
}
431+
432+
return list;
433+
}
403434
#else
404435
static zend_ast *zend_ast_create_from_va_list(zend_ast_kind kind, zend_ast_attr attr, va_list va) {
405436
uint32_t i, children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT;
@@ -479,6 +510,41 @@ ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind ki
479510

480511
return ast;
481512
}
513+
514+
ZEND_API zend_ast *zend_ast_create_arg_list(uint32_t init_children, zend_ast_kind kind, ...) {
515+
zend_ast *ast;
516+
zend_ast_list *list;
517+
bool has_placeholders = false;
518+
519+
ast = zend_ast_alloc(zend_ast_list_size(4));
520+
list = (zend_ast_list *) ast;
521+
list->kind = kind;
522+
list->attr = 0;
523+
list->lineno = CG(zend_lineno);
524+
list->children = 0;
525+
526+
{
527+
va_list va;
528+
uint32_t i;
529+
va_start(va, kind);
530+
for (i = 0; i < init_children; ++i) {
531+
zend_ast *child = va_arg(va, zend_ast *);
532+
ast = zend_ast_list_add(ast, child);
533+
uint32_t lineno = zend_ast_get_lineno(child);
534+
if (lineno < ast->lineno) {
535+
ast->lineno = lineno;
536+
}
537+
has_placeholders = has_placeholders || zend_ast_is_placeholder_arg(child);
538+
}
539+
va_end(va);
540+
}
541+
542+
if (has_placeholders) {
543+
return zend_ast_create_fcc(list);
544+
}
545+
546+
return ast;
547+
}
482548
#endif
483549

484550
zend_ast *zend_ast_create_concat_op(zend_ast *op0, zend_ast *op1) {
@@ -508,6 +574,23 @@ ZEND_ATTRIBUTE_NODISCARD ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zen
508574
return (zend_ast *) list;
509575
}
510576

577+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_arg_list_add(zend_ast *list, zend_ast *arg)
578+
{
579+
if (list->kind == ZEND_AST_CALLABLE_CONVERT) {
580+
zend_ast_fcc *fcc_ast = (zend_ast_fcc*)list;
581+
fcc_ast->args = zend_ast_list_add(fcc_ast->args, arg);
582+
return (zend_ast*)fcc_ast;
583+
}
584+
585+
ZEND_ASSERT(list->kind == ZEND_AST_ARG_LIST);
586+
587+
if (zend_ast_is_placeholder_arg(arg)) {
588+
return zend_ast_create_fcc(zend_ast_list_add(list, arg));
589+
}
590+
591+
return zend_ast_list_add(list, arg);
592+
}
593+
511594
static zend_result zend_ast_add_array_element(const zval *result, zval *offset, zval *expr)
512595
{
513596
if (Z_TYPE_P(offset) == IS_UNDEF) {
@@ -1056,10 +1139,22 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
10561139
{
10571140
zend_function *fptr;
10581141
zend_class_entry *called_scope = NULL;
1142+
1143+
zend_ast *args_ast = zend_ast_call_get_args(ast);
1144+
ZEND_ASSERT(args_ast->kind == ZEND_AST_CALLABLE_CONVERT);
1145+
1146+
zend_ast_fcc *fcc_ast = (zend_ast_fcc*)args_ast;
1147+
1148+
zend_ast_list *args = zend_ast_get_list(fcc_ast->args);
1149+
ZEND_ASSERT(args->children > 0);
1150+
if (args->children != 1 || args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) {
1151+
/* TODO: PFAs */
1152+
zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations");
1153+
return FAILURE;
1154+
}
1155+
10591156
switch (ast->kind) {
10601157
case ZEND_AST_CALL: {
1061-
ZEND_ASSERT(ast->child[1]->kind == ZEND_AST_CALLABLE_CONVERT);
1062-
zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast->child[1];
10631158
fptr = ZEND_MAP_PTR_GET(fcc_ast->fptr);
10641159

10651160
if (!fptr) {
@@ -1084,9 +1179,6 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
10841179
break;
10851180
}
10861181
case ZEND_AST_STATIC_CALL: {
1087-
ZEND_ASSERT(ast->child[2]->kind == ZEND_AST_CALLABLE_CONVERT);
1088-
zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast->child[2];
1089-
10901182
zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope);
10911183
if (!ce) {
10921184
return FAILURE;
@@ -1243,7 +1335,8 @@ static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast)
12431335
} else if (ast->kind == ZEND_AST_OP_ARRAY) {
12441336
size = sizeof(zend_ast_op_array);
12451337
} else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) {
1246-
size = sizeof(zend_ast_fcc);
1338+
zend_ast *args_ast = ((zend_ast_fcc*)ast)->args;
1339+
size = sizeof(zend_ast_fcc) + zend_ast_tree_size(args_ast);
12471340
} else if (zend_ast_is_list(ast)) {
12481341
uint32_t i;
12491342
const zend_ast_list *list = zend_ast_get_list(ast);
@@ -1320,6 +1413,8 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf)
13201413
new->lineno = old->lineno;
13211414
ZEND_MAP_PTR_INIT(new->fptr, ZEND_MAP_PTR(old->fptr));
13221415
buf = (void*)((char*)buf + sizeof(zend_ast_fcc));
1416+
new->args = buf;
1417+
buf = zend_ast_tree_copy(old->args, buf);
13231418
} else if (zend_ast_is_decl(ast)) {
13241419
/* Not implemented. */
13251420
ZEND_UNREACHABLE();
@@ -1403,6 +1498,11 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast)
14031498
zend_ast_destroy(decl->child[3]);
14041499
ast = decl->child[4];
14051500
goto tail_call;
1501+
} else if (EXPECTED(ast->kind == ZEND_AST_CALLABLE_CONVERT)) {
1502+
zend_ast_fcc *fcc_ast = (zend_ast_fcc*) ast;
1503+
1504+
ast = fcc_ast->args;
1505+
goto tail_call;
14061506
}
14071507
}
14081508

@@ -2299,6 +2399,13 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
22992399
EMPTY_SWITCH_DEFAULT_CASE();
23002400
}
23012401
break;
2402+
case ZEND_AST_PLACEHOLDER_ARG:
2403+
if (ast->attr == ZEND_PLACEHOLDER_VARIADIC) {
2404+
APPEND_STR("...");
2405+
} else {
2406+
APPEND_STR("?");
2407+
}
2408+
break;
23022409

23032410
/* 1 child node */
23042411
case ZEND_AST_VAR:
@@ -2445,9 +2552,11 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
24452552
zend_ast_export_ex(str, ast->child[1], 0, indent);
24462553
smart_str_appendc(str, ')');
24472554
break;
2448-
case ZEND_AST_CALLABLE_CONVERT:
2449-
smart_str_appends(str, "...");
2450-
break;
2555+
case ZEND_AST_CALLABLE_CONVERT: {
2556+
zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast;
2557+
ast = fcc_ast->args;
2558+
goto simple_list;
2559+
}
24512560
case ZEND_AST_CLASS_CONST:
24522561
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
24532562
smart_str_appends(str, "::");
@@ -2966,3 +3075,15 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr)
29663075

29673076
return ast;
29683077
}
3078+
3079+
zend_ast * ZEND_FASTCALL zend_ast_call_get_args(zend_ast *ast)
3080+
{
3081+
if (ast->kind == ZEND_AST_CALL) {
3082+
return ast->child[1];
3083+
} else if (ast->kind == ZEND_AST_STATIC_CALL || ast->kind == ZEND_AST_METHOD_CALL) {
3084+
return ast->child[2];
3085+
}
3086+
3087+
ZEND_UNREACHABLE();
3088+
return NULL;
3089+
}

Zend/zend_ast.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ enum _zend_ast_kind {
7676
ZEND_AST_TYPE,
7777
ZEND_AST_CONSTANT_CLASS,
7878
ZEND_AST_CALLABLE_CONVERT,
79+
ZEND_AST_PLACEHOLDER_ARG,
7980

8081
/* 1 child node */
8182
ZEND_AST_VAR = 1 << ZEND_AST_NUM_CHILDREN_SHIFT,
@@ -229,10 +230,12 @@ typedef struct _zend_ast_decl {
229230
zend_ast *child[5];
230231
} zend_ast_decl;
231232

233+
// TODO: rename
232234
typedef struct _zend_ast_fcc {
233235
zend_ast_kind kind; /* Type of the node (ZEND_AST_* enum constant) */
234236
zend_ast_attr attr; /* Additional attribute, use depending on node type */
235237
uint32_t lineno; /* Line number */
238+
zend_ast *args;
236239
ZEND_MAP_PTR_DEF(zend_function *, fptr);
237240
} zend_ast_fcc;
238241

@@ -307,27 +310,39 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_0(zend_ast_kind kind);
307310
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_1(zend_ast_kind kind, zend_ast *child);
308311
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2);
309312

313+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_0(zend_ast_kind kind);
314+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_1(zend_ast_kind kind, zend_ast *child);
315+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_2(zend_ast_kind kind, zend_ast *child1, zend_ast *child2);
316+
310317
# define zend_ast_create(...) \
311318
ZEND_AST_SPEC_CALL(zend_ast_create, __VA_ARGS__)
312319
# define zend_ast_create_ex(...) \
313320
ZEND_AST_SPEC_CALL_EX(zend_ast_create_ex, __VA_ARGS__)
314321
# define zend_ast_create_list(init_children, ...) \
315322
ZEND_AST_SPEC_CALL(zend_ast_create_list, __VA_ARGS__)
323+
# define zend_ast_create_arg_list(init_children, ...) \
324+
ZEND_AST_SPEC_CALL(zend_ast_create_arg_list, __VA_ARGS__)
316325

317326
#else
318327
ZEND_API zend_ast *zend_ast_create(zend_ast_kind kind, ...);
319328
ZEND_API zend_ast *zend_ast_create_ex(zend_ast_kind kind, zend_ast_attr attr, ...);
320329
ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind kind, ...);
330+
ZEND_API zend_ast *zend_ast_create_arg_list(uint32_t init_children, zend_ast_kind kind, ...);
321331
#endif
322332

323333
ZEND_ATTRIBUTE_NODISCARD ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zend_ast *list, zend_ast *op);
324334

335+
/* Like zend_ast_list_add(), but wraps the list into a ZEND_AST_CALLABLE_CONVERT
336+
* if any arg is a ZEND_AST_PLACEHOLDER_ARG. list can be a zend_ast_list, or a
337+
* zend_ast_fcc. */
338+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_arg_list_add(zend_ast *list, zend_ast *arg);
339+
325340
ZEND_API zend_ast *zend_ast_create_decl(
326341
zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment,
327342
zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4
328343
);
329344

330-
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(void);
345+
ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(zend_ast *args);
331346

332347
typedef struct {
333348
bool had_side_effects;
@@ -425,4 +440,6 @@ static zend_always_inline zend_ast *zend_ast_list_rtrim(zend_ast *ast) {
425440

426441
zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr);
427442

443+
zend_ast * ZEND_FASTCALL zend_ast_call_get_args(zend_ast *ast);
444+
428445
#endif

Zend/zend_compile.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3948,6 +3948,11 @@ static bool zend_compile_call_common(znode *result, zend_ast *args_ast, const ze
39483948
zend_error_noreturn(E_COMPILE_ERROR, "Cannot create Closure for new expression");
39493949
}
39503950

3951+
zend_ast_list *args = zend_ast_get_list(((zend_ast_fcc*)args_ast)->args);
3952+
if (args->children != 1 || args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) {
3953+
zend_error_noreturn(E_COMPILE_ERROR, "Cannot create a Closure for call expression with more than one argument, or non-variadic placeholders");
3954+
}
3955+
39513956
if (opcode == ZEND_INIT_FCALL) {
39523957
opline->op1.num = zend_vm_calc_used_stack(0, fbc);
39533958
}

Zend/zend_compile.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,9 @@ static zend_always_inline bool zend_check_arg_send_type(const zend_function *zf,
12361236
#define ZEND_IS_BINARY_ASSIGN_OP_OPCODE(opcode) \
12371237
(((opcode) >= ZEND_ADD) && ((opcode) <= ZEND_POW))
12381238

1239+
/* PFAs/FCCs */
1240+
#define ZEND_PLACEHOLDER_VARIADIC (1<<0)
1241+
12391242
/* Pseudo-opcodes that are used only temporarily during compilation */
12401243
#define ZEND_GOTO 253
12411244
#define ZEND_BRK 254

0 commit comments

Comments
 (0)