diff --git a/Zend/tests/gh7900.phpt b/Zend/tests/arrow_functions/gh7900.phpt similarity index 100% rename from Zend/tests/gh7900.phpt rename to Zend/tests/arrow_functions/gh7900.phpt diff --git a/Zend/tests/arrow_functions/multiline_001.phpt b/Zend/tests/arrow_functions/multiline_001.phpt new file mode 100644 index 0000000000000..57d962047e358 --- /dev/null +++ b/Zend/tests/arrow_functions/multiline_001.phpt @@ -0,0 +1,21 @@ +--TEST-- +Multiline arrow function +--FILE-- + { + echo "inside fn($a):\n"; + return $a; + }; + + $f($a); + echo "inside a($a):\n"; +} + +a(12345); + +?> +--EXPECT-- +inside fn(12345): +inside a(12345): \ No newline at end of file diff --git a/Zend/tests/arrow_functions/multiline_002.phpt b/Zend/tests/arrow_functions/multiline_002.phpt new file mode 100644 index 0000000000000..0a2a03507f51c --- /dev/null +++ b/Zend/tests/arrow_functions/multiline_002.phpt @@ -0,0 +1,13 @@ +--TEST-- +Arrow functions implicit use must be throwing notices only upon actual use +--FILE-- + {return $b + $c;})()); + +?> +--EXPECTF-- +Warning: Undefined variable $c in %s on line %d +int(1) diff --git a/Zend/tests/arrow_functions/multiline_gh7900_return.phpt b/Zend/tests/arrow_functions/multiline_gh7900_return.phpt new file mode 100644 index 0000000000000..dba68131032f9 --- /dev/null +++ b/Zend/tests/arrow_functions/multiline_gh7900_return.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-7900: Arrow function with never return type compile-time errors (multiline, no errors) +--INI-- +zend.assertions=1 +assert.exception=1 +--FILE-- + { throw new \Exception('Here'); }; + +try { + var_dump($x()); +} catch (\Exception $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Here diff --git a/Zend/tests/arrow_functions/multiline_gh7900_throw.phpt b/Zend/tests/arrow_functions/multiline_gh7900_throw.phpt new file mode 100644 index 0000000000000..a95b2536e598a --- /dev/null +++ b/Zend/tests/arrow_functions/multiline_gh7900_throw.phpt @@ -0,0 +1,17 @@ +--TEST-- +GH-7900: Arrow function with never return type compile-time errors (multiline, Fatal error) +--INI-- +zend.assertions=1 +assert.exception=1 +--FILE-- + { return 42; }) && false); +} catch (\Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +Fatal error: A never-returning function must not return in %s on line %d diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cb64729806a23..1b23cfb130102 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8365,7 +8365,9 @@ static zend_op_array *zend_compile_func_decl_ex( zend_compile_closure_uses(uses_ast); } - if (ast->kind == ZEND_AST_ARROW_FUNC && decl->child[2]->kind != ZEND_AST_RETURN) { + if (ast->kind == ZEND_AST_ARROW_FUNC + && stmt_ast->kind != ZEND_AST_RETURN + && stmt_ast->kind != ZEND_AST_STMT_LIST) { bool needs_return = true; if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { zend_arg_info *return_info = CG(active_op_array)->arg_info - 1; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index d2a29e670d8bf..44b2372ee7e60 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1337,13 +1337,15 @@ inline_function: function returns_ref backup_doc_comment '(' parameter_list ')' lexical_vars return_type backup_fn_flags '{' inner_statement_list '}' backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $2 | $13, $1, $3, - NULL, - $5, $7, $11, $8, NULL); CG(extra_fn_flags) = $9; } + NULL, $5, $7, $11, $8, NULL); CG(extra_fn_flags) = $9; } | fn returns_ref backup_doc_comment '(' parameter_list ')' return_type T_DOUBLE_ARROW backup_fn_flags backup_lex_pos expr backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_ARROW_FUNC, $2 | $12, $1, $3, - NULL, $5, NULL, $11, $7, NULL); - CG(extra_fn_flags) = $9; } + NULL, $5, NULL, $11, $7, NULL); CG(extra_fn_flags) = $9; } + | fn returns_ref backup_doc_comment '(' parameter_list ')' return_type + T_DOUBLE_ARROW backup_fn_flags '{' inner_statement_list '}' backup_fn_flags + { $$ = zend_ast_create_decl(ZEND_AST_ARROW_FUNC, $2 | $13, $1, $3, + NULL, $5, NULL, $11, $7, NULL); CG(extra_fn_flags) = $9; } ; fn: