Skip to content

Commit a82c6f1

Browse files
committed
Evaluate const expression cast at ct if possible
Related to GH-18264.
1 parent 87499e4 commit a82c6f1

File tree

4 files changed

+101
-25
lines changed

4 files changed

+101
-25
lines changed

Diff for: Zend/Optimizer/zend_optimizer.c

+2-25
Original file line numberDiff line numberDiff line change
@@ -82,31 +82,8 @@ zend_result zend_optimizer_eval_unary_op(zval *result, uint8_t opcode, zval *op1
8282

8383
zend_result zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1) /* {{{ */
8484
{
85-
switch (type) {
86-
case IS_NULL:
87-
ZVAL_NULL(result);
88-
return SUCCESS;
89-
case _IS_BOOL:
90-
ZVAL_BOOL(result, zval_is_true(op1));
91-
return SUCCESS;
92-
case IS_LONG:
93-
ZVAL_LONG(result, zval_get_long(op1));
94-
return SUCCESS;
95-
case IS_DOUBLE:
96-
ZVAL_DOUBLE(result, zval_get_double(op1));
97-
return SUCCESS;
98-
case IS_STRING:
99-
/* Conversion from double to string takes into account run-time
100-
'precision' setting and cannot be evaluated at compile-time */
101-
if (Z_TYPE_P(op1) != IS_ARRAY && Z_TYPE_P(op1) != IS_DOUBLE) {
102-
ZVAL_STR(result, zval_get_string(op1));
103-
return SUCCESS;
104-
}
105-
break;
106-
case IS_ARRAY:
107-
ZVAL_COPY(result, op1);
108-
convert_to_array(result);
109-
return SUCCESS;
85+
if (zend_try_ct_eval_cast(result, type, op1)) {
86+
return SUCCESS;
11087
}
11188
return FAILURE;
11289
}

Diff for: Zend/tests/constexpr/constant_expressions_cast.phpt

+65
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@ const T9 = (array) new DateTime;
1818
const T10 = (int) new DateTime;
1919

2020
var_dump(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
21+
22+
const C_FLOAT = 0.3;
23+
const C_EMPTY_ARRAY = [];
24+
const C_ARRAY = ["a" => 1];
25+
const C_INT = 5;
26+
const C_EMPTY_STRING = "";
27+
const C_CALLABLE = var_dump(...);
28+
const C_USER_OBJECT = new X;
29+
const C_DATE_TIME = new DateTime;
30+
31+
const T11 = (int) C_FLOAT;
32+
const T12 = (bool) C_FLOAT;
33+
const T13 = (string) C_EMPTY_ARRAY;
34+
const T14 = (object) C_ARRAY;
35+
const T15 = (float) C_INT;
36+
const T16 = (array) C_EMPTY_STRING;
37+
const T17 = (array) C_CALLABLE;
38+
const T18 = (array) C_USER_OBJECT;
39+
const T19 = (array) C_DATE_TIME;
40+
const T20 = (int) C_DATE_TIME;
41+
42+
var_dump(T11, T12, T13, T14, T15, T16, T17, T18, T19, T20);
2143
?>
2244
--EXPECTF--
2345
Warning: Array to string conversion in %s on line %d
@@ -62,3 +84,46 @@ array(3) {
6284
string(%d) "%s"
6385
}
6486
int(1)
87+
88+
Warning: Array to string conversion in %s on line %d
89+
90+
Warning: Object of class DateTime could not be converted to int in %s on line %d
91+
int(0)
92+
bool(true)
93+
string(5) "Array"
94+
object(stdClass)#%d (1) {
95+
["a"]=>
96+
int(1)
97+
}
98+
float(5)
99+
array(1) {
100+
[0]=>
101+
string(0) ""
102+
}
103+
array(1) {
104+
[0]=>
105+
object(Closure)#%d (2) {
106+
["function"]=>
107+
string(8) "var_dump"
108+
["parameter"]=>
109+
array(2) {
110+
["$value"]=>
111+
string(10) "<required>"
112+
["$values"]=>
113+
string(10) "<optional>"
114+
}
115+
}
116+
}
117+
array(1) {
118+
["foo"]=>
119+
int(3)
120+
}
121+
array(3) {
122+
["date"]=>
123+
string(%d) "%s"
124+
["timezone_type"]=>
125+
int(%d)
126+
["timezone"]=>
127+
string(%d) "%s"
128+
}
129+
int(1)

Diff for: Zend/zend_compile.c

+32
Original file line numberDiff line numberDiff line change
@@ -11842,6 +11842,34 @@ static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t
1184211842
}
1184311843
/* }}} */
1184411844

11845+
bool zend_try_ct_eval_cast(zval *result, uint32_t type, zval *op1)
11846+
{
11847+
switch (type) {
11848+
case _IS_BOOL:
11849+
ZVAL_BOOL(result, zval_is_true(op1));
11850+
return true;
11851+
case IS_LONG:
11852+
ZVAL_LONG(result, zval_get_long(op1));
11853+
return true;
11854+
case IS_DOUBLE:
11855+
ZVAL_DOUBLE(result, zval_get_double(op1));
11856+
return true;
11857+
case IS_STRING:
11858+
/* Conversion from double to string takes into account run-time
11859+
'precision' setting and cannot be evaluated at compile-time */
11860+
if (Z_TYPE_P(op1) != IS_ARRAY && Z_TYPE_P(op1) != IS_DOUBLE) {
11861+
ZVAL_STR(result, zval_get_string(op1));
11862+
return true;
11863+
}
11864+
break;
11865+
case IS_ARRAY:
11866+
ZVAL_COPY(result, op1);
11867+
convert_to_array(result);
11868+
return true;
11869+
}
11870+
return false;
11871+
}
11872+
1184511873
static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
1184611874
{
1184711875
zend_ast *ast = *ast_ptr;
@@ -12129,6 +12157,10 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
1212912157
return;
1213012158
case ZEND_AST_CAST:
1213112159
zend_eval_const_expr(&ast->child[0]);
12160+
if (ast->child[0]->kind == ZEND_AST_ZVAL
12161+
&& zend_try_ct_eval_cast(&result, ast->attr, zend_ast_get_zval(ast->child[0]))) {
12162+
break;
12163+
}
1213212164
return;
1213312165
default:
1213412166
return;

Diff for: Zend/zend_compile.h

+2
Original file line numberDiff line numberDiff line change
@@ -1301,4 +1301,6 @@ ZEND_API bool zend_is_op_long_compatible(const zval *op);
13011301
ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, const zval *op1, const zval *op2);
13021302
ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, const zval *op);
13031303

1304+
bool zend_try_ct_eval_cast(zval *result, uint32_t type, zval *op1);
1305+
13041306
#endif /* ZEND_COMPILE_H */

0 commit comments

Comments
 (0)