From: Andrea Faulds Date: Wed, 14 Oct 2015 18:15:32 +0000 (+0100) Subject: Add void return type X-Git-Tag: php-7.1.0alpha1~714 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=366ba41334870f325f248d8e486e3ebf8bafb984;p=php Add void return type --- diff --git a/NEWS b/NEWS index 1d9fd2a100..c33379064b 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ PHP NEWS Core: . Fixed bug #62210 (Exceptions can leak temporary variables). (Dmitry, Bob) + . Added void return type. (Andrea) Standard . Implemented FR #55716 (Add an option to pass a custom stream context to diff --git a/UPGRADING b/UPGRADING index 44516e9079..8929404d98 100644 --- a/UPGRADING +++ b/UPGRADING @@ -18,10 +18,16 @@ PHP 7.1 UPGRADE NOTES ======================================== 1. Backward Incompatible Changes ======================================== +- Core: + . 'void' can no longer be used as the name of a class, interface, or trait. + This applies to declarations, class_alias() and use statements. ======================================== 2. New Features ======================================== +- Core + . Added void return type, which requires that a function not return a value. + (RFC: https://wiki.php.net/rfc/void_return_type) ======================================== 3. Changes in SAPI modules diff --git a/Zend/tests/return_types/void_allowed.phpt b/Zend/tests/return_types/void_allowed.phpt new file mode 100644 index 0000000000..8f07c7392e --- /dev/null +++ b/Zend/tests/return_types/void_allowed.phpt @@ -0,0 +1,20 @@ +--TEST-- +void return type: acceptable cases +--FILE-- +type_hint == IS_VOID) { + zend_error_noreturn(E_COMPILE_ERROR, "A void function must not return a value"); + } + if (return_info->type_hint != IS_UNDEF) { zend_op *opline = zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL); if (expr && expr->op_type == IS_CONST) { @@ -4706,6 +4713,10 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast) /* {{{ */ zend_compile_typename(type_ast, arg_info); + if (arg_info->type_hint == IS_VOID) { + zend_error_noreturn(E_COMPILE_ERROR, "void cannot be used as a parameter type"); + } + if (type_ast->kind == ZEND_AST_TYPE) { if (arg_info->type_hint == IS_ARRAY) { if (default_ast && !has_null_default diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index aa48b06767..044b49e760 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -946,6 +946,24 @@ static ZEND_COLD void zend_verify_internal_return_error(const zend_function *zf, fclass, fsep, fname, need_msg, need_kind, returned_msg, returned_kind); } +static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, const char *returned_msg, const char *returned_kind) +{ + const char *fname = ZSTR_VAL(zf->common.function_name); + const char *fsep; + const char *fclass; + + if (zf->common.scope) { + fsep = "::"; + fclass = ZSTR_VAL(zf->common.scope->name); + } else { + fsep = ""; + fclass = ""; + } + + zend_type_error("%s%s%s() must not return a value, %s%s returned", + fclass, fsep, fname, returned_msg, returned_kind); +} + #if ZEND_DEBUG static int zend_verify_internal_return_type(zend_function *zf, zval *ret) { @@ -975,6 +993,8 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret) } else if (ret_info->type_hint == _IS_BOOL && EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) { /* pass */ + } else if (ret_info->type_hint == IS_VOID) { + zend_verify_void_return_error(zf, zend_zval_type_name(ret), ""); } else { /* Use strict check to verify return value of internal function */ zend_verify_internal_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), ""); @@ -1035,6 +1055,12 @@ static zend_always_inline void zend_verify_return_type(zend_function *zf, zval * } else if (ret_info->type_hint == _IS_BOOL && EXPECTED(Z_TYPE_P(ret) == IS_FALSE || Z_TYPE_P(ret) == IS_TRUE)) { /* pass */ + /* There would be a check here for the IS_VOID type hint, which + * would trigger an error because a value had been returned. + * However, zend_compile.c already does a compile-time check + * that bans `return ...;` within a void function. Thus we can skip + * this part of the runtime check for non-internal functions. + */ } else if (UNEXPECTED(!zend_verify_scalar_type_hint(ret_info->type_hint, ret, ZEND_RET_USES_STRICT_TYPES()))) { zend_verify_return_error(zf, "be of the type ", zend_get_type_by_const(ret_info->type_hint), zend_zval_type_name(ret), ""); } @@ -1048,7 +1074,7 @@ static ZEND_COLD int zend_verify_missing_return_type(zend_function *zf, void **c char *need_msg; zend_class_entry *ce; - if (ret_info->type_hint) { + if (ret_info->type_hint && EXPECTED(ret_info->type_hint != IS_VOID)) { if (ret_info->class_name) { if (EXPECTED(*cache_slot)) { ce = (zend_class_entry*)*cache_slot; diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 9d15f498f8..805ea6d8c7 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -318,6 +318,7 @@ struct _zend_ast_ref { /* fake types */ #define _IS_BOOL 13 #define IS_CALLABLE 14 +#define IS_VOID 18 /* internal types */ #define IS_INDIRECT 15