Skip to content

Commit 2dcbfca

Browse files
GH-16067: prevent abstract in methods of anonymous classes
As an extra benefit, the error message now points to the line of the method rather than just the overall class declaration.
1 parent 4a20e09 commit 2dcbfca

File tree

4 files changed

+55
-7
lines changed

4 files changed

+55
-7
lines changed

Zend/tests/anon/gh16067.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ $c = new class {
88
}
99
?>
1010
--EXPECTF--
11-
Fatal error: Class class@anonymous must implement 1 abstract method (class@anonymous::f) in %s on line 3
11+
Fatal error: Cannot use the abstract modifier on a method of an anonymous class in %s on line 4

Zend/zend_compile.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,14 +900,17 @@ uint32_t zend_modifier_token_to_flag(zend_modifier_target target, uint32_t token
900900
break;
901901
case T_FINAL:
902902
if (target == ZEND_MODIFIER_TARGET_METHOD
903+
|| target == ZEND_MODIFIER_TARGET_ANON_CLASS_METHOD
903904
|| target == ZEND_MODIFIER_TARGET_CONSTANT
904905
|| target == ZEND_MODIFIER_TARGET_PROPERTY
905906
|| target == ZEND_MODIFIER_TARGET_PROPERTY_HOOK) {
906907
return ZEND_ACC_FINAL;
907908
}
908909
break;
909910
case T_STATIC:
910-
if (target == ZEND_MODIFIER_TARGET_PROPERTY || target == ZEND_MODIFIER_TARGET_METHOD) {
911+
if (target == ZEND_MODIFIER_TARGET_PROPERTY
912+
|| target == ZEND_MODIFIER_TARGET_METHOD
913+
|| target == ZEND_MODIFIER_TARGET_ANON_CLASS_METHOD) {
911914
return ZEND_ACC_STATIC;
912915
}
913916
break;
@@ -933,6 +936,8 @@ uint32_t zend_modifier_token_to_flag(zend_modifier_target target, uint32_t token
933936
member = "property";
934937
} else if (target == ZEND_MODIFIER_TARGET_METHOD) {
935938
member = "method";
939+
} else if (target == ZEND_MODIFIER_TARGET_ANON_CLASS_METHOD) {
940+
member = "method of an anonymous class";
936941
} else if (target == ZEND_MODIFIER_TARGET_CONSTANT) {
937942
member = "class constant";
938943
} else if (target == ZEND_MODIFIER_TARGET_CPP) {
@@ -1036,6 +1041,8 @@ uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag, zend_modifi
10361041
"Multiple readonly modifiers are not allowed", 0);
10371042
return 0;
10381043
}
1044+
// No need for the final+abstract check on anonymous class methods, since
1045+
// abstract methods are not allowed
10391046
if (target == ZEND_MODIFIER_TARGET_METHOD && (new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) {
10401047
zend_throw_exception(zend_ce_compile_error,
10411048
"Cannot use the final modifier on an abstract method", 0);

Zend/zend_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,7 @@ void zend_emit_final_return(bool return_one);
891891
typedef enum {
892892
ZEND_MODIFIER_TARGET_PROPERTY = 0,
893893
ZEND_MODIFIER_TARGET_METHOD,
894+
ZEND_MODIFIER_TARGET_ANON_CLASS_METHOD,
894895
ZEND_MODIFIER_TARGET_CONSTANT,
895896
ZEND_MODIFIER_TARGET_CPP,
896897
ZEND_MODIFIER_TARGET_PROPERTY_HOOK,

Zend/zend_language_parser.y

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
258258
%type <ast> foreach_statement declare_statement finally_statement unset_variable variable
259259
%type <ast> extends_from parameter optional_type_without_static argument global_var
260260
%type <ast> static_var class_statement trait_adaptation trait_precedence trait_alias
261+
%type <ast> class_statement_anon class_statement_list_anon
261262
%type <ast> absolute_trait_method_reference trait_method_reference property echo_expr
262263
%type <ast> new_dereferenceable new_non_dereferenceable anonymous_class class_name class_name_reference simple_variable
263264
%type <ast> internal_functions_in_yacc
@@ -278,6 +279,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
278279
%type <ast> isset_variable type return_type type_expr type_without_static
279280
%type <ast> identifier type_expr_without_static union_type_without_static_element union_type_without_static intersection_type_without_static
280281
%type <ast> inline_function union_type_element union_type intersection_type
282+
%type <ast> attributed_class_statement_common attributed_class_statement_anon
281283
%type <ast> attributed_statement attributed_class_statement attributed_parameter
282284
%type <ast> attribute_decl attribute attributes attribute_group namespace_declaration_name
283285
%type <ast> match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list
@@ -288,6 +290,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
288290

289291
%type <num> returns_ref function fn is_reference is_variadic property_modifiers property_hook_modifiers
290292
%type <num> method_modifiers class_const_modifiers member_modifier optional_cpp_modifiers
293+
%type <num> method_modifiers_anon
291294
%type <num> class_modifiers class_modifier anonymous_class_modifiers anonymous_class_modifiers_optional use_type backup_fn_flags
292295

293296
%type <ptr> backup_lex_pos
@@ -941,8 +944,17 @@ class_statement_list:
941944
{ $$ = zend_ast_create_list(0, ZEND_AST_STMT_LIST); }
942945
;
943946

947+
class_statement_list_anon:
948+
class_statement_list_anon class_statement_anon
949+
{ $$ = zend_ast_list_add($1, $2); }
950+
| %empty
951+
{ $$ = zend_ast_create_list(0, ZEND_AST_STMT_LIST); }
952+
;
944953

945-
attributed_class_statement:
954+
/* Attributed class statements allowed in anonymous classes as well as normal
955+
* classes/interfaces/traits/enums
956+
*/
957+
attributed_class_statement_common:
946958
property_modifiers optional_type_without_static property_list ';'
947959
{ $$ = zend_ast_create(ZEND_AST_PROP_GROUP, $2, $3, NULL);
948960
$$->attr = $1; }
@@ -955,11 +967,23 @@ attributed_class_statement:
955967
| class_const_modifiers T_CONST type_expr class_const_list ';'
956968
{ $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $4, NULL, $3);
957969
$$->attr = $1; }
970+
| enum_case { $$ = $1; }
971+
;
972+
973+
attributed_class_statement:
974+
attributed_class_statement_common { $$ = $1; }
958975
| method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')'
959976
return_type backup_fn_flags method_body backup_fn_flags
960-
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1 | $12, $2, $5,
961-
zend_ast_get_str($4), $7, NULL, $11, $9, NULL); CG(extra_fn_flags) = $10; }
962-
| enum_case { $$ = $1; }
977+
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1 | $12, $2, $5,
978+
zend_ast_get_str($4), $7, NULL, $11, $9, NULL); CG(extra_fn_flags) = $10; }
979+
;
980+
981+
attributed_class_statement_anon:
982+
attributed_class_statement_common { $$ = $1; }
983+
| method_modifiers_anon function returns_ref identifier backup_doc_comment '(' parameter_list ')'
984+
return_type backup_fn_flags method_body backup_fn_flags
985+
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1 | $12, $2, $5,
986+
zend_ast_get_str($4), $7, NULL, $11, $9, NULL); CG(extra_fn_flags) = $10; }
963987
;
964988

