Also fix general memory leak when root ast gets replaced in compile time evaluation
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;
+const T_5 = null ?? __LINE__;
+const T_6 = __LINE__ ?? "bar";
var_dump(T_1);
var_dump(T_2);
var_dump(T_3);
var_dump(T_4);
+var_dump(T_5);
+var_dump(T_6);
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((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(%d)
+int(%d)
int(1)
int(2)
int(3)
int(2)
int(3)
int(4)
-
-Fatal error: Cannot use [] for reading in %s.php on line 25
--- /dev/null
+--TEST--
+Constant expressions with empty dimension fetch on coalesce
+--FILE--
+<?php
+
+const A = [][] ?? 1;
+
+?>
+--EXPECTF--
+Fatal error: Cannot use [] for reading in %s.php on line %d
+
false => false,
true => true,
];
+eval("const T_20x = 'a';");
+const T_20 = null ?: (T_20x . 'bc');
var_dump(
T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9, T_10,
- T_11, T_12, T_13, T_14, T_15, T_16, T_17, T_18, T_19
+ T_11, T_12, T_13, T_14, T_15, T_16, T_17, T_18, T_19, T_20
);
?>
[1]=>
bool(true)
}
+string(3) "abc"
zend_compile_const_expr(&ast);
if (ast->kind == ZEND_AST_ZVAL) {
ZVAL_COPY_VALUE(result, zend_ast_get_zval(ast));
-
- /* Kill this branch of the original AST, as it was already destroyed.
- * It would be nice to find a better solution to this problem in the
- * future. */
- orig_ast->kind = 0;
} else {
ZVAL_NEW_AST(result, zend_ast_copy(ast));
+ /* destroy the ast here, it might have been replaced */
+ zend_ast_destroy(ast);
}
+
+ /* Kill this branch of the original AST, as it was already destroyed.
+ * It would be nice to find a better solution to this problem in the
+ * future. */
+ orig_ast->kind = 0;
}
/* }}} */
zend_ct_eval_unary_pm(&result, ast->kind, zend_ast_get_zval(ast->child[0]));
break;
+ case ZEND_AST_COALESCE:
+ zend_eval_const_expr(&ast->child[0]);
+
+ if (ast->child[0]->kind != ZEND_AST_ZVAL) {
+ /* ensure everything was compile-time evaluated at least once */
+ zend_eval_const_expr(&ast->child[1]);
+ return;
+ }
+
+ if (Z_TYPE_P(zend_ast_get_zval(ast->child[0])) == IS_NULL) {
+ zend_eval_const_expr(&ast->child[1]);
+ *ast_ptr = ast->child[1];
+ ast->child[1] = NULL;
+ zend_ast_destroy(ast);
+ } else {
+ *ast_ptr = ast->child[0];
+ ast->child[0] = NULL;
+ zend_ast_destroy(ast);
+ }
+ return;
case ZEND_AST_CONDITIONAL:
{
zend_ast **child, *child_ast;
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);
+ zend_fetch_dimension_address_read(result, container, dim, dim_type, BP_VAR_IS);
}