@@ -259,7 +259,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
259259%type  <ast>  unprefixed_use_declarations  const_decl  inner_statement 
260260%type  <ast>  expr  optional_expr  while_statement  for_statement  foreach_variable 
261261%type  <ast>  foreach_statement  declare_statement  finally_statement  unset_variable  variable 
262- %type  <ast>  extends_from  parameter  optional_type_without_static  argument  global_var 
262+ %type  <ast>  extends_from  parameter  optional_type_without_static  argument  argument_no_expr   global_var 
263263%type  <ast>  static_var  class_statement  trait_adaptation  trait_precedence  trait_alias 
264264%type  <ast>  absolute_trait_method_reference  trait_method_reference  property  echo_expr 
265265%type  <ast>  new_dereferenceable  new_non_dereferenceable  anonymous_class  class_name  class_name_reference  simple_variable 
@@ -287,7 +287,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
287287%type  <ast>  enum_declaration_statement  enum_backing_type  enum_case  enum_case_expr 
288288%type  <ast>  function_name  non_empty_member_modifiers 
289289%type  <ast>  property_hook  property_hook_list  optional_property_hook_list  hooked_property  property_hook_body 
290- %type  <ast>  optional_parameter_list 
290+ %type  <ast>  optional_parameter_list   clone_argument_list   non_empty_clone_argument_list 
291291
292292%type  <num>  returns_ref  function  fn  is_reference  is_variadic  property_modifiers  property_hook_modifiers 
293293%type  <num>  method_modifiers  class_const_modifiers  member_modifier  optional_cpp_modifiers 
@@ -914,13 +914,42 @@ non_empty_argument_list:
914914			{ $$  = zend_ast_list_add($1 , $3 ); }
915915;
916916
917- argument :
918- 		expr 				{ $$  = $1 ; }
919- 	| 	identifier  ' :' expr 
917+ /*  `clone_argument_list` is necessary to resolve a parser ambiguity (shift-reduce conflict)
918+  * of `clone($expr)`, which could either be parsed as a function call with `$expr` as the first 
919+  * argument or as a use of the `clone` language construct with an expression with useless 
920+  * parenthesis. Both would be valid and result in the same AST / the same semantics. 
921+  * `clone_argument_list` is defined in a way that an `expr` in the first position needs to 
922+  * be followed by a `,` which is not valid syntax for a parenthesized `expr`, ensuring 
923+  * that calling `clone()` with a single unnamed parameter is handled by the language construct 
924+  * syntax. 
925+  */  
926+ clone_argument_list :
927+ 		' (' ' )' $$  = zend_ast_create_list(0 , ZEND_AST_ARG_LIST); }
928+ 	| 	' (' non_empty_clone_argument_list  possible_comma  ' )' $$  = $2 ; }
929+ 	| 	' (' expr  ' ,' ' )' $$  = zend_ast_create_list(1 , ZEND_AST_ARG_LIST, $2 ); }
930+ 	| 	' (' T_ELLIPSIS  ' )' $$  = zend_ast_create_fcc(); }
931+ ;
932+ 
933+ non_empty_clone_argument_list :
934+ 		expr  ' ,' argument 
935+ 			{ $$  = zend_ast_create_list(2 , ZEND_AST_ARG_LIST, $1 , $3 ); }
936+ 	| 	argument_no_expr 
937+ 			{ $$  = zend_ast_create_list(1 , ZEND_AST_ARG_LIST, $1 ); }
938+ 	| 	non_empty_clone_argument_list  ' ,' argument 
939+ 			{ $$  = zend_ast_list_add($1 , $3 ); }
940+ ;
941+ 
942+ argument_no_expr :
943+ 		identifier  ' :' expr 
920944			{ $$  = zend_ast_create(ZEND_AST_NAMED_ARG, $1 , $3 ); }
921945	| 	T_ELLIPSIS  expr 	{ $$  = zend_ast_create(ZEND_AST_UNPACK, $2 ); }
922946;
923947
948+ argument :
949+ 		expr  { $$  = $1 ; }
950+ 	| 	argument_no_expr  { $$  = $1 ; }
951+ ;
952+ 
924953global_var_list :
925954		global_var_list  ' ,' global_var  { $$  = zend_ast_list_add($1 , $3 ); }
926955	| 	global_var  { $$  = zend_ast_create_list(1 , ZEND_AST_STMT_LIST, $1 ); }
@@ -1228,10 +1257,10 @@ expr:
12281257			{ $$  = zend_ast_create(ZEND_AST_ASSIGN, $1 , $3 ); }
12291258	| 	variable  ' =' ampersand  variable 
12301259			{ $$  = zend_ast_create(ZEND_AST_ASSIGN_REF, $1 , $4 ); }
1231- 	| 	T_CLONE  ' ( '   T_ELLIPSIS   ' ) ' 
1260+ 	| 	T_CLONE  clone_argument_list  {
12321261			zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE));
12331262			name->attr = ZEND_NAME_FQ;
1234- 			$$  = zend_ast_create(ZEND_AST_CALL, name, zend_ast_create_fcc() );
1263+ 			$$  = zend_ast_create(ZEND_AST_CALL, name, $2 );
12351264		}
12361265	| 	T_CLONE  expr  {
12371266			zend_ast *name = zend_ast_create_zval_from_str(ZSTR_KNOWN(ZEND_STR_CLONE));
0 commit comments