From 1cfa4db338086c7710f822a6e69a680b5f9f744b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 20 Mar 2015 18:36:43 +0300 Subject: [PATCH] Fixed return type hint handling for constants --- Zend/zend_compile.c | 23 +++++---------------- Zend/zend_vm_def.h | 9 ++++++--- Zend/zend_vm_execute.h | 45 ++++++++++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index d0c7264eec..64d96e452d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index fd586e79cb..9065221b39 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index ebc21017ac..df01a3bb4b 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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(); -- 2.40.0