diff options
author | Andrea Faulds <ajf@ajf.me> | 2015-01-10 03:29:41 +0000 |
---|---|---|
committer | Andrea Faulds <ajf@ajf.me> | 2015-02-10 15:48:06 +0000 |
commit | cc01e37e54874541aad343dd6c5902e9a111b9fc (patch) | |
tree | 0cb5677fa126fd9f53c5d2fa20217c563d9454bd | |
parent | 5544e37231fe754fa35d5f8a301647d3df35f942 (diff) | |
download | php-git-cc01e37e54874541aad343dd6c5902e9a111b9fc.tar.gz |
It Begins
-rw-r--r-- | Zend/zend_compile.c | 13 | ||||
-rw-r--r-- | Zend/zend_compile.h | 1 | ||||
-rw-r--r-- | Zend/zend_execute.c | 12 | ||||
-rw-r--r-- | Zend/zend_globals.h | 1 | ||||
-rw-r--r-- | Zend/zend_types.h | 5 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 12 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 10 |
7 files changed, 38 insertions, 16 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0f391f527a..81eb1d4434 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -142,6 +142,7 @@ static zend_bool zend_get_unqualified_name(const zend_string *name, const char * static void init_compiler_declarables(void) /* {{{ */ { ZVAL_LONG(&CG(declarables).ticks, 0); + CG(declarables).strict_typehints = 0; } /* }}} */ @@ -2548,7 +2549,8 @@ void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function * opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc); } - call_flags = (opline->opcode == ZEND_NEW ? ZEND_CALL_CTOR : 0); + call_flags = ((opline->opcode == ZEND_NEW) ? ZEND_CALL_CTOR : 0) + | (CG(declarables).strict_typehints ? ZEND_CALL_STRICT_TYPEHINTS : 0); opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); opline->op1.num = call_flags; @@ -3787,6 +3789,15 @@ void zend_compile_declare(zend_ast *ast) /* {{{ */ zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be " "the very first statement in the script"); } + } else if (zend_string_equals_literal_ci(name, "strict_typehints")) { + zval value_zv; + zend_const_expr_to_zval(&value_zv, value_ast); + + if (Z_TYPE(value_zv) != IS_FALSE && Z_TYPE(value_zv) != IS_TRUE) { + zend_error_noreturn(E_COMPILE_ERROR, "strict_typehints declaration must have a boolean value"); + } + + CG(declarables).strict_typehints = (Z_TYPE(value_zv) == IS_TRUE) ? 1 : 0; } else { zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", name->val); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 09966ed327..3d44a08df7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -469,6 +469,7 @@ struct _zend_execute_data { #define ZEND_CALL_FREE_EXTRA_ARGS (1 << 2) /* equal to IS_TYPE_REFCOUNTED */ #define ZEND_CALL_CTOR (1 << 3) #define ZEND_CALL_CTOR_RESULT_UNUSED (1 << 4) +#define ZEND_CALL_STRICT_TYPEHINTS (1 << 5) #define ZEND_CALL_INFO(call) \ (Z_TYPE_INFO((call)->This) >> 24) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 26b6a3526a..604303ae10 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -658,7 +658,7 @@ static zend_bool zend_verify_scalar_type_hint(zend_uchar type_hint, zval *arg) } } -static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg) +static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zend_bool strict) { zend_internal_arg_info *cur_arg_info; char *need_msg; @@ -695,7 +695,7 @@ static void zend_verify_internal_arg_type(zend_function *zf, uint32_t arg_num, z if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg); } - } else if (UNEXPECTED(cur_arg_info->type_hint != Z_TYPE_P(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: @@ -703,14 +703,14 @@ failure: } return; } - if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { + if (strict || !zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { goto failure; } } } } -static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value) +static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, zend_bool strict) { zend_arg_info *cur_arg_info; char *need_msg; @@ -747,7 +747,7 @@ static void zend_verify_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL) && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value))))) { zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "", arg); } - } else if (UNEXPECTED(cur_arg_info->type_hint != Z_TYPE_P(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: @@ -755,7 +755,7 @@ failure: } return; } - if (!zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { + if (strict || !zend_verify_scalar_type_hint(cur_arg_info->type_hint, arg)) { goto failure; } } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index beca5ad631..7295eaefd3 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -64,6 +64,7 @@ END_EXTERN_C() typedef struct _zend_declarables { zval ticks; + zend_bool strict_typehints; } zend_declarables; typedef struct _zend_vm_stack *zend_vm_stack; diff --git a/Zend/zend_types.h b/Zend/zend_types.h index 80e1700373..f3bc9774ec 100644 --- a/Zend/zend_types.h +++ b/Zend/zend_types.h @@ -238,6 +238,11 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) { return pz->u1.v.type; } +#define ZEND_SAME_FAKE_TYPE(faketype, realtype) ( \ + (faketype) == (realtype) \ + || ((faketype) == _IS_BOOL && ((realtype) == IS_TRUE || (realtype) == IS_FALSE)) \ +) + /* we should never set just Z_TYPE, we should set Z_TYPE_INFO */ #define Z_TYPE(zval) zval_get_type(&(zval)) #define Z_TYPE_P(zval_p) Z_TYPE(*(zval_p)) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8a1bda8cd7..0557ddd16c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2768,6 +2768,8 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zend_object *object = Z_OBJ(call->This); zval *ret; + ZEND_ADD_CALL_FLAG(call, opline->op1.num & ZEND_CALL_STRICT_TYPEHINTS); + SAVE_OPLINE(); EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { @@ -2843,7 +2845,7 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, ANY, ANY) zval *p = ZEND_CALL_ARG(call, 1); for (i = 0; i < num_args; ++i) { - zend_verify_internal_arg_type(fbc, i + 1, p); + zend_verify_internal_arg_type(fbc, i + 1, p, (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); p++; } if (UNEXPECTED(EG(exception) != NULL)) { @@ -3692,7 +3694,7 @@ ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var); - zend_verify_arg_type(EX(func), arg_num, param, NULL); + zend_verify_arg_type(EX(func), arg_num, param, NULL, (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); CHECK_EXCEPTION(); } @@ -3720,7 +3722,7 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) } if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2)); + zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2), (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); } CHECK_EXCEPTION(); @@ -3746,8 +3748,8 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY) ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(params)) { param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - do { - zend_verify_arg_type(EX(func), arg_num, param, NULL); + do { + zend_verify_arg_type(EX(func), arg_num, param, NULL, (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); param++; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 19e1a741b5..ab736264ad 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -494,6 +494,8 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zend_object *object = Z_OBJ(call->This); zval *ret; + ZEND_ADD_CALL_FLAG(call, opline->op1.num & ZEND_CALL_STRICT_TYPEHINTS); + SAVE_OPLINE(); EX(call) = call->prev_execute_data; if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { @@ -569,7 +571,7 @@ static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) zval *p = ZEND_CALL_ARG(call, 1); for (i = 0; i < num_args; ++i) { - zend_verify_internal_arg_type(fbc, i + 1, p); + zend_verify_internal_arg_type(fbc, i + 1, p, (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); p++; } if (UNEXPECTED(EG(exception) != NULL)) { @@ -987,7 +989,7 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { zval *param = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->result.var); - zend_verify_arg_type(EX(func), arg_num, param, NULL); + zend_verify_arg_type(EX(func), arg_num, param, NULL, (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); CHECK_EXCEPTION(); } @@ -1014,7 +1016,7 @@ static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T); if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { do { - zend_verify_arg_type(EX(func), arg_num, param, NULL); + zend_verify_arg_type(EX(func), arg_num, param, NULL, (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param); ZEND_HASH_FILL_ADD(param); param++; @@ -1764,7 +1766,7 @@ static int ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ } if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) { - zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2)); + zend_verify_arg_type(EX(func), arg_num, param, EX_CONSTANT(opline->op2), (EX_CALL_INFO() & ZEND_CALL_STRICT_TYPEHINTS) ? 1 : 0); } CHECK_EXCEPTION(); |