From 08b75395838b4b42a41e3c70684fa6c6b113eee0 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 8 Sep 2022 17:41:53 +0200 Subject: [PATCH] Fix syntax error when dnf type in parens after readonly Fixes GH-9500 Closes GH-9512 --- NEWS | 4 ++++ Zend/tests/gh9500.phpt | 25 +++++++++++++++++++++++++ Zend/tests/readonly_function.phpt | 28 ++++++++++++++++++++++++++-- Zend/zend_language_parser.y | 17 ++++++++++++++++- Zend/zend_language_scanner.l | 6 ------ 5 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 Zend/tests/gh9500.phpt diff --git a/NEWS b/NEWS index c5cb59f0184..a9d5110a41c 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.0RC2 +- Core: + . Fixed bug GH-9500 (Using dnf type with parentheses after readonly keyword + results in a parse error). (ilutov) + - Opcache: . Fixed bug GH-9259 (opcache.interned_strings_buffer setting integer overflow). (Arnaud) diff --git a/Zend/tests/gh9500.phpt b/Zend/tests/gh9500.phpt new file mode 100644 index 00000000000..4afc8c57967 --- /dev/null +++ b/Zend/tests/gh9500.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug GH-9500: Disjunctive Normal Form Types - readonly property followed by ( +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/Zend/tests/readonly_function.phpt b/Zend/tests/readonly_function.phpt index 0262b3b7348..35102d36b9d 100644 --- a/Zend/tests/readonly_function.phpt +++ b/Zend/tests/readonly_function.phpt @@ -7,10 +7,34 @@ function readonly() { echo "Hi!\n"; } +class A { + const readonly = 'Const hi!'; + + static function readonly() { + echo "Static hi!\n"; + } +} + +class B { + public $readonly = 'Prop hi!'; + + function readonly() { + echo "Instance hi!\n"; + } +} + +$b = new B(); + readonly(); -readonly (); +echo A::readonly, "\n"; +A::readonly(); +$b->readonly(); +echo $b->readonly, "\n"; ?> --EXPECT-- Hi! -Hi! +Const hi! +Static hi! +Instance hi! +Prop hi! diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 7194f70b9d4..f0c6622171a 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -278,6 +278,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type attribute_decl attribute attributes attribute_group namespace_declaration_name %type match match_arm_list non_empty_match_arm_list match_arm match_arm_cond_list %type enum_declaration_statement enum_backing_type enum_case enum_case_expr +%type function_name %type returns_ref function fn is_reference is_variadic variable_modifiers %type method_modifiers non_empty_member_modifiers member_modifier @@ -560,8 +561,17 @@ unset_variable: variable { $$ = zend_ast_create(ZEND_AST_UNSET, $1); } ; +function_name: + T_STRING { $$ = $1; } + | T_READONLY { + zval zv; + if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } + $$ = zend_ast_create_zval(&zv); + } +; + function_declaration_statement: - function returns_ref T_STRING backup_doc_comment '(' parameter_list ')' return_type + function returns_ref function_name backup_doc_comment '(' parameter_list ')' return_type backup_fn_flags '{' inner_statement_list '}' backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_FUNC_DECL, $2 | $13, $1, $4, zend_ast_get_str($3), $6, NULL, $11, $8, NULL); CG(extra_fn_flags) = $9; } @@ -1270,6 +1280,11 @@ lexical_var: function_call: name argument_list { $$ = zend_ast_create(ZEND_AST_CALL, $1, $2); } + | T_READONLY argument_list { + zval zv; + if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } + $$ = zend_ast_create(ZEND_AST_CALL, zend_ast_create_zval(&zv), $2); + } | class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list { $$ = zend_ast_create(ZEND_AST_STATIC_CALL, $1, $3, $4); } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM member_name argument_list diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index a367c2acb82..c73a50948d6 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -1729,12 +1729,6 @@ NEWLINE ("\r"|"\n"|"\r\n") RETURN_TOKEN_WITH_IDENT(T_READONLY); } -/* Don't treat "readonly(" as a keyword, to allow using it as a function name. */ -"readonly"[ \n\r\t]*"(" { - yyless(strlen("readonly")); - RETURN_TOKEN_WITH_STR(T_STRING, 0); -} - "unset" { RETURN_TOKEN_WITH_IDENT(T_UNSET); }