]> granicus.if.org Git - php/commitdiff
Forbid "return;" for typed returns already at compile-time
authorNikita Popov <nikic@php.net>
Sat, 4 Jun 2016 11:13:25 +0000 (13:13 +0200)
committerNikita Popov <nikic@php.net>
Sat, 4 Jun 2016 11:27:11 +0000 (13:27 +0200)
These would otherwise generate a "none returned" error at runtime.
Catch them early.

Zend/tests/return_types/029.phpt
Zend/tests/return_types/bug71092.phpt
Zend/tests/type_declarations/typed_return_without_value.phpt [new file with mode: 0644]
Zend/zend_compile.c

index 041b354130fe6d9bb145f4fd7b2fa05e73b32204..adc07cde7f4dd64a57b37b7dcdfd0c705cf94e0f 100644 (file)
@@ -9,7 +9,7 @@ function foo() : array {
        try {
                throw new Exception("xxxx");
        } finally {
-               return ;
+               return null;
        }
 }
 
@@ -21,7 +21,7 @@ Stack trace:
 #0 %s(%d): foo()
 #1 {main}
 
-Next TypeError: Return value of foo() must be of the type array, none returned in %s29.php:%d
+Next TypeError: Return value of foo() must be of the type array, null returned in %s29.php:%d
 Stack trace:
 #0 %s(%d): foo()
 #1 {main}
index a1ebc7908540d4063cae0bc740e1b66e3c6e9ffb..1d4fe983b36a72b71269e73c0a2642a75b485036 100644 (file)
@@ -9,14 +9,14 @@ function boom(): array {
        $data = [['id']];
        switch ($data[0]) {
        case ['id']:
-               return;
+               return null;
        }
 }
 
 boom();
 ?>
 --EXPECTF--
-Fatal error: Uncaught TypeError: Return value of boom() must be of the type array, none returned in %sbug71092.php:%d
+Fatal error: Uncaught TypeError: Return value of boom() must be of the type array, null returned in %sbug71092.php:%d
 Stack trace:
 #0 %s(%d): boom()
 #1 {main}
diff --git a/Zend/tests/type_declarations/typed_return_without_value.phpt b/Zend/tests/type_declarations/typed_return_without_value.phpt
new file mode 100644 (file)
index 0000000..1bf932b
--- /dev/null
@@ -0,0 +1,14 @@
+--TEST--
+Typed return without value generates compile-time error
+--FILE--
+<?php
+
+function test() : int {
+    return;
+}
+
+test();
+
+?>
+--EXPECTF--
+Fatal error: A function with return type must return a value in %s on line %d
index 9ebe966f1682463481af8d08c0e213a747bc1602..4bcec416a7ed08c19aafe59d1f1aec2ec4ff7474 100644 (file)
@@ -2264,7 +2264,8 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
 }
 /* }}} */
 
-static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info) /* {{{ */
+static void zend_emit_return_type_check(
+               znode *expr, zend_arg_info *return_info, zend_bool implicit) /* {{{ */
 {
        /* `return ...;` is illegal in a void function (but `return;` isn't) */
        if (return_info->type_hint == IS_VOID) {
@@ -2278,6 +2279,11 @@ static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info)
        if (return_info->type_hint != IS_UNDEF) {
                zend_op *opline;
 
+               if (!expr && !implicit) {
+                       zend_error_noreturn(E_COMPILE_ERROR,
+                               "A function with return type must return a value");
+               }
+
                if (expr && expr->op_type == IS_CONST) {
                        if ((return_info->type_hint == Z_TYPE(expr->u.constant))
                         ||((return_info->type_hint == _IS_BOOL)
@@ -2312,7 +2318,7 @@ void zend_emit_final_return(int return_one) /* {{{ */
        zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
 
        if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
-               zend_emit_return_type_check(NULL, CG(active_op_array)->arg_info - 1);
+               zend_emit_return_type_check(NULL, CG(active_op_array)->arg_info - 1, 1);
        }
 
        zn.op_type = IS_CONST;
@@ -4058,7 +4064,8 @@ void zend_compile_return(zend_ast *ast) /* {{{ */
 
        /* Generator return types are handled separately */
        if (!(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) && CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
-               zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
+               zend_emit_return_type_check(
+                       expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1, 0);
        }
 
        zend_handle_loops_and_finally();