From ce26d84edd85c7331f566a570a5a602755e68e5c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 20 May 2023 18:20:13 +0200 Subject: [PATCH] Correctly handle multiple constants in typed declaration While here also fix AST printing support. --- .../typed_class_constants_ast_print.phpt | 18 ++++++++++++++ ...ed_class_constants_multiple_constants.phpt | 12 ++++++++++ Zend/zend_ast.c | 4 ++++ Zend/zend_ast.h | 4 ++-- Zend/zend_compile.c | 6 ++--- Zend/zend_language_parser.y | 24 ++++++++++--------- 6 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 Zend/tests/type_declarations/typed_class_constants_ast_print.phpt create mode 100644 Zend/tests/type_declarations/typed_class_constants_multiple_constants.phpt diff --git a/Zend/tests/type_declarations/typed_class_constants_ast_print.phpt b/Zend/tests/type_declarations/typed_class_constants_ast_print.phpt new file mode 100644 index 0000000000000..dd4957f2269c5 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_ast_print.phpt @@ -0,0 +1,18 @@ +--TEST-- +AST printing support for typed constants +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +assert(false && new class { + public const int X = 1; +}) diff --git a/Zend/tests/type_declarations/typed_class_constants_multiple_constants.phpt b/Zend/tests/type_declarations/typed_class_constants_multiple_constants.phpt new file mode 100644 index 0000000000000..8d973b2e5d591 --- /dev/null +++ b/Zend/tests/type_declarations/typed_class_constants_multiple_constants.phpt @@ -0,0 +1,12 @@ +--TEST-- +Multiple typed constants in one declaration +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use string as value for class constant Test::Y of type int in %s on line %d diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 70d01bb9f85f3..954c9958c534d 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1924,6 +1924,10 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio zend_ast_export_visibility(str, ast->attr); smart_str_appends(str, "const "); + if (ast->child[2]) { + zend_ast_export_type(str, ast->child[2], indent); + smart_str_appendc(str, ' '); + } ast = ast->child[0]; diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 73e4fed7a997a..0bbb3a820c291 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -145,7 +145,6 @@ enum _zend_ast_kind { ZEND_AST_USE_ELEM, ZEND_AST_TRAIT_ALIAS, ZEND_AST_GROUP_USE, - ZEND_AST_CLASS_CONST_GROUP, ZEND_AST_ATTRIBUTE, ZEND_AST_MATCH, ZEND_AST_MATCH_ARM, @@ -161,6 +160,8 @@ enum _zend_ast_kind { ZEND_AST_CATCH, ZEND_AST_PROP_GROUP, ZEND_AST_PROP_ELEM, + ZEND_AST_CONST_ELEM, + ZEND_AST_CLASS_CONST_GROUP, // Pseudo node for initializing enums ZEND_AST_CONST_ENUM_INIT, @@ -169,7 +170,6 @@ enum _zend_ast_kind { ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_FOREACH, ZEND_AST_ENUM_CASE, - ZEND_AST_CONST_ELEM, /* 5 child nodes */ ZEND_AST_PARAM = 5 << ZEND_AST_NUM_CHILDREN_SHIFT, diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 04244b0de626a..bb12e55848b2f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7693,7 +7693,7 @@ static void zend_check_trait_alias_modifiers(uint32_t attr) /* {{{ */ } /* }}} */ -static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast) +static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast, zend_ast *type_ast) { zend_ast_list *list = zend_ast_get_list(ast); zend_class_entry *ce = CG(active_class_entry); @@ -7705,7 +7705,6 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as zend_ast *name_ast = const_ast->child[0]; zend_ast **value_ast_ptr = &const_ast->child[1]; zend_ast *doc_comment_ast = const_ast->child[2]; - zend_ast *type_ast = const_ast->child[3]; zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast)); zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL; zval value_zv; @@ -7752,8 +7751,9 @@ static void zend_compile_class_const_group(zend_ast *ast) /* {{{ */ { zend_ast *const_ast = ast->child[0]; zend_ast *attr_ast = ast->child[1]; + zend_ast *type_ast = ast->child[2]; - zend_compile_class_const_decl(const_ast, ast->attr, attr_ast); + zend_compile_class_const_decl(const_ast, ast->attr, attr_ast, type_ast); } /* }}} */ diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 9b663887264f0..298eaf95ad055 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -267,7 +267,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type echo_expr_list unset_variables catch_name_list catch_list optional_variable parameter_list class_statement_list %type implements_list case_list if_stmt_without_else %type non_empty_parameter_list argument_list non_empty_argument_list property_list -%type class_const_list first_class_const_decl class_const_decl class_name_list trait_adaptations method_body non_empty_for_exprs +%type class_const_list class_const_decl class_name_list trait_adaptations method_body non_empty_for_exprs %type ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars %type lexical_var_list encaps_list %type array_pair non_empty_array_pair_list array_pair_list possible_array_pair @@ -940,7 +940,10 @@ attributed_class_statement: { $$ = zend_ast_create(ZEND_AST_PROP_GROUP, $2, $3, NULL); $$->attr = $1; } | class_const_modifiers T_CONST class_const_list ';' - { $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $3, NULL); + { $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $3, NULL, NULL); + $$->attr = $1; } + | class_const_modifiers T_CONST type_expr class_const_list ';' + { $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $4, NULL, $3); $$->attr = $1; } | method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')' return_type backup_fn_flags method_body backup_fn_flags @@ -1076,21 +1079,20 @@ property: class_const_list: class_const_list ',' class_const_decl { $$ = zend_ast_list_add($1, $3); } - | first_class_const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); } -; - -first_class_const_decl: - T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } - | semi_reserved '=' expr backup_doc_comment { zval zv; if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } $$ = zend_ast_create(ZEND_AST_CONST_ELEM, zend_ast_create_zval(&zv), $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } - | type_expr identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $2, $4, ($5 ? zend_ast_create_zval_from_str($5) : NULL), $1); } + | class_const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); } ; class_const_decl: - identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } + T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); } + | semi_reserved '=' expr backup_doc_comment { + zval zv; + if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } + $$ = zend_ast_create(ZEND_AST_CONST_ELEM, zend_ast_create_zval(&zv), $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); + } ; const_decl: - T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } + T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); } ; echo_expr_list: