Fixed return type hint handling for constants

This commit is contained in:
Dmitry Stogov 2015-03-20 18:36:43 +03:00
parent 139c6c644c
commit 1cfa4db338
3 changed files with 41 additions and 36 deletions

View File

@ -1929,11 +1929,12 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
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 = (returns_reference ? ZEND_RETURN_REF : 0);
if (expr && expr->op_type == IS_CONST) {
opline->result_type = expr->op_type = IS_TMP_VAR;
opline->result.var = expr->u.op.var = get_temporary_variable(CG(active_op_array));
}
}
}
/* }}} */
@ -3405,21 +3406,7 @@ 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_arg_info *arg_info = CG(active_op_array)->arg_info - 1;
/* for scalar, weak return types, the value may be casted
* thus, for constants, we need to store them in a tmp var
*/
if (expr_node.op_type == IS_CONST && !(CG(active_op_array)->fn_flags & ZEND_ACC_STRICT_TYPES)) {
znode expr_node_copy = expr_node;
zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &expr_node_copy, NULL);
}
zend_emit_return_type_check(&expr_node, arg_info);
if (expr_node.op_type == IS_CONST) {
zval_copy_ctor(&expr_node.u.constant);
}
zend_emit_return_type_check(expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1);
}
opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
&expr_node, NULL);

View File

@ -3589,12 +3589,13 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
#if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED)
USE_OPLINE
#endif
SAVE_OPLINE();
if (OP1_TYPE == IS_UNUSED) {
zend_verify_missing_return_type(EX(func));
} else {
/* prevents "undefined variable opline" errors */
#if OP1_TYPE != IS_UNUSED
#if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED)
zval *retval_ptr;
zend_free_op free_op1;
zend_arg_info *ret_info = EX(func)->common.arg_info - 1;
@ -3606,7 +3607,7 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
&& !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)))) {
/* A cast or an error will happen, so separate the zval to prevent overwriting it */
if (EXPECTED((opline->extended_value & ZEND_RETURN_REF) == 0)) {
if (EXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) == 0)) {
/* Does not return by reference */
SEPARATE_ZVAL(retval_ptr);
} else {
@ -3614,8 +3615,10 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
SEPARATE_ZVAL_NOREF(retval_ptr);
}
}
zend_verify_return_type(EX(func), retval_ptr);
if (OP1_TYPE == IS_CONST) {
ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr);
}
#endif
}
CHECK_EXCEPTION();

View File

@ -6969,12 +6969,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
#if 0 || (IS_CONST != IS_UNUSED)
USE_OPLINE
#endif
SAVE_OPLINE();
if (IS_CONST == IS_UNUSED) {
zend_verify_missing_return_type(EX(func));
} else {
/* prevents "undefined variable opline" errors */
#if IS_CONST != IS_UNUSED
#if 0 || (IS_CONST != IS_UNUSED)
zval *retval_ptr;
zend_arg_info *ret_info = EX(func)->common.arg_info - 1;
@ -6986,7 +6987,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
&& !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)))) {
/* A cast or an error will happen, so separate the zval to prevent overwriting it */
if (EXPECTED((opline->extended_value & ZEND_RETURN_REF) == 0)) {
if (EXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) == 0)) {
/* Does not return by reference */
SEPARATE_ZVAL(retval_ptr);
} else {
@ -6994,8 +6995,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
SEPARATE_ZVAL_NOREF(retval_ptr);
}
}
zend_verify_return_type(EX(func), retval_ptr);
if (IS_CONST == IS_CONST) {
ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr);
}
#endif
}
CHECK_EXCEPTION();
@ -11930,12 +11933,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
#if 0 || (IS_TMP_VAR != IS_UNUSED)
USE_OPLINE
#endif
SAVE_OPLINE();
if (IS_TMP_VAR == IS_UNUSED) {
zend_verify_missing_return_type(EX(func));
} else {
/* prevents "undefined variable opline" errors */
#if IS_TMP_VAR != IS_UNUSED
#if 0 || (IS_TMP_VAR != IS_UNUSED)
zval *retval_ptr;
zend_free_op free_op1;
zend_arg_info *ret_info = EX(func)->common.arg_info - 1;
@ -11947,7 +11951,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
&& !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)))) {
/* A cast or an error will happen, so separate the zval to prevent overwriting it */
if (EXPECTED((opline->extended_value & ZEND_RETURN_REF) == 0)) {
if (EXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) == 0)) {
/* Does not return by reference */
SEPARATE_ZVAL(retval_ptr);
} else {
@ -11955,8 +11959,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
SEPARATE_ZVAL_NOREF(retval_ptr);
}
}
zend_verify_return_type(EX(func), retval_ptr);
if (IS_TMP_VAR == IS_CONST) {
ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr);
}
#endif
}
CHECK_EXCEPTION();
@ -17291,12 +17297,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
#if 0 || (IS_VAR != IS_UNUSED)
USE_OPLINE
#endif
SAVE_OPLINE();
if (IS_VAR == IS_UNUSED) {
zend_verify_missing_return_type(EX(func));
} else {
/* prevents "undefined variable opline" errors */
#if IS_VAR != IS_UNUSED
#if 0 || (IS_VAR != IS_UNUSED)
zval *retval_ptr;
zend_free_op free_op1;
zend_arg_info *ret_info = EX(func)->common.arg_info - 1;
@ -17308,7 +17315,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
&& !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)))) {
/* A cast or an error will happen, so separate the zval to prevent overwriting it */
if (EXPECTED((opline->extended_value & ZEND_RETURN_REF) == 0)) {
if (EXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) == 0)) {
/* Does not return by reference */
SEPARATE_ZVAL(retval_ptr);
} else {
@ -17316,8 +17323,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
SEPARATE_ZVAL_NOREF(retval_ptr);
}
}
zend_verify_return_type(EX(func), retval_ptr);
if (IS_VAR == IS_CONST) {
ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr);
}
#endif
}
CHECK_EXCEPTION();
@ -22909,12 +22918,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
#if 0 || (IS_UNUSED != IS_UNUSED)
USE_OPLINE
#endif
SAVE_OPLINE();
if (IS_UNUSED == IS_UNUSED) {
zend_verify_missing_return_type(EX(func));
} else {
/* prevents "undefined variable opline" errors */
#if IS_UNUSED != IS_UNUSED
#if 0 || (IS_UNUSED != IS_UNUSED)
zval *retval_ptr;
zend_arg_info *ret_info = EX(func)->common.arg_info - 1;
@ -22926,7 +22936,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
&& !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)))) {
/* A cast or an error will happen, so separate the zval to prevent overwriting it */
if (EXPECTED((opline->extended_value & ZEND_RETURN_REF) == 0)) {
if (EXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) == 0)) {
/* Does not return by reference */
SEPARATE_ZVAL(retval_ptr);
} else {
@ -22934,8 +22944,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
SEPARATE_ZVAL_NOREF(retval_ptr);
}
}
zend_verify_return_type(EX(func), retval_ptr);
if (IS_UNUSED == IS_CONST) {
ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr);
}
#endif
}
CHECK_EXCEPTION();
@ -31863,12 +31875,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
#if 0 || (IS_CV != IS_UNUSED)
USE_OPLINE
#endif
SAVE_OPLINE();
if (IS_CV == IS_UNUSED) {
zend_verify_missing_return_type(EX(func));
} else {
/* prevents "undefined variable opline" errors */
#if IS_CV != IS_UNUSED
#if 0 || (IS_CV != IS_UNUSED)
zval *retval_ptr;
zend_arg_info *ret_info = EX(func)->common.arg_info - 1;
@ -31880,7 +31893,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
&& !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(retval_ptr)))) {
/* A cast or an error will happen, so separate the zval to prevent overwriting it */
if (EXPECTED((opline->extended_value & ZEND_RETURN_REF) == 0)) {
if (EXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) == 0)) {
/* Does not return by reference */
SEPARATE_ZVAL(retval_ptr);
} else {
@ -31888,8 +31901,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
SEPARATE_ZVAL_NOREF(retval_ptr);
}
}
zend_verify_return_type(EX(func), retval_ptr);
if (IS_CV == IS_CONST) {
ZVAL_COPY(EX_VAR(opline->result.var), retval_ptr);
}
#endif
}
CHECK_EXCEPTION();