]> granicus.if.org Git - php/commitdiff
allow null coalescing (??) on constant expressions
authorMárcio Almada <marcio3w@gmail.com>
Sun, 17 Apr 2016 08:27:15 +0000 (04:27 -0400)
committerBob Weinand <bobwei9@hotmail.com>
Wed, 20 Apr 2016 23:22:28 +0000 (01:22 +0200)
Zend/tests/constant_expressions_coalesce.phpt [new file with mode: 0644]
Zend/zend_ast.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_execute.h

diff --git a/Zend/tests/constant_expressions_coalesce.phpt b/Zend/tests/constant_expressions_coalesce.phpt
new file mode 100644 (file)
index 0000000..aa40bd6
--- /dev/null
@@ -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
index cfcd636269cb8ec509f32980375fdfdaafa7c32a..4d3678f0b60a7172ce4e35d67a89bdb987cabf2a 100644 (file)
@@ -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 {
index 89fd0e520ec117df2b9cc36288531e2bef36d851..18836d6418087de62242bda4b297e77c59b6cf17 100644 (file)
@@ -6833,7 +6833,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;
 }
 /* }}} */
 
index 1bf654eb92726a6e26ff70112177cc79ff46bf9c..9e30f55bdc329b70c7567e270f9eafaa1041a54e 100644 (file)
@@ -889,6 +889,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--;
index 8253fd5d85ae6648fa774c59758a87b696a7351e..324cf82e2b443677d2ee605ba6240a7dd46a707a 100644 (file)
@@ -1912,6 +1912,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)) {
index 83336061e4fad7507d933f0f5860dd1d533e7b45..c47667b8f0d6819d0e2e7750f1ae356e5f8bf409 100644 (file)
@@ -296,6 +296,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);