Evaluate const expression cast at ct if possible

Related to GH-18264
Closes GH-18347
This commit is contained in:
Ilija Tovilo 2025-04-17 13:52:17 +02:00
parent 27b83e3095
commit c97bdce962
No known key found for this signature in database
GPG key ID: 5050C66BFCD1015A
4 changed files with 101 additions and 25 deletions

View file

@ -82,31 +82,8 @@ zend_result zend_optimizer_eval_unary_op(zval *result, uint8_t opcode, zval *op1
zend_result zend_optimizer_eval_cast(zval *result, uint32_t type, zval *op1) /* {{{ */
{
switch (type) {
case IS_NULL:
ZVAL_NULL(result);
return SUCCESS;
case _IS_BOOL:
ZVAL_BOOL(result, zval_is_true(op1));
return SUCCESS;
case IS_LONG:
ZVAL_LONG(result, zval_get_long(op1));
return SUCCESS;
case IS_DOUBLE:
ZVAL_DOUBLE(result, zval_get_double(op1));
return SUCCESS;
case IS_STRING:
/* Conversion from double to string takes into account run-time
'precision' setting and cannot be evaluated at compile-time */
if (Z_TYPE_P(op1) != IS_ARRAY && Z_TYPE_P(op1) != IS_DOUBLE) {
ZVAL_STR(result, zval_get_string(op1));
return SUCCESS;
}
break;
case IS_ARRAY:
ZVAL_COPY(result, op1);
convert_to_array(result);
return SUCCESS;
if (zend_try_ct_eval_cast(result, type, op1)) {
return SUCCESS;
}
return FAILURE;
}

View file

@ -18,6 +18,28 @@ const T9 = (array) new DateTime;
const T10 = (int) new DateTime;
var_dump(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
const C_FLOAT = 0.3;
const C_EMPTY_ARRAY = [];
const C_ARRAY = ["a" => 1];
const C_INT = 5;
const C_EMPTY_STRING = "";
const C_CALLABLE = var_dump(...);
const C_USER_OBJECT = new X;
const C_DATE_TIME = new DateTime;
const T11 = (int) C_FLOAT;
const T12 = (bool) C_FLOAT;
const T13 = (string) C_EMPTY_ARRAY;
const T14 = (object) C_ARRAY;
const T15 = (float) C_INT;
const T16 = (array) C_EMPTY_STRING;
const T17 = (array) C_CALLABLE;
const T18 = (array) C_USER_OBJECT;
const T19 = (array) C_DATE_TIME;
const T20 = (int) C_DATE_TIME;
var_dump(T11, T12, T13, T14, T15, T16, T17, T18, T19, T20);
?>
--EXPECTF--
Warning: Array to string conversion in %s on line %d
@ -62,3 +84,46 @@ array(3) {
string(%d) "%s"
}
int(1)
Warning: Array to string conversion in %s on line %d
Warning: Object of class DateTime could not be converted to int in %s on line %d
int(0)
bool(true)
string(5) "Array"
object(stdClass)#%d (1) {
["a"]=>
int(1)
}
float(5)
array(1) {
[0]=>
string(0) ""
}
array(1) {
[0]=>
object(Closure)#%d (2) {
["function"]=>
string(8) "var_dump"
["parameter"]=>
array(2) {
["$value"]=>
string(10) "<required>"
["$values"]=>
string(10) "<optional>"
}
}
}
array(1) {
["foo"]=>
int(3)
}
array(3) {
["date"]=>
string(%d) "%s"
["timezone_type"]=>
int(%d)
["timezone"]=>
string(%d) "%s"
}
int(1)

View file

@ -11842,6 +11842,34 @@ static zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t
}
/* }}} */
bool zend_try_ct_eval_cast(zval *result, uint32_t type, zval *op1)
{
switch (type) {
case _IS_BOOL:
ZVAL_BOOL(result, zval_is_true(op1));
return true;
case IS_LONG:
ZVAL_LONG(result, zval_get_long(op1));
return true;
case IS_DOUBLE:
ZVAL_DOUBLE(result, zval_get_double(op1));
return true;
case IS_STRING:
/* Conversion from double to string takes into account run-time
'precision' setting and cannot be evaluated at compile-time */
if (Z_TYPE_P(op1) != IS_ARRAY && Z_TYPE_P(op1) != IS_DOUBLE) {
ZVAL_STR(result, zval_get_string(op1));
return true;
}
break;
case IS_ARRAY:
ZVAL_COPY(result, op1);
convert_to_array(result);
return true;
}
return false;
}
static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
{
zend_ast *ast = *ast_ptr;
@ -12129,6 +12157,10 @@ static void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
return;
case ZEND_AST_CAST:
zend_eval_const_expr(&ast->child[0]);
if (ast->child[0]->kind == ZEND_AST_ZVAL
&& zend_try_ct_eval_cast(&result, ast->attr, zend_ast_get_zval(ast->child[0]))) {
break;
}
return;
default:
return;

View file

@ -1301,4 +1301,6 @@ ZEND_API bool zend_is_op_long_compatible(const zval *op);
ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, const zval *op1, const zval *op2);
ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, const zval *op);
bool zend_try_ct_eval_cast(zval *result, uint32_t type, zval *op1);
#endif /* ZEND_COMPILE_H */