diff --git a/Zend/tests/bug68446.phpt b/Zend/tests/bug68446.phpt index 9648966691bf6..91685ebb5e5a1 100644 --- a/Zend/tests/bug68446.phpt +++ b/Zend/tests/bug68446.phpt @@ -9,7 +9,7 @@ function a(array $a = FOO) { var_dump($a); } -function b(array $b = BAR) { +function b(?array $b = BAR) { var_dump($b); } diff --git a/Zend/tests/type_declarations/scalar_constant_defaults.phpt b/Zend/tests/type_declarations/scalar_constant_defaults.phpt index b9076c6b52d89..88c6a4b39facd 100644 --- a/Zend/tests/type_declarations/scalar_constant_defaults.phpt +++ b/Zend/tests/type_declarations/scalar_constant_defaults.phpt @@ -39,6 +39,10 @@ function int_val_default_null(int $a = NULL_VAL) { return $a; } +function nullable_int_val_default_null(?int $a = NULL_VAL) { + return $a; +} + echo "Testing int val" . PHP_EOL; var_dump(int_val()); @@ -58,13 +62,27 @@ echo "Testing string add val" . PHP_EOL; var_dump(string_add_val()); echo "Testing int with default null constant" . PHP_EOL; -var_dump(int_val_default_null()); +try { + var_dump(int_val_default_null()); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} echo "Testing int with null null constant" . PHP_EOL; -var_dump(int_val_default_null(null)); +try { + var_dump(int_val_default_null(null)); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +echo "Testing nullable int with default null constant" . PHP_EOL; +var_dump(nullable_int_val_default_null()); + +echo "Testing nullable int with null null constant" . PHP_EOL; +var_dump(nullable_int_val_default_null(null)); ?> ---EXPECT-- +--EXPECTF-- Testing int val int(10) Testing float val @@ -78,6 +96,10 @@ float(10.7) Testing string add val string(14) "this is a test" Testing int with default null constant -NULL +Argument 1 passed to int_val_default_null() must be of the type int, null given, called in %s on line %d Testing int with null null constant +Argument 1 passed to int_val_default_null() must be of the type int, null given, called in %s on line %d +Testing nullable int with default null constant +NULL +Testing nullable int with null null constant NULL diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 09c0485411fe0..1d628a235206d 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -793,23 +793,6 @@ static ZEND_COLD void zend_verify_arg_error( } } -static int is_null_constant(zend_class_entry *scope, zval *default_value) -{ - if (Z_TYPE_P(default_value) == IS_CONSTANT_AST) { - zval constant; - - ZVAL_COPY(&constant, default_value); - if (UNEXPECTED(zval_update_constant_ex(&constant, scope) != SUCCESS)) { - return 0; - } - if (Z_TYPE(constant) == IS_NULL) { - return 1; - } - zval_ptr_dtor_nogc(&constant); - } - return 0; -} - static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg) { switch (type_hint) { @@ -1043,7 +1026,7 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf static zend_always_inline zend_bool zend_check_type( zend_type type, zval *arg, zend_class_entry **ce, void **cache_slot, - zval *default_value, zend_class_entry *scope, + zend_class_entry *scope, zend_bool is_return_type, zend_bool is_internal) { zend_reference *ref = NULL; @@ -1063,19 +1046,19 @@ static zend_always_inline zend_bool zend_check_type( } else { *ce = zend_fetch_class(ZEND_TYPE_NAME(type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD)); if (UNEXPECTED(!*ce)) { - return Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value))); + return Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(type); } *cache_slot = (void *) *ce; } if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) { return instanceof_function(Z_OBJCE_P(arg), *ce); } - return Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value))); + return Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(type); } else if (EXPECTED(ZEND_TYPE_CODE(type) == Z_TYPE_P(arg))) { return 1; } - if (Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value)))) { + if (Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(type)) { /* Null passed to nullable type */ return 1; } @@ -1104,7 +1087,7 @@ static zend_always_inline zend_bool zend_check_type( * because this case is already checked at compile-time. */ } -static zend_always_inline int zend_verify_recv_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot) +static zend_always_inline int zend_verify_recv_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot) { zend_arg_info *cur_arg_info = &zf->common.arg_info[arg_num-1]; zend_class_entry *ce; @@ -1113,7 +1096,7 @@ static zend_always_inline int zend_verify_recv_arg_type(zend_function *zf, uint3 cur_arg_info = &zf->common.arg_info[arg_num-1]; ce = NULL; - if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, default_value, zf->common.scope, 0, 0))) { + if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, zf->common.scope, 0, 0))) { zend_verify_arg_error(zf, cur_arg_info, arg_num, ce, arg); return 0; } @@ -1121,7 +1104,7 @@ static zend_always_inline int zend_verify_recv_arg_type(zend_function *zf, uint3 return 1; } -static zend_always_inline int zend_verify_variadic_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot) +static zend_always_inline int zend_verify_variadic_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot) { zend_arg_info *cur_arg_info; zend_class_entry *ce; @@ -1131,7 +1114,7 @@ static zend_always_inline int zend_verify_variadic_arg_type(zend_function *zf, u cur_arg_info = &zf->common.arg_info[zf->common.num_args]; ce = NULL; - if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, default_value, zf->common.scope, 0, 0))) { + if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, zf->common.scope, 0, 0))) { zend_verify_arg_error(zf, cur_arg_info, arg_num, ce, arg); return 0; } @@ -1158,7 +1141,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED int zend_verify_internal_arg_type break; } - if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, &dummy_cache_slot, NULL, fbc->common.scope, 0, /* is_internal */ 1))) { + if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, &dummy_cache_slot, fbc->common.scope, 0, /* is_internal */ 1))) { return 0; } arg++; @@ -1254,7 +1237,7 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret) return 1; } - if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, &dummy_cache_slot, NULL, NULL, 1, /* is_internal */ 1))) { + if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, &dummy_cache_slot, NULL, 1, /* is_internal */ 1))) { zend_verify_internal_return_error(zf, ce, ret); return 0; } @@ -1268,7 +1251,7 @@ static zend_always_inline void zend_verify_return_type(zend_function *zf, zval * zend_arg_info *ret_info = zf->common.arg_info - 1; zend_class_entry *ce = NULL; - if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, cache_slot, NULL, NULL, 1, 0))) { + if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, cache_slot, NULL, 1, 0))) { zend_verify_return_error(zf, ce, ret); } } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index ccd46c575d228..8884810f65dc7 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5198,7 +5198,7 @@ ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED|CACHE_SLOT) zval *param = EX_VAR(opline->result.var); SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num)) || EG(exception))) { HANDLE_EXCEPTION(); } } @@ -5243,10 +5243,8 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT) } if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zval *default_value = RT_CONSTANT(opline, opline->op2); - SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)) || EG(exception))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)) || EG(exception))) { HANDLE_EXCEPTION(); } } @@ -5275,7 +5273,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED|CACHE_SLOT) param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { - zend_verify_variadic_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)); + zend_verify_variadic_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num)); if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); param++; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1a62480bb3f1e..70d89048e7eee 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3046,10 +3046,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CON } if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zval *default_value = RT_CONSTANT(opline, opline->op2); - SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)) || EG(exception))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)) || EG(exception))) { HANDLE_EXCEPTION(); } } @@ -3127,7 +3125,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_UNUSED_H zval *param = EX_VAR(opline->result.var); SAVE_OPLINE(); - if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) { + if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num)) || EG(exception))) { HANDLE_EXCEPTION(); } } @@ -3155,7 +3153,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_UNUSED_HAND param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { - zend_verify_variadic_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)); + zend_verify_variadic_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num)); if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); param++; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index da4f0846ef571..e8a9918b398e0 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -3104,11 +3104,6 @@ static int zend_update_type_info(const zend_op_array *op_array, ce = NULL; if (arg_info) { tmp = zend_fetch_arg_info_type(script, arg_info, &ce); - if (opline->opcode == ZEND_RECV_INIT && - Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) { - /* The constant may resolve to NULL */ - tmp |= MAY_BE_NULL; - } if (arg_info->pass_by_reference) { tmp |= MAY_BE_REF; } diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 13309a4c11b84..18af7234a74b8 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1115,23 +1115,6 @@ static zval* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_execute_data *execu return value; } -static int is_null_constant(zend_class_entry *scope, zval *default_value) -{ - if (Z_CONSTANT_P(default_value)) { - zval constant; - - ZVAL_COPY(&constant, default_value); - if (UNEXPECTED(zval_update_constant_ex(&constant, scope) != SUCCESS)) { - return 0; - } - if (Z_TYPE(constant) == IS_NULL) { - return 1; - } - zval_ptr_dtor(&constant); - } - return 0; -} - static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg) { switch (type_hint) { @@ -1313,12 +1296,11 @@ static void ZEND_FASTCALL zend_jit_verify_arg_object(zval *arg, zend_op_array *o } } -static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_op_array *op_array, uint32_t arg_num, zend_arg_info *arg_info, void **cache_slot, zval *default_value) +static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_op_array *op_array, uint32_t arg_num, zend_arg_info *arg_info, void **cache_slot) { zend_class_entry *ce = NULL; - if (Z_TYPE_P(arg) == IS_NULL && - (ZEND_TYPE_ALLOW_NULL(arg_info->type) || (default_value && is_null_constant(op_array->scope, default_value)))) { + if (Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(arg_info->type)) { /* Null passed to nullable type */ return; } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 7bb9c4e4b20c5..79abfe714ef95 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -9021,16 +9021,13 @@ static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, zend_op_array | mov CARG3, arg_num | LOAD_ADDR CARG4, (ptrdiff_t)arg_info | mov aword A5, r0 - | mov aword A6, 0 | EXT_CALL zend_jit_verify_arg_slow, r0 |.elif X64 | mov CARG3, arg_num | LOAD_ADDR CARG4, (ptrdiff_t)arg_info | mov CARG5, r0 - | xor CARG6, CARG6 | EXT_CALL zend_jit_verify_arg_slow, r0 |.else - | push 0 | push r0 | push (ptrdiff_t)arg_info | push arg_num @@ -9190,16 +9187,13 @@ static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, zend_op_a | mov CARG3, arg_num | LOAD_ADDR CARG4, (ptrdiff_t)arg_info | mov aword A5, r0 - | ADDR_OP2_2 mov, aword A6, zv, r0 | EXT_CALL zend_jit_verify_arg_slow, r0 |.elif X64 | mov CARG3, arg_num | LOAD_ADDR CARG4, (ptrdiff_t)arg_info | mov CARG5, r0 - | LOAD_ADDR CARG6, zv | EXT_CALL zend_jit_verify_arg_slow, r0 |.else - | push zv | push r0 | push (ptrdiff_t)arg_info | push arg_num