diff --git a/Zend/tests/attributes/override/properties_01.phpt b/Zend/tests/attributes/override/properties_01.phpt new file mode 100644 index 0000000000000..d83f935f83496 --- /dev/null +++ b/Zend/tests/attributes/override/properties_01.phpt @@ -0,0 +1,39 @@ +--TEST-- +#[\Override]: Properties +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_02.phpt b/Zend/tests/attributes/override/properties_02.phpt new file mode 100644 index 0000000000000..3791ee2fe5a2b --- /dev/null +++ b/Zend/tests/attributes/override/properties_02.phpt @@ -0,0 +1,16 @@ +--TEST-- +#[\Override]: Properties: No parent class. +--FILE-- + +--EXPECTF-- +Fatal error: C::$c has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_03.phpt b/Zend/tests/attributes/override/properties_03.phpt new file mode 100644 index 0000000000000..c2b2ea0acc2e0 --- /dev/null +++ b/Zend/tests/attributes/override/properties_03.phpt @@ -0,0 +1,21 @@ +--TEST-- +#[\Override]: Properties: No parent class, but child implements matching interface. +--FILE-- + +--EXPECTF-- +Fatal error: P::$i has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_04.phpt b/Zend/tests/attributes/override/properties_04.phpt new file mode 100644 index 0000000000000..142a1d0c640ac --- /dev/null +++ b/Zend/tests/attributes/override/properties_04.phpt @@ -0,0 +1,21 @@ +--TEST-- +#[\Override]: Properties: No parent class, but child implements matching interface (2). +--FILE-- + +--EXPECTF-- +Fatal error: P::$i has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_05.phpt b/Zend/tests/attributes/override/properties_05.phpt new file mode 100644 index 0000000000000..71113dad60e43 --- /dev/null +++ b/Zend/tests/attributes/override/properties_05.phpt @@ -0,0 +1,26 @@ +--TEST-- +#[\Override]: Properties: No parent interface. +--FILE-- + +--EXPECTF-- +Fatal error: I::$i has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_06.phpt b/Zend/tests/attributes/override/properties_06.phpt new file mode 100644 index 0000000000000..66309ac625c0c --- /dev/null +++ b/Zend/tests/attributes/override/properties_06.phpt @@ -0,0 +1,15 @@ +--TEST-- +#[\Override]: Properties: On trait. +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_07.phpt b/Zend/tests/attributes/override/properties_07.phpt new file mode 100644 index 0000000000000..e09cfe3a46a5f --- /dev/null +++ b/Zend/tests/attributes/override/properties_07.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Properties: On used trait without parent method. +--FILE-- + +--EXPECTF-- +Fatal error: Foo::$t has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_08.phpt b/Zend/tests/attributes/override/properties_08.phpt new file mode 100644 index 0000000000000..fb3cd508c4249 --- /dev/null +++ b/Zend/tests/attributes/override/properties_08.phpt @@ -0,0 +1,23 @@ +--TEST-- +#[\Override]: Properties: On used trait with interface method. +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_09.phpt b/Zend/tests/attributes/override/properties_09.phpt new file mode 100644 index 0000000000000..05fbb4c83ed81 --- /dev/null +++ b/Zend/tests/attributes/override/properties_09.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Properties: Parent property is private. +--FILE-- + +--EXPECTF-- +Fatal error: C::$p has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_10.phpt b/Zend/tests/attributes/override/properties_10.phpt new file mode 100644 index 0000000000000..918d248748e27 --- /dev/null +++ b/Zend/tests/attributes/override/properties_10.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Properties: Parent property is private (2). +--FILE-- + +--EXPECTF-- +Fatal error: C::$p has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_11.phpt b/Zend/tests/attributes/override/properties_11.phpt new file mode 100644 index 0000000000000..0eeedd4f86060 --- /dev/null +++ b/Zend/tests/attributes/override/properties_11.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Properties: Parent property is protected. +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_12.phpt b/Zend/tests/attributes/override/properties_12.phpt new file mode 100644 index 0000000000000..94d35454f789b --- /dev/null +++ b/Zend/tests/attributes/override/properties_12.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Properties: Parent property is protected (2). +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_13.phpt b/Zend/tests/attributes/override/properties_13.phpt new file mode 100644 index 0000000000000..d9ab0a6b9a299 --- /dev/null +++ b/Zend/tests/attributes/override/properties_13.phpt @@ -0,0 +1,21 @@ +--TEST-- +#[\Override]: Properties: Redeclared trait property. +--FILE-- + +--EXPECTF-- +Fatal error: C::$t has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_14.phpt b/Zend/tests/attributes/override/properties_14.phpt new file mode 100644 index 0000000000000..4e098c6d7212c --- /dev/null +++ b/Zend/tests/attributes/override/properties_14.phpt @@ -0,0 +1,25 @@ +--TEST-- +#[\Override]: Properties: Redeclared trait property with interface. +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_15.phpt b/Zend/tests/attributes/override/properties_15.phpt new file mode 100644 index 0000000000000..37d46b2a170a3 --- /dev/null +++ b/Zend/tests/attributes/override/properties_15.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Properties: Valid anonymous class. +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_16.phpt b/Zend/tests/attributes/override/properties_16.phpt new file mode 100644 index 0000000000000..57ea17818c406 --- /dev/null +++ b/Zend/tests/attributes/override/properties_16.phpt @@ -0,0 +1,21 @@ +--TEST-- +#[\Override]: Properties: Invalid anonymous class. +--FILE-- + +--EXPECTF-- +Fatal error: I@anonymous::$c has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_17.phpt b/Zend/tests/attributes/override/properties_17.phpt new file mode 100644 index 0000000000000..389d66035ea44 --- /dev/null +++ b/Zend/tests/attributes/override/properties_17.phpt @@ -0,0 +1,16 @@ +--TEST-- +#[\Override]: Properties: Static property no parent class. +--FILE-- + +--EXPECTF-- +Fatal error: C::$c has #[\Override] attribute, but no matching parent property exists in %s on line %d diff --git a/Zend/tests/attributes/override/properties_18.phpt b/Zend/tests/attributes/override/properties_18.phpt new file mode 100644 index 0000000000000..66731a69f8e8a --- /dev/null +++ b/Zend/tests/attributes/override/properties_18.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Override]: Properties: Static property. +--FILE-- + +--EXPECT-- +Done diff --git a/Zend/tests/attributes/override/properties_19.phpt b/Zend/tests/attributes/override/properties_19.phpt new file mode 100644 index 0000000000000..79708eb27a0ca --- /dev/null +++ b/Zend/tests/attributes/override/properties_19.phpt @@ -0,0 +1,20 @@ +--TEST-- +#[\Override]: Properties: valid promoted property +--FILE-- +args[0].value, &attribute_Attribute_class_Override_0_arg0); return class_entry; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f3f6d1b75aec1..fe62b4c1d7a2b 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7881,6 +7881,11 @@ static void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32 zend_compile_attributes( &prop->attributes, attributes_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, ZEND_ATTRIBUTE_TARGET_PARAMETER); } + + zend_attribute *override_attribute = zend_get_attribute_str(prop->attributes, "override", sizeof("override")-1); + if (override_attribute) { + prop->flags |= ZEND_ACC_OVERRIDE; + } } } @@ -8859,6 +8864,11 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f zend_compile_attributes(&info->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY, 0); } + zend_attribute *override_attribute = zend_get_attribute_str(info->attributes, "override", sizeof("override")-1); + if (override_attribute) { + info->flags |= ZEND_ACC_OVERRIDE; + } + CG(context).active_property_info_name = old_active_property_info_name; } } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 7ac0a2b8b2c44..c663c34d91ddc 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -253,7 +253,10 @@ typedef struct _zend_oparray_context { /* or IS_CONSTANT_VISITED_MARK | | | */ #define ZEND_CLASS_CONST_IS_CASE (1 << 6) /* | | | X */ /* | | | */ -/* Property Flags (unused: 13...) | | | */ +/* has #[\Override] attribute | | | */ +#define ZEND_ACC_OVERRIDE (1 << 28) /* | X | X | */ +/* | | | */ +/* Property Flags (unused: 13-27,29...) | | | */ /* =========== | | | */ /* | | | */ /* Promoted property / parameter | | | */ @@ -392,9 +395,6 @@ typedef struct _zend_oparray_context { /* supports opcache compile-time evaluation (funcs) | | | */ #define ZEND_ACC_COMPILE_TIME_EVAL (1 << 27) /* | X | | */ /* | | | */ -/* has #[\Override] attribute | | | */ -#define ZEND_ACC_OVERRIDE (1 << 28) /* | X | | */ -/* | | | */ /* Has IS_PTR operands that needs special cleaning; same | | | */ /* value as ZEND_ACC_OVERRIDE but override is for class | | | */ /* methods and this is for the top level op array | | | */ diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index d27cca5b76187..155ec084a462c 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1566,6 +1566,10 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke ZSTR_VAL(key), ZSTR_VAL(parent_info->ce->name)); } + + if (child_info->flags & ZEND_ACC_OVERRIDE) { + child_info->flags &= ~ZEND_ACC_OVERRIDE; + } } } else { zend_function **hooks = parent_info->hooks; @@ -2304,6 +2308,7 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry void zend_inheritance_check_override(const zend_class_entry *ce) { zend_function *f; + zend_property_info *p; if (ce->ce_flags & ZEND_ACC_TRAIT) { return; @@ -2320,6 +2325,15 @@ void zend_inheritance_check_override(const zend_class_entry *ce) } } ZEND_HASH_FOREACH_END(); + ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, p) { + if (p->flags & ZEND_ACC_OVERRIDE) { + zend_error_noreturn( + E_COMPILE_ERROR, + "%s::$%s has #[\\Override] attribute, but no matching parent property exists", + ZSTR_VAL(ce->name), zend_get_unmangled_property_name(p->name)); + } + } ZEND_HASH_FOREACH_END(); + if (ce->num_hooked_props) { zend_property_info *prop; ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {