summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Faulds <ajf@ajf.me>2015-01-10 03:29:41 +0000
committerAndrea Faulds <ajf@ajf.me>2015-02-10 15:48:06 +0000
commitcc01e37e54874541aad343dd6c5902e9a111b9fc (patch)
tree0cb5677fa126fd9f53c5d2fa20217c563d9454bd
parent5544e37231fe754fa35d5f8a301647d3df35f942 (diff)
downloadphp-git-cc01e37e54874541aad343dd6c5902e9a111b9fc.tar.gz
It Begins
-rw-r--r--Zend/zend_compile.c13
-rw-r--r--Zend/zend_compile.h1
-rw-r--r--Zend/zend_execute.c12
-rw-r--r--Zend/zend_globals.h1
-rw-r--r--Zend/zend_types.h5
-rw-r--r--Zend/zend_vm_def.h12
-rw-r--r--Zend/zend_vm_execute.h10
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();