diff --git a/Zend/tests/explicitSendByRef/__call.phpt b/Zend/tests/explicitSendByRef/__call.phpt index 7ee3320fc911c..83008addeff9a 100644 --- a/Zend/tests/explicitSendByRef/__call.phpt +++ b/Zend/tests/explicitSendByRef/__call.phpt @@ -22,7 +22,11 @@ class ForwardCalls { $forward = new ForwardCalls(new Incrementor); $i = 0; -$forward->inc(&$i); +try { + $forward->inc(&$i); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} var_dump($i); $i = 0; @@ -31,5 +35,6 @@ var_dump($i); ?> --EXPECT-- -int(1) +Cannot pass reference to by-value parameter 1 +int(0) int(0) diff --git a/Zend/tests/explicitSendByRef/basic.phpt b/Zend/tests/explicitSendByRef/basic.phpt index 83dabe3c7edb2..a719c3ffa71fe 100644 --- a/Zend/tests/explicitSendByRef/basic.phpt +++ b/Zend/tests/explicitSendByRef/basic.phpt @@ -14,10 +14,10 @@ var_dump($b); // Works (prefer-ref arg) $c = 42; -$vars = ['d' => &$c]; -extract(&$vars, EXTR_REFS); -$d++; -var_dump($c); +$vars = ['b' => 2, 'a' => 1]; +$vars2 = [2, 1]; +array_multisort(&$vars, $vars2); +var_dump($vars, $vars2); // Works (by-ref arg, by-ref function) $e = 42; @@ -68,7 +68,18 @@ array(1) { int(43) } } -int(43) +array(2) { + ["a"]=> + int(1) + ["b"]=> + int(2) +} +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} int(43) Cannot pass reference to by-value parameter 1 Cannot pass result of by-value function by reference diff --git a/Zend/tests/explicitSendByRef/call_user_func.phpt b/Zend/tests/explicitSendByRef/call_user_func.phpt index 1c58125915798..215dd1e7a3b17 100644 --- a/Zend/tests/explicitSendByRef/call_user_func.phpt +++ b/Zend/tests/explicitSendByRef/call_user_func.phpt @@ -3,33 +3,12 @@ call_user_func() with explicit pass by ref --FILE-- --EXPECTF-- -Warning: Foo\inc(): Argument #1 ($i) must be passed by reference, value given in %s on line %d -int(0) -int(1) - -Warning: Foo\inc(): Argument #1 ($i) must be passed by reference, value given in %s on line %d -int(0) -int(1) +Fatal error: Cannot pass reference to by-value parameter 2 in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index d07b896fec1fd..dfc86b63d5201 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4301,19 +4301,16 @@ static zend_result zend_compile_func_cuf(znode *result, zend_ast_list *args, zen zend_ast *arg_ast = args->child[i]; znode arg_node; zend_op *opline; - bool by_ref = 0; if (arg_ast->kind == ZEND_AST_REF) { - zend_compile_var(&arg_node, arg_ast->child[0], BP_VAR_W, 1); - by_ref = 1; - } else { - zend_compile_expr(&arg_node, arg_ast); + zend_error_noreturn(E_COMPILE_ERROR, + "Cannot pass reference to by-value parameter %" PRIu32, i + 1); } + zend_compile_expr(&arg_node, arg_ast); opline = zend_emit_op(NULL, ZEND_SEND_USER, &arg_node, NULL); opline->op2.num = i; opline->result.var = EX_NUM_TO_VAR(i - 1); - opline->extended_value = by_ref; } zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); @@ -6602,6 +6599,7 @@ static void zend_compile_declare(zend_ast *ast) /* {{{ */ if (Z_LVAL(value_zv) == 1) { CG(active_op_array)->fn_flags |= ZEND_ACC_STRICT_TYPES; } + } else { zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", ZSTR_VAL(name)); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index c6e60a29ade1a..6a5626492ec73 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -1044,8 +1044,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type); #define ZEND_SEND_BY_VAL 0u #define ZEND_SEND_BY_REF 1u -#define ZEND_SEND_PREFER_VAL 2u -#define ZEND_SEND_PREFER_REF 3u +#define ZEND_SEND_PREFER_REF 2u #define ZEND_THROW_IS_EXPR 1u @@ -1078,7 +1077,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type); #define IS_CONSTANT_CLASS 0x400 /* __CLASS__ in trait */ #define IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE 0x800 -static zend_always_inline bool zend_check_arg_must_be_sent_by_ref(const zend_function *zf, uint32_t arg_num) +static zend_always_inline bool zend_check_arg_send_type(const zend_function *zf, uint32_t arg_num, uint32_t mask) { arg_num--; if (UNEXPECTED(arg_num >= zf->common.num_args)) { @@ -1087,44 +1086,17 @@ static zend_always_inline bool zend_check_arg_must_be_sent_by_ref(const zend_fun } arg_num = zf->common.num_args; } - return ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) == ZEND_SEND_BY_REF; -} - -static zend_always_inline int zend_check_arg_should_be_sent_by_ref(const zend_function *zf, uint32_t arg_num) -{ - arg_num--; - if (UNEXPECTED(arg_num >= zf->common.num_args)) { - if (EXPECTED((zf->common.fn_flags & ZEND_ACC_VARIADIC) == 0)) { - return 0; - } - arg_num = zf->common.num_args; - } - - /* The SEND_BY_REF bit is set for PREFER_REF as well. */ - return (ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) & ZEND_SEND_BY_REF) != 0; -} - -static zend_always_inline int zend_check_arg_may_be_sent_by_ref(const zend_function *zf, uint32_t arg_num) -{ - arg_num--; - if (UNEXPECTED(arg_num >= zf->common.num_args)) { - if (EXPECTED((zf->common.fn_flags & ZEND_ACC_VARIADIC) == 0)) { - return 0; - } - arg_num = zf->common.num_args; - } - - return ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) != ZEND_SEND_BY_VAL; + return UNEXPECTED((ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) & mask) != 0); } #define ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \ - zend_check_arg_must_be_sent_by_ref(zf, arg_num) + zend_check_arg_send_type(zf, arg_num, ZEND_SEND_BY_REF) #define ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \ - zend_check_arg_should_be_sent_by_ref(zf, arg_num) + zend_check_arg_send_type(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) #define ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \ - zend_check_arg_may_be_sent_by_ref(zf, arg_num) + zend_check_arg_send_type(zf, arg_num, ZEND_SEND_PREFER_REF) /* Quick API to check first 12 arguments */ #define MAX_ARG_FLAG_NUM 12 @@ -1133,24 +1105,24 @@ static zend_always_inline int zend_check_arg_may_be_sent_by_ref(const zend_funct # define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \ (zf)->quick_arg_flags |= ((mask) << ((arg_num) - 1) * 2); \ } while (0) -# define ZEND_GET_ARG_FLAG(zf, arg_num) \ - (((zf)->quick_arg_flags >> (((arg_num) - 1) * 2)) & 0x3u) +# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \ + (((zf)->quick_arg_flags >> (((arg_num) - 1) * 2)) & (mask)) #else # define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \ (zf)->quick_arg_flags |= (((mask) << 6) << (arg_num) * 2); \ } while (0) -# define ZEND_GET_ARG_FLAG(zf, arg_num) \ - (((zf)->quick_arg_flags >> (((arg_num) + 3) * 2)) & 0x3u) +# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \ + (((zf)->quick_arg_flags >> (((arg_num) + 3) * 2)) & (mask)) #endif #define QUICK_ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \ - (ZEND_GET_ARG_FLAG(zf, arg_num) == ZEND_SEND_BY_REF) + ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF) #define QUICK_ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \ - ((ZEND_GET_ARG_FLAG(zf, arg_num) & ZEND_SEND_BY_REF) != 0) + ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) #define QUICK_ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \ - (ZEND_GET_ARG_FLAG(zf, arg_num) != ZEND_SEND_BY_VAL) + ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_PREFER_REF) #define ZEND_RETURN_VAL 0 #define ZEND_RETURN_REF 1 diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 9179177e525fd..3cea0d5b0accf 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -847,7 +847,7 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_ if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (ARG_MUST_BE_SENT_BY_REF(func, i + 1)) { + if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) { /* By-value send is not allowed -- emit a warning, * and perform the call with the value wrapped in a reference. */ zend_param_must_be_ref(func, i + 1); @@ -905,7 +905,7 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_ if (ARG_SHOULD_BE_SENT_BY_REF(func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (ARG_MUST_BE_SENT_BY_REF(func, arg_num)) { + if (!ARG_MAY_BE_SENT_BY_REF(func, arg_num)) { /* By-value send is not allowed -- emit a warning, * and perform the call with the value wrapped in a reference. */ zend_param_must_be_ref(func, arg_num); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index eda9e3a37af15..158b937238573 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1317,10 +1317,6 @@ ZEND_API bool zend_check_protected(const zend_class_entry *ce, const zend_class_ } /* }}} */ -ZEND_BEGIN_ARG_INFO_EX(zend_call_arg_info, 0, 0, 0) - ZEND_ARG_VARIADIC_INFO(ZEND_SEND_PREFER_VAL, args) -ZEND_END_ARG_INFO() - ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce, zend_string *method_name, bool is_static) /* {{{ */ { size_t mname_len; @@ -1330,9 +1326,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce * The low bit must be zero, to not be interpreted as a MAP_PTR offset. */ static const void *dummy = (void*)(intptr_t)2; - unsigned char arg_flags = - (ZEND_SEND_PREFER_VAL << 6) | (ZEND_SEND_PREFER_VAL << 4) | - (ZEND_SEND_PREFER_VAL << 2) | ZEND_SEND_PREFER_VAL; + static const zend_arg_info arg_info[1] = {{0}}; ZEND_ASSERT(fbc); @@ -1343,9 +1337,9 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce } func->type = ZEND_USER_FUNCTION; - func->arg_flags[0] = arg_flags; - func->arg_flags[1] = arg_flags; - func->arg_flags[2] = arg_flags; + func->arg_flags[0] = 0; + func->arg_flags[1] = 0; + func->arg_flags[2] = 0; func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC | ZEND_ACC_VARIADIC; if (is_static) { func->fn_flags |= ZEND_ACC_STATIC; @@ -1376,7 +1370,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce func->prototype = NULL; func->num_args = 0; func->required_num_args = 0; - func->arg_info = (zend_arg_info *) zend_call_arg_info + 1; + func->arg_info = (zend_arg_info *) arg_info; return (zend_function*)func; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index eec57a55181d9..fd9cc5bddb84a 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4889,7 +4889,7 @@ ZEND_VM_HOT_SEND_HANDLER(50, ZEND_SEND_VAR_NO_REF_EX, VAR, CONST|UNUSED|NUM, SPE ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } else { @@ -4901,7 +4901,7 @@ ZEND_VM_HOT_SEND_HANDLER(50, ZEND_SEND_VAR_NO_REF_EX, VAR, CONST|UNUSED|NUM, SPE ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } @@ -4966,10 +4966,10 @@ ZEND_VM_HANDLER(209, ZEND_SEND_EXPLICIT_REF, VAR|CV, NUM, SPEC(QUICK_ARG)) uint32_t arg_num = opline->op2.num; if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { ZEND_VM_C_GOTO(invalid_send_ref); } - } else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { ZEND_VM_C_LABEL(invalid_send_ref): SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num); @@ -5000,10 +5000,10 @@ ZEND_VM_HANDLER(210, ZEND_SEND_EXPLICIT_REF_FUNC, VAR, NUM) uint32_t arg_num = opline->op2.num; if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { ZEND_VM_C_GOTO(invalid_send_ref); } - } else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { ZEND_VM_C_LABEL(invalid_send_ref): SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num); @@ -5455,7 +5455,7 @@ ZEND_VM_C_LABEL(send_array): break; } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); @@ -5507,7 +5507,7 @@ ZEND_VM_C_LABEL(send_array): bool must_wrap = 0; if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); @@ -5540,31 +5540,21 @@ ZEND_VM_C_LABEL(send_array): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(120, ZEND_SEND_USER, CONST|TMP|VAR|CV, NUM, REF) +ZEND_VM_HANDLER(120, ZEND_SEND_USER, CONST|TMP|VAR|CV, NUM) { USE_OPLINE zval *arg, *param; SAVE_OPLINE(); + arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); param = ZEND_CALL_VAR(EX(call), opline->result.var); - if (opline->extended_value) { - arg = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if (Z_ISREF_P(arg)) { - Z_ADDREF_P(arg); - } else { - ZVAL_MAKE_REF_EX(arg, 2); - } - ZVAL_REF(param, Z_REF_P(arg)); + if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + zend_param_must_be_ref(EX(call)->func, opline->op2.num); + Z_TRY_ADDREF_P(arg); + ZVAL_NEW_REF(param, arg); } else { - arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R); - if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { - zend_param_must_be_ref(EX(call)->func, opline->op2.num); - Z_TRY_ADDREF_P(arg); - ZVAL_NEW_REF(param, arg); - } else { - ZVAL_COPY(param, arg); - } + ZVAL_COPY(param, arg); } FREE_OP1(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3d66e008c2e30..1d1dbc0d7e560 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2510,7 +2510,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O break; } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); @@ -2562,7 +2562,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_O bool must_wrap = 0; if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { if (UNEXPECTED(!Z_ISREF_P(arg))) { - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { /* By-value send is not allowed -- emit a warning, * but still perform the call. */ zend_param_must_be_ref(EX(call)->func, arg_num); @@ -4880,24 +4880,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CONST_HANDLER(Z SAVE_OPLINE(); + arg = RT_CONSTANT(opline, opline->op1); param = ZEND_CALL_VAR(EX(call), opline->result.var); - if (opline->extended_value) { - arg = zend_get_bad_ptr(); - if (Z_ISREF_P(arg)) { - Z_ADDREF_P(arg); - } else { - ZVAL_MAKE_REF_EX(arg, 2); - } - ZVAL_REF(param, Z_REF_P(arg)); + if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + zend_param_must_be_ref(EX(call)->func, opline->op2.num); + Z_TRY_ADDREF_P(arg); + ZVAL_NEW_REF(param, arg); } else { - arg = RT_CONSTANT(opline, opline->op1); - if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { - zend_param_must_be_ref(EX(call)->func, opline->op2.num); - Z_TRY_ADDREF_P(arg); - ZVAL_NEW_REF(param, arg); - } else { - ZVAL_COPY(param, arg); - } + ZVAL_COPY(param, arg); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -19531,24 +19521,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_TMP_HANDLER(ZEN SAVE_OPLINE(); + arg = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); param = ZEND_CALL_VAR(EX(call), opline->result.var); - if (opline->extended_value) { - arg = zend_get_bad_ptr(); - if (Z_ISREF_P(arg)) { - Z_ADDREF_P(arg); - } else { - ZVAL_MAKE_REF_EX(arg, 2); - } - ZVAL_REF(param, Z_REF_P(arg)); + if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + zend_param_must_be_ref(EX(call)->func, opline->op2.num); + Z_TRY_ADDREF_P(arg); + ZVAL_NEW_REF(param, arg); } else { - arg = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { - zend_param_must_be_ref(EX(call)->func, opline->op2.num); - Z_TRY_ADDREF_P(arg); - ZVAL_NEW_REF(param, arg); - } else { - ZVAL_COPY(param, arg); - } + ZVAL_COPY(param, arg); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -22209,10 +22189,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_EXPLICIT_REF_SPEC_VAR_HAN uint32_t arg_num = opline->op2.num; if (EXPECTED(0)) { - if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { goto invalid_send_ref; } - } else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { invalid_send_ref: SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num); @@ -22243,10 +22223,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_EXPLICIT_REF_SPEC_VAR_QUI uint32_t arg_num = opline->op2.num; if (EXPECTED(1)) { - if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { goto invalid_send_ref; } - } else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { invalid_send_ref: SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num); @@ -22277,10 +22257,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_EXPLICIT_REF_FUNC_SPEC_VA uint32_t arg_num = opline->op2.num; if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) { - if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { goto invalid_send_ref; } - } else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { invalid_send_ref: SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num); @@ -22311,24 +22291,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN SAVE_OPLINE(); + arg = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); param = ZEND_CALL_VAR(EX(call), opline->result.var); - if (opline->extended_value) { - arg = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - if (Z_ISREF_P(arg)) { - Z_ADDREF_P(arg); - } else { - ZVAL_MAKE_REF_EX(arg, 2); - } - ZVAL_REF(param, Z_REF_P(arg)); + if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + zend_param_must_be_ref(EX(call)->func, opline->op2.num); + Z_TRY_ADDREF_P(arg); + ZVAL_NEW_REF(param, arg); } else { - arg = _get_zval_ptr_var_deref(opline->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { - zend_param_must_be_ref(EX(call)->func, opline->op2.num); - Z_TRY_ADDREF_P(arg); - ZVAL_NEW_REF(param, arg); - } else { - ZVAL_COPY(param, arg); - } + ZVAL_COPY(param, arg); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -25137,7 +25107,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_EX_SPEC_VAR_CO ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } else { @@ -25149,7 +25119,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_EX_SPEC_VAR_CO ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } @@ -29587,7 +29557,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_EX_SPEC_VAR_UN ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } else { @@ -29599,7 +29569,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_EX_SPEC_VAR_UN ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } @@ -29655,7 +29625,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_EX ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } else { @@ -29667,7 +29637,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_NO_REF_EX ZVAL_COPY_VALUE(arg, varptr); if (EXPECTED(Z_ISREF_P(varptr) || - !ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) { + ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) { ZEND_VM_NEXT_OPCODE(); } } @@ -39894,10 +39864,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_EXPLICIT_REF_SPEC_CV_HAND uint32_t arg_num = opline->op2.num; if (EXPECTED(0)) { - if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { goto invalid_send_ref; } - } else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { invalid_send_ref: SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num); @@ -39927,10 +39897,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_EXPLICIT_REF_SPEC_CV_QUIC uint32_t arg_num = opline->op2.num; if (EXPECTED(1)) { - if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { goto invalid_send_ref; } - } else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { invalid_send_ref: SAVE_OPLINE(); zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num); @@ -39960,24 +39930,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND SAVE_OPLINE(); + arg = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); param = ZEND_CALL_VAR(EX(call), opline->result.var); - if (opline->extended_value) { - arg = _get_zval_ptr_cv_BP_VAR_W(opline->op1.var EXECUTE_DATA_CC); - if (Z_ISREF_P(arg)) { - Z_ADDREF_P(arg); - } else { - ZVAL_MAKE_REF_EX(arg, 2); - } - ZVAL_REF(param, Z_REF_P(arg)); + if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { + zend_param_must_be_ref(EX(call)->func, opline->op2.num); + Z_TRY_ADDREF_P(arg); + ZVAL_NEW_REF(param, arg); } else { - arg = _get_zval_ptr_cv_deref_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) { - zend_param_must_be_ref(EX(call)->func, opline->op2.num); - Z_TRY_ADDREF_P(arg); - ZVAL_NEW_REF(param, arg); - } else { - ZVAL_COPY(param, arg); - } + ZVAL_COPY(param, arg); } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index c85f5b95cabdf..0365c470a3676 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -357,7 +357,7 @@ static uint32_t zend_vm_opcodes_flags[211] = { 0x00001301, 0x01000703, 0x01000000, - 0x00101003, + 0x00001003, 0x00000007, 0x00040003, 0x09000007, diff --git a/build/gen_stub.php b/build/gen_stub.php index d686095979f27..3bf9fb995dce4 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -820,7 +820,6 @@ class ArgInfo { const SEND_BY_VAL = 0; const SEND_BY_REF = 1; const SEND_PREFER_REF = 2; - const SEND_PREFER_VAL = 3; public string $name; public int $sendBy; @@ -867,8 +866,6 @@ public function getSendByString(): string { return "1"; case self::SEND_PREFER_REF: return "ZEND_SEND_PREFER_REF"; - case self::SEND_PREFER_VAL: - return "ZEND_SEND_PREFER_VAL"; } throw new Exception("Invalid sendBy value"); } @@ -4047,7 +4044,7 @@ public function getVariableName(): string { if ($this->name === "param") { // Allow for parsing extended types like callable(string):mixed in docblocks preg_match('/^\s*(?[\w\|\\\\]+(?\((?(?:(?&parens)|[^(){}[\]]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\])*+(?::(?&type))?)\s*\$(?\w+).*$/', $value, $matches); - } elseif ($this->name === "prefer-ref" || $this->name === "prefer-val") { + } elseif ($this->name === "prefer-ref") { preg_match('/^\s*\$(?\w+).*$/', $value, $matches); } @@ -4189,14 +4186,6 @@ function parseFunctionLike( $paramMeta[$varName][$tag->name] = true; break; - case 'prefer-val': - $varName = $tag->getVariableName(); - if (!isset($paramMeta[$varName])) { - $paramMeta[$varName] = []; - } - $paramMeta[$varName][$tag->name] = true; - break; - case 'undocumentable': $isUndocumentable = true; break; @@ -4219,7 +4208,6 @@ function parseFunctionLike( $varName = $param->var->name; $preferRef = !empty($paramMeta[$varName]['prefer-ref']); - $preferVal = !empty($paramMeta[$varName]['prefer-val']); unset($paramMeta[$varName]); if (isset($varNameSet[$varName])) { @@ -4229,8 +4217,6 @@ function parseFunctionLike( if ($preferRef) { $sendBy = ArgInfo::SEND_PREFER_REF; - } else if ($preferVal) { - $sendBy = ArgInfo::SEND_PREFER_VAL; } else if ($param->byRef) { $sendBy = ArgInfo::SEND_BY_REF; } else { diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index a39bf3738e736..dd1f59c64c005 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1996,9 +1996,6 @@ function error_get_last(): ?array {} function error_clear_last(): void {} -/** - * @prefer-val $args - */ function call_user_func(callable $callback, mixed ...$args): mixed {} function call_user_func_array(callable $callback, array $args): mixed {} diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index af2f7827726dc..b7071f5970729 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: f8ef1d29a1471da7d9979dbc6ab14a07e406f713 */ + * Stub hash: 5d8e13990ce18bebc9c7e6a0a9a7ad8b7593d35b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -447,7 +447,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_call_user_func, 0, 1, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) - ZEND_ARG_VARIADIC_TYPE_INFO(ZEND_SEND_PREFER_VAL, args, IS_MIXED, 0) + ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_call_user_func_array, 0, 2, IS_MIXED, 0) @@ -455,10 +455,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_call_user_func_array, 0, 2, IS_M ZEND_ARG_TYPE_INFO(0, args, IS_ARRAY, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_forward_static_call, 0, 1, IS_MIXED, 0) - ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) - ZEND_ARG_VARIADIC_TYPE_INFO(0, args, IS_MIXED, 0) -ZEND_END_ARG_INFO() +#define arginfo_forward_static_call arginfo_call_user_func #define arginfo_forward_static_call_array arginfo_call_user_func_array