Fix param with hooks but no visibility not treated as cpp (GH-15442)

Fixes GH-15438
This commit is contained in:
Ilija Tovilo 2024-08-19 14:53:54 +02:00 committed by GitHub
parent 144c086c46
commit 770616b823
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 9 deletions

2
NEWS
View File

@ -5,6 +5,8 @@ PHP NEWS
- Core:
. Fixed bug GH-15408 (MSan false-positve on zend_max_execution_timer).
(zeriyoshi)
. Fixed bug GH-15438 (Hooks on constructor promoted properties without
visibility are ignored). (ilutov)
15 Aug 2024, PHP 8.4.0beta3

View File

@ -0,0 +1,20 @@
--TEST--
GH-15438: Promoted properties with hooks but no visibility
--FILE--
<?php
class C {
public function __construct(
$prop { set => $value * 2; }
) {}
}
$c = new C(42);
var_dump($c);
?>
--EXPECTF--
object(C)#%d (1) {
["prop"]=>
int(84)
}

View File

@ -0,0 +1,20 @@
--TEST--
GH-15438: Untyped promoted, hooked properties with no default value default to null
--FILE--
<?php
class C {
public function __construct(
public $prop { set => $value * 2; }
) {}
}
$c = new ReflectionClass(C::class)->newInstanceWithoutConstructor();
var_dump($c);
?>
--EXPECTF--
object(C)#%d (1) {
["prop"]=>
NULL
}

View File

@ -7570,6 +7570,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
uint32_t property_flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_READONLY);
bool is_promoted = property_flags || hooks_ast;
znode var_node, default_node;
uint8_t opcode;
@ -7626,14 +7627,14 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
if (attributes_ast) {
zend_compile_attributes(
&op_array->attributes, attributes_ast, i + 1, ZEND_ATTRIBUTE_TARGET_PARAMETER,
property_flags ? ZEND_ATTRIBUTE_TARGET_PROPERTY : 0
is_promoted ? ZEND_ATTRIBUTE_TARGET_PROPERTY : 0
);
}
bool forced_allow_nullable = false;
if (type_ast) {
uint32_t default_type = *default_ast_ptr ? Z_TYPE(default_node.u.constant) : IS_UNDEF;
bool force_nullable = default_type == IS_NULL && !property_flags;
bool force_nullable = default_type == IS_NULL && !is_promoted;
op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
arg_info->type = zend_compile_typename_ex(type_ast, force_nullable, &forced_allow_nullable);
@ -7696,14 +7697,14 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
}
uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, /* is_tentative */ 0)
| (property_flags ? _ZEND_IS_PROMOTED_BIT : 0);
| (is_promoted ? _ZEND_IS_PROMOTED_BIT : 0);
ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags;
if (opcode == ZEND_RECV) {
opline->op2.num = type_ast ?
ZEND_TYPE_FULL_MASK(arg_info->type) : MAY_BE_ANY;
}
if (property_flags) {
if (is_promoted) {
zend_op_array *op_array = CG(active_op_array);
zend_class_entry *scope = op_array->scope;
@ -7790,9 +7791,11 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32
for (i = 0; i < list->children; i++) {
zend_ast *param_ast = list->child[i];
zend_ast *hooks_ast = param_ast->child[5];
bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
uint32_t flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_READONLY);
if (!flags) {
bool is_promoted = flags || hooks_ast;
if (!is_promoted) {
continue;
}
@ -8543,6 +8546,10 @@ static void zend_compile_property_hooks(
/* Will be removed again, in case of Iterator or IteratorAggregate. */
ce->get_iterator = zend_hooked_object_get_iterator;
}
if (!prop_info->ce->parent_name) {
zend_verify_hooked_property(ce, prop_info, prop_name);
}
}
static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, zend_ast *attr_ast) /* {{{ */
@ -8679,10 +8686,6 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f
if (hooks_ast) {
zend_compile_property_hooks(info, name, type_ast, zend_ast_get_list(hooks_ast));
if (!ce->parent_name) {
zend_verify_hooked_property(ce, info, name);
}
}
if (attr_ast) {