diff options
author | Bob Weinand <bobwei9@hotmail.com> | 2016-04-21 01:26:48 +0200 |
---|---|---|
committer | Bob Weinand <bobwei9@hotmail.com> | 2016-04-21 01:26:48 +0200 |
commit | 36202ef0569db9039c683cf8b2245ca54cd6da46 (patch) | |
tree | 0030fbceb9fccf28c776a90faa03ec477d0f3e35 | |
parent | dc3ab58c14cb58e33b8a0c5c7a181846eb8b4ff3 (diff) | |
parent | 672a99597cce8b3ff133a8fddd44c1a9fc0158e5 (diff) | |
download | php-git-36202ef0569db9039c683cf8b2245ca54cd6da46.tar.gz |
Merge remote-tracking branch 'origin/PHP-7.0'
-rw-r--r-- | Zend/tests/constant_expressions_coalesce.phpt | 45 | ||||
-rw-r--r-- | Zend/zend_ast.c | 39 | ||||
-rw-r--r-- | Zend/zend_compile.c | 2 | ||||
-rw-r--r-- | Zend/zend_compile.h | 2 | ||||
-rw-r--r-- | Zend/zend_execute.c | 6 | ||||
-rw-r--r-- | Zend/zend_execute.h | 1 |
6 files changed, 93 insertions, 2 deletions
diff --git a/Zend/tests/constant_expressions_coalesce.phpt b/Zend/tests/constant_expressions_coalesce.phpt new file mode 100644 index 0000000000..aa40bd68e2 --- /dev/null +++ b/Zend/tests/constant_expressions_coalesce.phpt @@ -0,0 +1,45 @@ +--TEST-- +Constant expressions with null coalescing operator ?? +--FILE-- +<?php + +const A = [1 => [[]]]; + +const T_1 = null ?? A[1]['undefined']['index'] ?? 1; +const T_2 = null ?? A['undefined']['index'] ?? 2; +const T_3 = null ?? A[1][0][2] ?? 3; +const T_4 = A[1][0][2] ?? 4; + +var_dump(T_1); +var_dump(T_2); +var_dump(T_3); +var_dump(T_4); + +var_dump((function(){ static $var = null ?? A[1]['undefined']['index'] ?? 1; return $var; })()); +var_dump((function(){ static $var = null ?? A['undefined']['index'] ?? 2; return $var; })()); +var_dump((function(){ static $var = null ?? A[1][0][2] ?? 3; return $var; })()); +var_dump((function(){ static $var = A[1][0][2] ?? 4; return $var; })()); + +var_dump((new class { public $var = null ?? A[1]['undefined']['index'] ?? 1; })->var); +var_dump((new class { public $var = null ?? A['undefined']['index'] ?? 2; })->var); +var_dump((new class { public $var = null ?? A[1][0][2] ?? 3; })->var); +var_dump((new class { public $var = A[1][0][2] ?? 4; })->var); + +const D = [][] ?? 1; + +?> +--EXPECTF-- +int(1) +int(2) +int(3) +int(4) +int(1) +int(2) +int(3) +int(4) +int(1) +int(2) +int(3) +int(4) + +Fatal error: Cannot use [] for reading in %s.php on line 25 diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index cfcd636269..4d3678f0b6 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -337,6 +337,30 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc zval_dtor(&op1); } break; + case ZEND_AST_COALESCE: + if (ast->child[0]->kind == ZEND_AST_DIM) { + ast->child[0]->attr = ZEND_DIM_IS; + } + + if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) { + ret = FAILURE; + break; + } + if (Z_TYPE(op1) > IS_NULL) { + *result = op1; + } else { + if (ast->child[1]->kind == ZEND_AST_DIM) { + ast->child[1]->attr = ZEND_DIM_IS; + } + + if (UNEXPECTED(zend_ast_evaluate(result, ast->child[1], scope) != SUCCESS)) { + zval_dtor(&op1); + ret = FAILURE; + break; + } + zval_dtor(&op1); + } + break; case ZEND_AST_UNARY_PLUS: if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[0], scope) != SUCCESS)) { ret = FAILURE; @@ -385,6 +409,14 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc } break; case ZEND_AST_DIM: + if (ast->child[1] == NULL) { + zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading"); + } + + if (ast->attr == ZEND_DIM_IS && ast->child[0]->kind == ZEND_AST_DIM) { + ast->child[0]->attr = ZEND_DIM_IS; + } + if (UNEXPECTED(zend_ast_evaluate(&op1, ast->child[0], scope) != SUCCESS)) { ret = FAILURE; } else if (UNEXPECTED(zend_ast_evaluate(&op2, ast->child[1], scope) != SUCCESS)) { @@ -393,7 +425,12 @@ ZEND_API int zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *sc } else { zval tmp; - zend_fetch_dimension_by_zval(&tmp, &op1, &op2); + if (ast->attr == ZEND_DIM_IS) { + zend_fetch_dimension_by_zval_is(&tmp, &op1, &op2, IS_CONST); + } else { + zend_fetch_dimension_by_zval(&tmp, &op1, &op2); + } + if (UNEXPECTED(Z_ISREF(tmp))) { ZVAL_DUP(result, Z_REFVAL(tmp)); } else { diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 11eb04040b..842fa64563 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7314,7 +7314,7 @@ zend_bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */ || kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM || kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM || kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST - || kind == ZEND_AST_MAGIC_CONST; + || kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_COALESCE; } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8fe291f443..20a622f4d8 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -896,6 +896,8 @@ ZEND_API void zend_assert_valid_class_name(const zend_string *const_name); #define ZEND_SEND_BY_REF 1 #define ZEND_SEND_PREFER_REF 2 +#define ZEND_DIM_IS 1 + static zend_always_inline int zend_check_arg_send_type(const zend_function *zf, uint32_t arg_num, uint32_t mask) { arg_num--; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 6ba72b324e..7b1b7f3621 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1938,6 +1938,12 @@ ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval * zend_fetch_dimension_address_read_R(result, container, dim, IS_TMP_VAR); } +ZEND_API void zend_fetch_dimension_by_zval_is(zval *result, zval *container, zval *dim, int dim_type) +{ + zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS, 1); +} + + static zend_always_inline void zend_fetch_property_address(zval *result, zval *container, uint32_t container_op_type, zval *prop_ptr, uint32_t prop_op_type, void **cache_slot, int type) { if (container_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT)) { diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 738895e73c..b2163c7d25 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -294,6 +294,7 @@ ZEND_API zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, con void zend_verify_abstract_class(zend_class_entry *ce); ZEND_API void zend_fetch_dimension_by_zval(zval *result, zval *container, zval *dim); +ZEND_API void zend_fetch_dimension_by_zval_is(zval *result, zval *container, zval *dim, int dim_type); ZEND_API zval* zend_get_compiled_variable_value(const zend_execute_data *execute_data_ptr, uint32_t var); |