Skip to content

Commit defe31a

Browse files
committed
Fixed default invalid context tracking.
Added more test cases for default expressions.
1 parent 6acbffb commit defe31a

File tree

7 files changed

+96
-13
lines changed

7 files changed

+96
-13
lines changed

Zend/tests/default_expression/default_expressions.phpt

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ Tests an exhaustive list of valid expressions containing the default keyword
33
--FILE--
44
<?php
55

6+
class C {}
67
function F($V = 2) { return $V; }
8+
function FA($V = ['Alfa', 'Bravo']) { return $V; }
9+
function FE($V = new Exception) { return $V; }
10+
function FO($V = new C) { return $V; }
711

812
echo "Numeric binary operators (LHS)\n";
913
var_dump(F(default + 1));
@@ -63,6 +67,25 @@ var_dump(F(0 ?: default));
6367
var_dump(F(default ?? 0));
6468
var_dump(F(null ?? default));
6569

70+
echo "\nVariable assignment\n";
71+
F($V = default); var_dump($V);
72+
F($V += default); var_dump($V);
73+
F($V -= default); var_dump($V);
74+
F($V *= default); var_dump($V);
75+
F($V **= default); var_dump($V);
76+
F($V /= default); var_dump($V);
77+
F($V <<= default); var_dump($V);
78+
F($V >>= default); var_dump($V);
79+
F($V %= default); var_dump($V);
80+
F($V &= default); var_dump($V);
81+
F($V |= default); var_dump($V);
82+
F($V ^= default); var_dump($V);
83+
F($V .= default); var_dump($V);
84+
F($U ??= default); var_dump($U);
85+
FA(list($V) = default); var_dump($V);
86+
FA([, $V] = default); var_dump($V);
87+
// TODO: Variable expressions?
88+
6689
echo "\nCasts\n";
6790
var_dump(F((int)default));
6891
var_dump(F((double)default));
@@ -71,22 +94,42 @@ var_dump(F((array)default));
7194
var_dump(F((object)default));
7295
var_dump(F((bool)default));
7396

97+
echo "\nParens\n";
98+
var_dump(F((((default)))));
99+
74100
echo "\nInternal functions\n";
75101
var_dump(F(empty(default)));
76102
// eval() makes no sense.
77103
// exit() makes no sense.
78104
// TODO?
79-
// include()
80-
// include_once()
81-
// require()
82-
// require_once()
105+
// include
106+
// include_once
107+
// require
108+
// require_once
83109

84110
echo "\nMatch tier\n";
85111
var_dump(F(match(default) { default => default }));
86112
var_dump(F(match(default) { 2 => 3 }));
87113

114+
echo "\nInstanceof tier\n";
115+
var_dump(FO(default instanceof C));
116+
var_dump(FO(default instanceof D));
117+
118+
echo "\nClone tier\n";
119+
var_dump(FO(clone default));
120+
121+
echo "\nThrow tier\n";
122+
try {
123+
FE(throw default);
124+
} catch (Exception $E) {
125+
var_dump($E::class);
126+
}
127+
88128
echo "\nPrint tier\n";
89129
var_dump(F(print default));
130+
131+
// TODO: Silence operator?
132+
90133
?>
91134
--EXPECT--
92135
Numeric binary operators (LHS)
@@ -147,6 +190,24 @@ int(2)
147190
int(2)
148191
int(2)
149192

193+
Variable assignment
194+
int(2)
195+
int(4)
196+
int(2)
197+
int(4)
198+
int(16)
199+
int(8)
200+
int(32)
201+
int(8)
202+
int(0)
203+
int(0)
204+
int(2)
205+
int(0)
206+
string(2) "02"
207+
int(2)
208+
string(4) "Alfa"
209+
string(5) "Bravo"
210+
150211
Casts
151212
int(2)
152213
float(2)
@@ -161,12 +222,26 @@ object(stdClass)#1 (1) {
161222
}
162223
bool(true)
163224

225+
Parens
226+
int(2)
227+
164228
Internal functions
165229
bool(false)
166230

167231
Match tier
168232
int(2)
169233
int(3)
170234

235+
Instanceof tier
236+
bool(true)
237+
bool(false)
238+
239+
Clone tier
240+
object(C)#2 (0) {
241+
}
242+
243+
Throw tier
244+
string(9) "Exception"
245+
171246
Print tier
172247
2int(1)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Tests specifying the default keyword in an invalid context throws a compile error (2)
3+
--FILE--
4+
<?php
5+
6+
function F($V = 2) { return $V; }
7+
F(fn () => default)();
8+
?>
9+
--EXPECTF--
10+
Fatal error: Cannot use default in non-argument context. in %s on line %d

