diff --git a/Zend/tests/type_casts/gh18301_cast_to_void_for.phpt b/Zend/tests/type_casts/gh18301_cast_to_void_for.phpt new file mode 100644 index 000000000000..2ff7cfb0cb17 --- /dev/null +++ b/Zend/tests/type_casts/gh18301_cast_to_void_for.phpt @@ -0,0 +1,46 @@ +--TEST-- +GH-18301: casting to void is allowed in for’s expression lists +--FILE-- + +--EXPECTF-- +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +4 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +10 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +16 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +22 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d +28 + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d + +Warning: The return value of function incCount() should either be used or intentionally ignored by casting it as (void) in %s on line %d diff --git a/Zend/tests/type_casts/gh18301_cast_to_void_statement_for_condition.phpt b/Zend/tests/type_casts/gh18301_cast_to_void_statement_for_condition.phpt new file mode 100644 index 000000000000..6c90b2f7987c --- /dev/null +++ b/Zend/tests/type_casts/gh18301_cast_to_void_statement_for_condition.phpt @@ -0,0 +1,9 @@ +--TEST-- +GH-18301: casting to void is not allowed at the end of a for condition +--FILE-- + +--EXPECTF-- +Parse error: syntax error, unexpected token ";", expecting "," in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 2ad3f6b323d8..5414d686d982 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -5717,6 +5717,26 @@ static void zend_compile_return(zend_ast *ast) /* {{{ */ } /* }}} */ +static void zend_compile_void_cast(znode *result, zend_ast *ast) +{ + zend_ast *expr_ast = ast->child[0]; + znode expr_node; + zend_op *opline; + + zend_compile_expr(&expr_node, expr_ast); + + switch (expr_node.op_type) { + case IS_TMP_VAR: + case IS_VAR: + opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL); + opline->extended_value = ZEND_FREE_VOID_CAST; + break; + case IS_CONST: + zend_do_free(&expr_node); + break; + } +} + static void zend_compile_echo(zend_ast *ast) /* {{{ */ { zend_op *opline; @@ -5967,7 +5987,7 @@ static void zend_compile_do_while(zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_compile_expr_list(znode *result, zend_ast *ast) /* {{{ */ +static void zend_compile_for_expr_list(znode *result, zend_ast *ast) /* {{{ */ { zend_ast_list *list; uint32_t i; @@ -5984,7 +6004,13 @@ static void zend_compile_expr_list(znode *result, zend_ast *ast) /* {{{ */ zend_ast *expr_ast = list->child[i]; zend_do_free(result); - zend_compile_expr(result, expr_ast); + if (expr_ast->kind == ZEND_AST_CAST_VOID) { + zend_compile_void_cast(NULL, expr_ast); + result->op_type = IS_CONST; + ZVAL_NULL(&result->u.constant); + } else { + zend_compile_expr(result, expr_ast); + } } } /* }}} */ @@ -5999,7 +6025,7 @@ static void zend_compile_for(zend_ast *ast) /* {{{ */ znode result; uint32_t opnum_start, opnum_jmp, opnum_loop; - zend_compile_expr_list(&result, init_ast); + zend_compile_for_expr_list(&result, init_ast); zend_do_free(&result); opnum_jmp = zend_emit_jump(0); @@ -6010,11 +6036,11 @@ static void zend_compile_for(zend_ast *ast) /* {{{ */ zend_compile_stmt(stmt_ast); opnum_loop = get_next_op_number(); - zend_compile_expr_list(&result, loop_ast); + zend_compile_for_expr_list(&result, loop_ast); zend_do_free(&result); zend_update_jump_target_to_next(opnum_jmp); - zend_compile_expr_list(&result, cond_ast); + zend_compile_for_expr_list(&result, cond_ast); zend_do_extended_stmt(); zend_emit_cond_jump(ZEND_JMPNZ, &result, opnum_start); @@ -10594,26 +10620,6 @@ static void zend_compile_include_or_eval(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_compile_void_cast(znode *result, zend_ast *ast) -{ - zend_ast *expr_ast = ast->child[0]; - znode expr_node; - zend_op *opline; - - zend_compile_expr(&expr_node, expr_ast); - - switch (expr_node.op_type) { - case IS_TMP_VAR: - case IS_VAR: - opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL); - opline->extended_value = ZEND_FREE_VOID_CAST; - break; - case IS_CONST: - zend_do_free(&expr_node); - break; - } -} - static void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */ { zend_ast *var_ast = ast->child[0]; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 9483a83b4e95..190292fada76 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -268,7 +268,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*); %type callable_expr callable_variable static_member new_variable %type encaps_var encaps_var_offset isset_variables %type top_statement_list use_declarations const_list inner_statement_list if_stmt -%type alt_if_stmt for_exprs switch_case_list global_var_list static_var_list +%type alt_if_stmt for_cond_exprs for_exprs switch_case_list global_var_list static_var_list %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 @@ -508,7 +508,7 @@ statement: { $$ = zend_ast_create(ZEND_AST_WHILE, $3, $5); } | T_DO statement T_WHILE '(' expr ')' ';' { $$ = zend_ast_create(ZEND_AST_DO_WHILE, $2, $5); } - | T_FOR '(' for_exprs ';' for_exprs ';' for_exprs ')' for_statement + | T_FOR '(' for_exprs ';' for_cond_exprs ';' for_exprs ')' for_statement { $$ = zend_ast_create(ZEND_AST_FOR, $3, $5, $7, $9); } | T_SWITCH '(' expr ')' switch_case_list { $$ = zend_ast_create(ZEND_AST_SWITCH, $3, $5); } @@ -1169,6 +1169,12 @@ echo_expr: expr { $$ = zend_ast_create(ZEND_AST_ECHO, $1); } ; +for_cond_exprs: + %empty { $$ = NULL; } + | non_empty_for_exprs ',' expr { $$ = zend_ast_list_add($1, $3); } + | expr { $$ = zend_ast_create_list(1, ZEND_AST_EXPR_LIST, $1); } +; + for_exprs: %empty { $$ = NULL; } | non_empty_for_exprs { $$ = $1; } @@ -1176,6 +1182,8 @@ for_exprs: non_empty_for_exprs: non_empty_for_exprs ',' expr { $$ = zend_ast_list_add($1, $3); } + | non_empty_for_exprs ',' T_VOID_CAST expr { $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_CAST_VOID, $4)); } + | T_VOID_CAST expr { $$ = zend_ast_create_list(1, ZEND_AST_EXPR_LIST, zend_ast_create(ZEND_AST_CAST_VOID, $2)); } | expr { $$ = zend_ast_create_list(1, ZEND_AST_EXPR_LIST, $1); } ;