Skip to content

Commit b6958bb

Browse files
Girgiasnikic
andauthored
Implement "Deprecate implicit non-integer-compatible float to int conversions" RFC. (#6661)
RFC: https://wiki.php.net/rfc/implicit-float-int-deprecate Co-authored-by: Nikita Popov <nikita.ppv@gmail.com>
1 parent e006fd4 commit b6958bb

File tree

132 files changed

+2250
-2019
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

132 files changed

+2250
-2019
lines changed

Zend/Optimizer/pass1.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,12 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
119119
} else if (opline->extended_value == ZEND_MOD
120120
|| opline->extended_value == ZEND_SL
121121
|| opline->extended_value == ZEND_SR) {
122-
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
123-
/* don't optimize if it should produce a runtime numeric string error */
124-
if (!(Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING
125-
&& !is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0))) {
126-
convert_to_long(&ZEND_OP2_LITERAL(opline));
122+
zval *op2 = &ZEND_OP2_LITERAL(opline);
123+
if (Z_TYPE_P(op2) != IS_LONG) {
124+
if (!zend_is_op_long_compatible(op2)) {
125+
break;
127126
}
127+
convert_to_long(op2);
128128
}
129129
} else if (opline->extended_value == ZEND_CONCAT) {
130130
if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) {

Zend/Optimizer/sccp.c

+21-6
Original file line numberDiff line numberDiff line change
@@ -425,9 +425,14 @@ static inline int fetch_array_elem(zval **result, zval *op1, zval *op2) {
425425
case IS_LONG:
426426
*result = zend_hash_index_find(Z_ARR_P(op1), Z_LVAL_P(op2));
427427
return SUCCESS;
428-
case IS_DOUBLE:
429-
*result = zend_hash_index_find(Z_ARR_P(op1), zend_dval_to_lval(Z_DVAL_P(op2)));
428+
case IS_DOUBLE: {
429+
zend_long lval = zend_dval_to_lval(Z_DVAL_P(op2));
430+
if (!zend_is_long_compatible(Z_DVAL_P(op2), lval)) {
431+
return FAILURE;
432+
}
433+
*result = zend_hash_index_find(Z_ARR_P(op1), lval);
430434
return SUCCESS;
435+
}
431436
case IS_STRING:
432437
*result = zend_symtable_find(Z_ARR_P(op1), Z_STR_P(op2));
433438
return SUCCESS;
@@ -508,9 +513,14 @@ static inline int ct_eval_del_array_elem(zval *result, zval *key) {
508513
case IS_LONG:
509514
zend_hash_index_del(Z_ARR_P(result), Z_LVAL_P(key));
510515
break;
511-
case IS_DOUBLE:
512-
zend_hash_index_del(Z_ARR_P(result), zend_dval_to_lval(Z_DVAL_P(key)));
516+
case IS_DOUBLE: {
517+
zend_long lval = zend_dval_to_lval(Z_DVAL_P(key));
518+
if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
519+
return FAILURE;
520+
}
521+
zend_hash_index_del(Z_ARR_P(result), lval);
513522
break;
523+
}
514524
case IS_STRING:
515525
zend_symtable_del(Z_ARR_P(result), Z_STR_P(key));
516526
break;
@@ -548,11 +558,16 @@ static inline int ct_eval_add_array_elem(zval *result, zval *value, zval *key) {
548558
SEPARATE_ARRAY(result);
549559
value = zend_hash_index_update(Z_ARR_P(result), Z_LVAL_P(key), value);
550560
break;
551-
case IS_DOUBLE:
561+
case IS_DOUBLE: {
562+
zend_long lval = zend_dval_to_lval(Z_DVAL_P(key));
563+
if (!zend_is_long_compatible(Z_DVAL_P(key), lval)) {
564+
return FAILURE;
565+
}
552566
SEPARATE_ARRAY(result);
553567
value = zend_hash_index_update(
554-
Z_ARR_P(result), zend_dval_to_lval(Z_DVAL_P(key)), value);
568+
Z_ARR_P(result), lval, value);
555569
break;
570+
}
556571
case IS_STRING:
557572
SEPARATE_ARRAY(result);
558573
value = zend_symtable_update(Z_ARR_P(result), Z_STR_P(key), value);

Zend/Optimizer/zend_inference.c

+13-6
Original file line numberDiff line numberDiff line change
@@ -4481,7 +4481,6 @@ ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op,
44814481
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
44824482
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
44834483
case ZEND_DIV:
4484-
case ZEND_MOD:
44854484
if (!OP2_HAS_RANGE() ||
44864485
(OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
44874486
/* Division by zero */
@@ -4493,10 +4492,18 @@ ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op,
44934492
case ZEND_POW:
44944493
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
44954494
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4495+
/* Ops may throw if not an integer */
4496+
case ZEND_MOD:
4497+
if (!OP2_HAS_RANGE() ||
4498+
(OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) {
4499+
/* Division by zero */
4500+
return 1;
4501+
}
4502+
ZEND_FALLTHROUGH;
44964503
case ZEND_SL:
44974504
case ZEND_SR:
4498-
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4499-
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4505+
return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4506+
(t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
45004507
!OP2_HAS_RANGE() ||
45014508
OP2_MIN_RANGE() < 0;
45024509
case ZEND_CONCAT:
@@ -4510,10 +4517,10 @@ ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op,
45104517
&& (t2 & MAY_BE_ANY) == MAY_BE_STRING) {
45114518
return 0;
45124519
}
4513-
return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4514-
(t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4520+
return (t1 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
4521+
(t2 & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
45154522
case ZEND_BW_NOT:
4516-
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
4523+
return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
45174524
case ZEND_PRE_INC:
45184525
case ZEND_POST_INC:
45194526
case ZEND_PRE_DEC:

Zend/tests/array_offset.phpt

+4
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ echo "Done\n";
1313
--EXPECTF--
1414
Warning: Undefined array key -1 in %s on line %d
1515

16+
Deprecated: Implicit conversion from non-compatible float -1.1 to int in %s on line %d
17+
1618
Warning: Undefined array key -1 in %s on line %d
1719

1820
Warning: Undefined array key -1 in %s on line %d
1921

22+
Deprecated: Implicit conversion from non-compatible float -1.1 to int in %s on line %d
23+
2024
Warning: Undefined array key -1 in %s on line %d
2125
Done

Zend/tests/bug46701.phpt

+10-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ class foo {
2626
new foo;
2727

2828
?>
29-
--EXPECT--
29+
--EXPECTF--
30+
Deprecated: Implicit conversion from non-compatible float 3428599296 to int in %s on line %d
31+
32+
Deprecated: Implicit conversion from non-compatible float 3459455488 to int in %s on line %d
33+
34+
Deprecated: Implicit conversion from non-compatible float 3459616768 to int in %s on line %d
3035
array(3) {
3136
[-866368000]=>
3237
int(1)
@@ -35,7 +40,11 @@ array(3) {
3540
[-835350528]=>
3641
int(3)
3742
}
43+
44+
Deprecated: Implicit conversion from non-compatible float 3459455488 to int in %s on line %d
3845
int(2)
46+
47+
Deprecated: Implicit conversion from non-compatible float 3459616768 to int in %s on line %d
3948
array(1) {
4049
[-835350528]=>
4150
int(3)

Zend/tests/bug72347.phpt

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ function test() : int {
1212
}
1313
var_dump(test());
1414
?>
15-
--EXPECT--
15+
--EXPECTF--
16+
Deprecated: Implicit conversion from non-compatible float 1.5 to int in %s on line %d
1617
float(1.5)
1718
int(1)

Zend/tests/constant_expressions_dynamic.phpt

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ var_dump(
4646
?>
4747
--EXPECTF--
4848
Warning: A non-numeric value encountered in %s on line %d
49+
50+
Deprecated: Implicit conversion from non-compatible float 3.14 to int in %s on line %d
4951
int(3)
5052
string(4) "1foo"
5153
bool(false)

Zend/tests/empty_str_offset.phpt

+19-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ var_dump(empty($str[$f]));
6262
print "done\n";
6363

6464
?>
65-
--EXPECT--
65+
--EXPECTF--
6666
- empty ---
6767
bool(false)
6868
bool(true)
@@ -98,14 +98,32 @@ bool(true)
9898
- null ---
9999
bool(false)
100100
- double ---
101+
102+
Deprecated: Implicit conversion from non-compatible float -1.1 to int in %s on line %d
101103
bool(false)
104+
105+
Deprecated: Implicit conversion from non-compatible float -10.5 to int in %s on line %d
102106
bool(true)
107+
108+
Deprecated: Implicit conversion from non-compatible float -4.1 to int in %s on line %d
103109
bool(true)
110+
111+
Deprecated: Implicit conversion from non-compatible float -0.8 to int in %s on line %d
104112
bool(false)
113+
114+
Deprecated: Implicit conversion from non-compatible float -0.1 to int in %s on line %d
105115
bool(false)
116+
117+
Deprecated: Implicit conversion from non-compatible float 0.2 to int in %s on line %d
106118
bool(false)
119+
120+
Deprecated: Implicit conversion from non-compatible float 0.9 to int in %s on line %d
107121
bool(false)
122+
123+
Deprecated: Implicit conversion from non-compatible float 3.141592653589793 to int in %s on line %d
108124
bool(false)
125+
126+
Deprecated: Implicit conversion from non-compatible float 100.5001 to int in %s on line %d
109127
bool(true)
110128
- array ---
111129
bool(true)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Explicit (int) cast must not warn
3+
--SKIPIF--
4+
<?php
5+
if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
6+
?>
7+
--FILE--
8+
<?php
9+
10+
$values =[
11+
3.0,
12+
3.5,
13+
10e120,
14+
10e300,
15+
fdiv(0, 0),
16+
(string) 3.0,
17+
(string) 3.5,
18+
(string) 10e120,
19+
(string) 10e300,
20+
(string) fdiv(0, 0),
21+
];
22+
23+
foreach($values as $value) {
24+
var_dump((int) $value);
25+
}
26+
27+
?>
28+
--EXPECT--
29+
int(3)
30+
int(3)
31+
int(0)
32+
int(0)
33+
int(0)
34+
int(3)
35+
int(3)
36+
int(9223372036854775807)
37+
int(9223372036854775807)
38+
int(0)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Explicit (int) cast must not warn 32bit variation
3+
--SKIPIF--
4+
<?php
5+
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
6+
?>
7+
--FILE--
8+
<?php
9+
10+
$values =[
11+
3.0,
12+
3.5,
13+
10e120,
14+
10e300,
15+
fdiv(0, 0),
16+
(string) 3.0,
17+
(string) 3.5,
18+
(string) 10e120,
19+
(string) 10e300,
20+
(string) fdiv(0, 0),
21+
];
22+
23+
foreach($values as $value) {
24+
var_dump((int) $value);
25+
}
26+
27+
?>
28+
--EXPECT--
29+
int(3)
30+
int(3)
31+
int(0)
32+
int(0)
33+
int(0)
34+
int(3)
35+
int(3)
36+
int(2147483647)
37+
int(2147483647)
38+
int(0)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
Negative 0 check
3+
--FILE--
4+
<?php
5+
6+
$negativeZero = -0.0;
7+
var_dump($negativeZero);
8+
var_dump($negativeZero === (float)(int)$negativeZero);
9+
var_dump($negativeZero === 0.0);
10+
11+
?>
12+
--EXPECT--
13+
float(-0)
14+
bool(true)
15+
bool(true)

0 commit comments

Comments
 (0)