965989
class_statement:
@@ -969,6 +993,13 @@ class_statement:
969993
{ $$ = zend_ast_create(ZEND_AST_USE_TRAIT, $2, $3); }
970994
;
971995

996+
class_statement_anon:
997+
attributed_class_statement_anon { $$ = $1; }
998+
| attributes attributed_class_statement_anon { $$ = zend_ast_with_attributes($2, $1); }
999+
| T_USE class_name_list trait_adaptations
1000+
{ $$ = zend_ast_create(ZEND_AST_USE_TRAIT, $2, $3); }
1001+
;
1002+
9721003
class_name_list:
9731004
class_name { $$ = zend_ast_create_list(1, ZEND_AST_NAME_LIST, $1); }
9741005
| class_name_list ',' class_name { $$ = zend_ast_list_add($1, $3); }
@@ -1049,6 +1080,15 @@ method_modifiers:
10491080
if (!($$ & ZEND_ACC_PPP_MASK)) { $$ |= ZEND_ACC_PUBLIC; } }
10501081
;
10511082

1083+
method_modifiers_anon:
1084+
%empty
1085+
{ $$ = ZEND_ACC_PUBLIC; }
1086+
| non_empty_member_modifiers
1087+
{ $$ = zend_modifier_list_to_flags(ZEND_MODIFIER_TARGET_ANON_CLASS_METHOD, $1);
1088+
if (!$$) { YYERROR; }
1089+
if (!($$ & ZEND_ACC_PPP_MASK)) { $$ |= ZEND_ACC_PUBLIC; } }
1090+
;
1091+
10521092
class_const_modifiers:
10531093
%empty
10541094
{ $$ = ZEND_ACC_PUBLIC; }
@@ -1179,7 +1219,7 @@ non_empty_for_exprs:
11791219

11801220
anonymous_class:
11811221
anonymous_class_modifiers_optional T_CLASS { $<num>$ = CG(zend_lineno); } ctor_arguments
1182-
extends_from implements_list backup_doc_comment '{' class_statement_list '}' {
1222+
extends_from implements_list backup_doc_comment '{' class_statement_list_anon '}' {
11831223
zend_ast *decl = zend_ast_create_decl(
11841224
ZEND_AST_CLASS, ZEND_ACC_ANON_CLASS | $1, $<num>3, $7, NULL,
11851225
$5, $6, $9, NULL, NULL);

0 commit comments

Comments
 (0)