From cbc4e8ba0137133c19572c2d618da51060d8cb63 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 3 Nov 2025 10:49:22 -0800 Subject: [PATCH 1/3] Fix GH-20377: emit assignment for all final promoted properties Previously, the assignment op line was only emitted when one of the other flags allowed for promoted properties (visibility, set visibility, or readonly) was also used, or when the property had hooks. The property was still added to the class, but the magical assignment `$this->prop = $prop` was missing. Add that assignment even when no visibility is explicitly specified, and a test to confirm the fix. --- .../ctor_promotion/ctor_promotion_final.phpt | 23 +++++++++++++++++++ Zend/zend_compile.c | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/ctor_promotion/ctor_promotion_final.phpt diff --git a/Zend/tests/ctor_promotion/ctor_promotion_final.phpt b/Zend/tests/ctor_promotion/ctor_promotion_final.phpt new file mode 100644 index 0000000000000..abfb5b7088082 --- /dev/null +++ b/Zend/tests/ctor_promotion/ctor_promotion_final.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-20377: Constructor promotion with a final property without visibility set +--FILE-- + +--EXPECTF-- +object(Demo)#%d (2) { + ["foo"]=> + string(5) "first" + ["bar"]=> + string(6) "second" +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0180e6e8e1c0a..f8b8c148005f2 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8008,7 +8008,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 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_PPP_SET_MASK | ZEND_ACC_READONLY); + uint32_t flags = param_ast->attr & (ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY | ZEND_ACC_FINAL); bool is_promoted = flags || hooks_ast; if (!is_promoted) { continue; From f0d06b184bc3cc442729c6fc926c74abfab7d65f Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 3 Nov 2025 11:57:18 -0800 Subject: [PATCH 2/3] Deduplicate list of flags --- Zend/zend_compile.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f8b8c148005f2..8be1ee14f4859 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7770,6 +7770,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 } } + const uint32_t promotion_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_READONLY | ZEND_ACC_FINAL; for (i = 0; i < list->children; ++i) { zend_ast *param_ast = list->child[i]; zend_ast *type_ast = param_ast->child[0]; @@ -7781,7 +7782,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 zend_string *name = zval_make_interned_string(zend_ast_get_zval(var_ast)); 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_PPP_SET_MASK | ZEND_ACC_READONLY | ZEND_ACC_FINAL); + uint32_t property_flags = param_ast->attr & promotion_flags; bool is_promoted = property_flags || hooks_ast; CG(zend_lineno) = param_ast->lineno; @@ -8008,7 +8009,7 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 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_PPP_SET_MASK | ZEND_ACC_READONLY | ZEND_ACC_FINAL); + uint32_t flags = param_ast->attr & promotion_flags; bool is_promoted = flags || hooks_ast; if (!is_promoted) { continue; From fdb5553c61e91ac018be2239be251da46ed36620 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 3 Nov 2025 11:58:16 -0800 Subject: [PATCH 3/3] NEWS --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 8652023266a36..382d23f1f4e97 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,8 @@ PHP NEWS (ilutov) . Fixed bug GH-20194 (null offset deprecation not emitted for writes). (Girgias) + . Fixed bug GH-GH-20377 (final promoted properties without explicit visibility + not automatically assigned). (DanielEScherzer) - Opcache: . Fixed bug GH-20012 (heap buffer overflow in jit). (Arnaud)