Zend/zend_compile.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_arra
340340
CG(context).in_jmp_frameless_branch = false;
341341
CG(context).active_property_info = NULL;
342342
CG(context).active_property_hook_kind = (zend_property_hook_kind)-1;
343+
CG(context).arg_num = 0;
343344
}
344345
/* }}} */
345346

@@ -3701,7 +3702,7 @@ static uint32_t zend_compile_args(
37013702
uint32_t i;
37023703
bool uses_arg_unpack = 0;
37033704
uint32_t arg_count = 0; /* number of arguments not including unpacks */
3704-
uint32_t prev_arg_num = CG(arg_num);
3705+
uint32_t prev_arg_num = CG(context).arg_num;
37053706

37063707
/* Whether named arguments are used syntactically, to enforce language level limitations.
37073708
* May not actually use named argument passing. */
@@ -3779,7 +3780,7 @@ static uint32_t zend_compile_args(
37793780
arg_count++;
37803781
}
37813782

3782-
CG(arg_num) = arg_num;
3783+
CG(context).arg_num = arg_num;
37833784

37843785
/* Treat passing of $GLOBALS the same as passing a call.
37853786
* This will error at runtime if the argument is by-ref. */
@@ -3895,15 +3896,15 @@ static uint32_t zend_compile_args(
38953896
zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL);
38963897
}
38973898

3898-
CG(arg_num) = prev_arg_num;
3899+
CG(context).arg_num = prev_arg_num;
38993900

39003901
return arg_count;
39013902
}
39023903
/* }}} */
39033904

39043905
static void zend_compile_default(znode *result, zend_ast *ast)
39053906
{
3906-
uint32_t arg_num = CG(arg_num);
3907+
uint32_t arg_num = CG(context).arg_num;
39073908

39083909
if (arg_num == 0) {
39093910
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use default in non-argument context.");

Zend/zend_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ typedef struct _zend_oparray_context {
207207
const zend_property_info *active_property_info;
208208
zend_property_hook_kind active_property_hook_kind;
209209
bool in_jmp_frameless_branch;
210+
uint32_t arg_num; // Current 1-based argument index if compiling arguments, otherwise zero.
210211
} zend_oparray_context;
211212

212213
/* Class, property and method flags class|meth.|prop.|const*/

Zend/zend_globals.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ struct _zend_compiler_globals {
154154
uint32_t rtd_key_counter;
155155

156156
zend_stack short_circuiting_opnums;
157-
158-
// Current 1-based argument index if compiling arguments, otherwise zero.
159-
uint32_t arg_num;
160157
#ifdef ZTS
161158
uint32_t copied_functions_count;
162159
#endif

Zend/zend_language_parser.y

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,7 @@ expr:
13131313
| '@' expr { $$ = zend_ast_create(ZEND_AST_SILENCE, $2); }
13141314
| scalar { $$ = $1; }
13151315
| '`' backticks_expr '`' { $$ = zend_ast_create(ZEND_AST_SHELL_EXEC, $2); }
1316+
| T_DEFAULT { $$ = zend_ast_create(ZEND_AST_DEFAULT); }
13161317
| T_PRINT expr { $$ = zend_ast_create(ZEND_AST_PRINT, $2); }
13171318
| T_YIELD { $$ = zend_ast_create(ZEND_AST_YIELD, NULL, NULL); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
13181319
| T_YIELD expr { $$ = zend_ast_create(ZEND_AST_YIELD, $2, NULL); CG(extra_fn_flags) |= ZEND_ACC_GENERATOR; }
@@ -1322,7 +1323,6 @@ expr:
13221323
| inline_function { $$ = $1; }
13231324
| attributes inline_function { $$ = zend_ast_with_attributes($2, $1); }
13241325
| T_STATIC inline_function { $$ = $2; ((zend_ast_decl *) $$)->flags |= ZEND_ACC_STATIC; }
1325-
| T_DEFAULT { $$ = zend_ast_create(ZEND_AST_DEFAULT); }
13261326
| attributes T_STATIC inline_function
13271327
{ $$ = zend_ast_with_attributes($3, $1); ((zend_ast_decl *) $$)->flags |= ZEND_ACC_STATIC; }
13281328
| match { $$ = $1; }

Zend/zend_language_scanner.l

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,6 @@ static zend_op_array *zend_compile(int type)
595595
CG(in_compilation) = 1;
596596
CG(ast) = NULL;
597597
CG(ast_arena) = zend_arena_create(1024 * 32);
598-
CG(arg_num) = 0;
599598

600599
if (!zendparse()) {
601600
int last_lineno = CG(zend_lineno);

0 commit comments

Comments
 (0)