--- /dev/null
+--TEST--
+Return value separation
+
+--FILE--
+<?php
+function test1(&$abc) : string {
+ return $abc;
+}
+
+function &test2(int $abc) : string {
+ return $abc;
+}
+
+$a = 123;
+
+var_dump(test1($a));
+var_dump($a);
+var_dump(test2($a));
+var_dump($a);
+
+?>
+--EXPECTF--
+string(3) "123"
+int(123)
+string(3) "123"
+int(123)
\ No newline at end of file
static void zend_emit_return_type_check(znode *expr, zend_arg_info *return_info) /* {{{ */
{
+ zend_bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
+
if (return_info->type_hint != IS_UNDEF) {
zend_op *opline = zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL);
- opline->extended_value = CG(declarables).strict_types;
+ opline->extended_value = (CG(declarables).strict_types ? ZEND_RETURN_TYPE_STRICT : 0)
+ & (returns_reference ? ZEND_RETURN_TYPE_BYREF : 0);
}
}
/* }}} */
type = zend_lookup_scalar_typehint_by_name(class_name);
if (type != 0) {
arg_info->type_hint = type;
- goto done;
- }
-
- if (zend_is_const_default_class_ref(type_ast)) {
- class_name = zend_resolve_class_name_ast(type_ast);
} else {
- zend_string_addref(class_name);
- }
-
- arg_info->type_hint = IS_OBJECT;
- arg_info->class_name = class_name;
+
+ if (zend_is_const_default_class_ref(type_ast)) {
+ class_name = zend_resolve_class_name_ast(type_ast);
+ } else {
+ zend_string_addref(class_name);
+ }
-done:
+ arg_info->type_hint = IS_OBJECT;
+ arg_info->class_name = class_name;
+ }
if (default_ast && !has_null_default && !Z_CONSTANT(default_node.u.constant)) {
if (arg_info->class_name) {
zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
#define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4)
#define ZEND_CALL_STRICT_TYPEHINTS (1 << 5)
+#define ZEND_RETURN_TYPE_STRICT (1 << 0)
+#define ZEND_RETURN_TYPE_BYREF (1 << 1)
+
#define ZEND_CALL_INFO(call) \
(Z_TYPE_INFO((call)->This) >> 24)
zend_verify_arg_error(zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg);
}
} else if (UNEXPECTED(!ZEND_SAME_FAKE_TYPE(cur_arg_info->type_hint, Z_TYPE_P(arg)))) {
- if (Z_TYPE_P(arg) == IS_NULL) {
- if (!cur_arg_info->allow_null) {
-failure:
- zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
- }
+ if ((Z_TYPE_P(arg) == IS_NULL && !cur_arg_info->allow_null)
+ || !zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, strict)) {
+
+ zend_verify_arg_error(zf, arg_num, "be of the type ", zend_get_type_by_const(cur_arg_info->type_hint), zend_zval_type_name(arg), "", arg);
return;
}
- if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg, strict)) {
- goto failure;
- }
}
}
}
zval *retval_ptr;
zend_free_op free_op1;
- retval_ptr = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
- /* extended_value stores strictness flag */
- zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
+ retval_ptr = GET_OP1_ZVAL_PTR(BP_VAR_R);
+
+ if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
+ /* Does not return by reference */
+ SEPARATE_ZVAL(retval_ptr);
+ } else {
+ ZVAL_DEREF(retval_ptr);
+ SEPARATE_ZVAL_NOREF(retval_ptr);
+ }
+
+ zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
#endif
}
CHECK_EXCEPTION();
retval_ptr = EX_CONSTANT(opline->op1);
- /* extended_value stores strictness flag */
- zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
+
+ if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
+ /* Does not return by reference */
+ SEPARATE_ZVAL(retval_ptr);
+ } else {
+ ZVAL_DEREF(retval_ptr);
+ SEPARATE_ZVAL_NOREF(retval_ptr);
+ }
+
+ zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
#endif
}
CHECK_EXCEPTION();
zend_free_op free_op1;
retval_ptr = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
- /* extended_value stores strictness flag */
- zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
+
+ if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
+ /* Does not return by reference */
+ SEPARATE_ZVAL(retval_ptr);
+ } else {
+ ZVAL_DEREF(retval_ptr);
+ SEPARATE_ZVAL_NOREF(retval_ptr);
+ }
+
+ zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
#endif
}
CHECK_EXCEPTION();
zval *retval_ptr;
zend_free_op free_op1;
- retval_ptr = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1);
- /* extended_value stores strictness flag */
- zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
+ retval_ptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
+
+ if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
+ /* Does not return by reference */
+ SEPARATE_ZVAL(retval_ptr);
+ } else {
+ ZVAL_DEREF(retval_ptr);
+ SEPARATE_ZVAL_NOREF(retval_ptr);
+ }
+
+ zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
#endif
}
CHECK_EXCEPTION();
retval_ptr = NULL;
- /* extended_value stores strictness flag */
- zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
+
+ if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
+ /* Does not return by reference */
+ SEPARATE_ZVAL(retval_ptr);
+ } else {
+ ZVAL_DEREF(retval_ptr);
+ SEPARATE_ZVAL_NOREF(retval_ptr);
+ }
+
+ zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
#endif
}
CHECK_EXCEPTION();
zval *retval_ptr;
- retval_ptr = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var);
- /* extended_value stores strictness flag */
- zend_verify_return_type(EX(func), retval_ptr, opline->extended_value);
+ retval_ptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
+
+ if (EXPECTED((opline->extended_value & ZEND_RETURN_TYPE_BYREF) == 0)) {
+ /* Does not return by reference */
+ SEPARATE_ZVAL(retval_ptr);
+ } else {
+ ZVAL_DEREF(retval_ptr);
+ SEPARATE_ZVAL_NOREF(retval_ptr);
+ }
+
+ zend_verify_return_type(EX(func), retval_ptr, opline->extended_value & ZEND_RETURN_TYPE_STRICT);
#endif
}
CHECK_EXCEPTION();