Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Zend/Optimizer/zend_func_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ ZEND_API uint32_t zend_get_func_info(
#endif

ret = zend_get_return_info_from_signature_only(
callee_func, /* script */ NULL, ce, ce_is_instanceof);
callee_func, /* script */ NULL, ce, ce_is_instanceof, /* use_tentative_return_info */ 1);

#if ZEND_DEBUG
if (internal_ret) {
Expand Down Expand Up @@ -884,7 +884,7 @@ ZEND_API uint32_t zend_get_func_info(
}
if (!ret) {
ret = zend_get_return_info_from_signature_only(
callee_func, /* TODO: script */ NULL, ce, ce_is_instanceof);
callee_func, /* TODO: script */ NULL, ce, ce_is_instanceof, /* use_tentative_return_info */ 0);
}
}
return ret;
Expand Down
9 changes: 5 additions & 4 deletions Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -4001,9 +4001,11 @@ static int is_recursive_tail_call(const zend_op_array *op_array,

uint32_t zend_get_return_info_from_signature_only(
const zend_function *func, const zend_script *script,
zend_class_entry **ce, bool *ce_is_instanceof) {
zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info) {
uint32_t type;
if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && !ZEND_ARG_TYPE_IS_TENTATIVE(func->common.arg_info - 1)) {
if (func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE &&
(use_tentative_return_info || !ZEND_ARG_TYPE_IS_TENTATIVE(func->common.arg_info - 1))
) {
zend_arg_info *ret_info = func->common.arg_info - 1;
type = zend_fetch_arg_info_type(script, ret_info, ce);
*ce_is_instanceof = ce != NULL;
Expand All @@ -4026,12 +4028,11 @@ ZEND_API void zend_init_func_return_info(
const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret)
{
ZEND_ASSERT((op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE));
ZEND_ASSERT(!ZEND_ARG_TYPE_IS_TENTATIVE(&((zend_function *) op_array)->common.arg_info[-1]));

zend_ssa_range tmp_range = {0, 0, 0, 0};
bool is_instanceof = false;
ret->type = zend_get_return_info_from_signature_only(
(zend_function *) op_array, script, &ret->ce, &is_instanceof);
(zend_function *) op_array, script, &ret->ce, &is_instanceof, /* use_tentative_return_info */ 1);
ret->is_instanceof = is_instanceof;
ret->range = tmp_range;
ret->has_range = 0;
Expand Down
2 changes: 1 addition & 1 deletion Zend/Optimizer/zend_inference.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ ZEND_API void zend_init_func_return_info(
const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret);
uint32_t zend_get_return_info_from_signature_only(
const zend_function *func, const zend_script *script,
zend_class_entry **ce, bool *ce_is_instanceof);
zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info);
void zend_func_return_info(const zend_op_array *op_array,
const zend_script *script,
int recursive,
Expand Down
4 changes: 1 addition & 3 deletions Zend/Optimizer/zend_optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1446,9 +1446,7 @@ ZEND_API int zend_optimize_script(zend_script *script, zend_long optimization_le
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
if (func_info) {
func_info->call_map = zend_build_call_map(&ctx.arena, func_info, call_graph.op_arrays[i]);
if ((call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
!ZEND_ARG_TYPE_IS_TENTATIVE(&((zend_function *) call_graph.op_arrays[i])->common.arg_info[-1])
) {
if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_init_func_return_info(call_graph.op_arrays[i], script, &func_info->return_info);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Internal class as parent
Test unresolvable inheritance check due to unavailable parameter type when the parent has a tentative return type.
--FILE--
<?php

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Internal class as parent
Test unresolvable inheritance check due to unavailable return type when the parent has a tentative return type.
--FILE--
<?php

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Test that the ReturnTypeWillChange attribute cannot target classes
--FILE--
<?php

#[ReturnTypeWillChange]
class Foo
{
}

?>
--EXPECTF--
Fatal error: Attribute "ReturnTypeWillChange" cannot target class (allowed targets: method) in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--TEST--
Test that the ReturnTypeWillChange attribute cannot target functions
--FILE--
<?php

#[ReturnTypeWillChange]
function foo() {}

?>
--EXPECTF--
Fatal error: Attribute "ReturnTypeWillChange" cannot target function (allowed targets: method) in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
Test that the ReturnTypeWillChange attribute cannot be used with functions
--FILE--
<?php

class Foo
{
#[ReturnTypeWillChange]
public int $bar;
}

?>
--EXPECTF--
Fatal error: Attribute "ReturnTypeWillChange" cannot target property (allowed targets: method) in %s on line %d
10 changes: 1 addition & 9 deletions Zend/zend_attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,6 @@ void validate_attribute(zend_attribute *attr, uint32_t target, zend_class_entry
}
}

void validate_return_type_will_change_attribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
{
if (target != ZEND_ATTRIBUTE_TARGET_METHOD) {
zend_error(E_COMPILE_ERROR, "Only methods can be marked with #[ReturnTypeWillChange]");
}
}

ZEND_METHOD(Attribute, __construct)
{
zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL;
Expand Down Expand Up @@ -293,8 +286,7 @@ void zend_register_attribute_ce(void)
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("IS_REPEATABLE"), ZEND_ATTRIBUTE_IS_REPEATABLE);

zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange();
attr = zend_internal_attribute_register(zend_ce_return_type_will_change_attribute, ZEND_ATTRIBUTE_TARGET_METHOD);
attr->validator = validate_return_type_will_change_attribute;
zend_internal_attribute_register(zend_ce_return_type_will_change_attribute, ZEND_ATTRIBUTE_TARGET_METHOD);
}

void zend_attributes_shutdown(void)
Expand Down
8 changes: 4 additions & 4 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1305,7 +1305,7 @@ static void zend_mark_function_as_generator() /* {{{ */
"The \"yield\" expression can only be used inside a function");
}

if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE && !ZEND_ARG_TYPE_IS_TENTATIVE(&(CG(active_op_array))->arg_info[-1])) {
if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_type return_type = CG(active_op_array)->arg_info[-1].type;
bool valid_type = (ZEND_TYPE_FULL_MASK(return_type) & (MAY_BE_ITERABLE | MAY_BE_OBJECT)) != 0;
if (!valid_type) {
Expand Down Expand Up @@ -2424,7 +2424,7 @@ static void zend_emit_return_type_check(
znode *expr, zend_arg_info *return_info, bool implicit) /* {{{ */
{
zend_type type = return_info->type;
if (ZEND_TYPE_IS_SET(type) && !ZEND_ARG_TYPE_IS_TENTATIVE(return_info)) {
if (ZEND_TYPE_IS_SET(type)) {
zend_op *opline;

/* `return ...;` is illegal in a void function (but `return;` isn't) */
Expand Down Expand Up @@ -6476,7 +6476,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
arg_infos->type = zend_compile_typename(
return_type_ast, /* force_allow_null */ 0);
ZEND_TYPE_FULL_MASK(arg_infos->type) |= _ZEND_ARG_INFO_FLAGS(
(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0, /* is_variadic */ 0, 0);
(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0, /* is_variadic */ 0, /* is_tentative */ 0);
} else {
arg_infos->type = (zend_type) ZEND_TYPE_INIT_CODE(fallback_return_type, 0, 0);
}
Expand Down Expand Up @@ -6606,7 +6606,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fall
zend_alloc_cache_slots(zend_type_get_num_classes(arg_info->type));
}

uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, 0)
uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, /* is_tentative */ 0)
| (visibility ? _ZEND_IS_PROMOTED_BIT : 0);
ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags;
if (opcode == ZEND_RECV) {
Expand Down
19 changes: 9 additions & 10 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1294,19 +1294,18 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con
static bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
{
zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1;
if (!ZEND_ARG_TYPE_IS_TENTATIVE(ret_info)) {
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) {
if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) {
zend_verify_void_return_error(zf, zend_zval_type_name(ret), "");
return 0;
}
return 1;
}

if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) {
zend_verify_internal_return_error(zf, ret);
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_VOID) {
if (UNEXPECTED(Z_TYPE_P(ret) != IS_NULL)) {
zend_verify_void_return_error(zf, zend_zval_type_name(ret), "");
return 0;
}
return 1;
}

if (UNEXPECTED(!zend_check_type(&ret_info->type, ret, /* cache_slot */ NULL, NULL, 1, /* is_internal */ 1))) {
zend_verify_internal_return_error(zf, ret);
return 0;
}

return 1;
Expand Down
8 changes: 4 additions & 4 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -869,10 +869,10 @@ static void ZEND_COLD emit_incompatible_method_error(
ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
} else if (status == INHERITANCE_WARNING) {
zend_attribute *return_type_will_change_attribute = zend_get_attribute_str(
child->common.attributes,
"returntypewillchange",
sizeof("returntypewillchange")-1
);
child->common.attributes,
"returntypewillchange",
sizeof("returntypewillchange")-1
);

if (!return_type_will_change_attribute) {
zend_error_at(E_DEPRECATED, NULL, func_lineno(child),
Expand Down
6 changes: 2 additions & 4 deletions ext/opcache/ZendAccelerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_int
if (Z_FUNC(p->val)->common.function_name) {
Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name);
}
if ((Z_FUNC(p->val)->common.arg_info) &&
if (Z_FUNC(p->val)->common.arg_info &&
(Z_FUNC(p->val)->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) {
uint32_t i;
uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1;
Expand Down Expand Up @@ -3885,9 +3885,7 @@ static bool preload_needed_types_known(zend_class_entry *ce) {
zend_string *lcname;
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, lcname, fptr) {
uint32_t i;
if ((fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
!ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1])
) {
if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
if (!preload_is_type_known(ce, &fptr->common.arg_info[-1].type) &&
preload_is_method_maybe_override(ce, lcname)) {
return 0;
Expand Down
8 changes: 2 additions & 6 deletions ext/opcache/jit/zend_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -3604,9 +3604,7 @@ static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, cons
}
func_info = ZEND_FUNC_INFO(op_array);
func_info->call_map = zend_build_call_map(&CG(arena), func_info, op_array);
if ((op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
!ZEND_ARG_TYPE_IS_TENTATIVE(&((zend_function *) op_array)->common.arg_info[-1])
) {
if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_init_func_return_info(op_array, script, &func_info->return_info);
}
}
Expand Down Expand Up @@ -3922,9 +3920,7 @@ ZEND_EXT_API int zend_jit_script(zend_script *script)
info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
if (info) {
info->call_map = zend_build_call_map(&CG(arena), info, call_graph.op_arrays[i]);
if ((call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
!ZEND_ARG_TYPE_IS_TENTATIVE(&((zend_function *) call_graph.op_arrays[i])->common.arg_info[-1])
) {
if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_init_func_return_info(call_graph.op_arrays[i], script, &info->return_info);
}
}
Expand Down
4 changes: 1 addition & 3 deletions ext/opcache/jit/zend_jit_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,9 +489,7 @@ static zend_ssa *zend_jit_trace_build_ssa(const zend_op_array *op_array, zend_sc
break;
}
jit_extension->func_info.call_map = zend_build_call_map(&CG(arena), &jit_extension->func_info, op_array);
if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE &&
!ZEND_ARG_TYPE_IS_TENTATIVE(&((zend_function *) op_array)->common.arg_info[-1])
) {
if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_init_func_return_info(op_array, script, &jit_extension->func_info.return_info);
}
}
Expand Down