Skip to content

Commit 5be27b7

Browse files
committed
avoid promoting division, modulo and indexing operations that could fail
1 parent dc1eee2 commit 5be27b7

17 files changed

+317
-291
lines changed

compiler/rustc_mir/src/transform/promote_consts.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,10 @@ impl<'tcx> Validator<'_, 'tcx> {
505505
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
506506

507507
ProjectionElem::Index(local) => {
508+
// This could be OOB, so reject for implicit promotion.
509+
if !self.explicit {
510+
return Err(Unpromotable);
511+
}
508512
self.validate_local(local)?;
509513
}
510514

@@ -589,9 +593,7 @@ impl<'tcx> Validator<'_, 'tcx> {
589593

590594
fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
591595
match rvalue {
592-
Rvalue::Use(operand)
593-
| Rvalue::Repeat(operand, _)
594-
| Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => {
596+
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
595597
self.validate_operand(operand)?;
596598
}
597599

@@ -616,10 +618,26 @@ impl<'tcx> Validator<'_, 'tcx> {
616618
self.validate_operand(operand)?;
617619
}
618620

621+
Rvalue::NullaryOp(op, _) => match op {
622+
NullOp::Box => return Err(Unpromotable),
623+
NullOp::SizeOf => {}
624+
},
625+
626+
Rvalue::UnaryOp(op, operand) => {
627+
match op {
628+
// These operations can never fail.
629+
UnOp::Neg | UnOp::Not => {}
630+
}
631+
632+
self.validate_operand(operand)?;
633+
}
634+
619635
Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
620636
let op = *op;
621-
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
622-
// raw pointer operations are not allowed inside consts and thus not promotable
637+
let lhs_ty = lhs.ty(self.body, self.tcx);
638+
639+
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() {
640+
// Raw and fn pointer operations are not allowed inside consts and thus not promotable.
623641
assert!(matches!(
624642
op,
625643
BinOp::Eq
@@ -634,7 +652,22 @@ impl<'tcx> Validator<'_, 'tcx> {
634652
}
635653

636654
match op {
637-
// FIXME: reject operations that can fail -- namely, division and modulo.
655+
BinOp::Div | BinOp::Rem => {
656+
if !self.explicit && lhs_ty.is_integral() {
657+
// Integer division: the RHS must be a non-zero const.
658+
let const_val = match rhs {
659+
Operand::Constant(c) => {
660+
c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty)
661+
}
662+
_ => None,
663+
};
664+
match const_val {
665+
Some(x) if x != 0 => {} // okay
666+
_ => return Err(Unpromotable), // value not known or 0 -- not okay
667+
}
668+
}
669+
}
670+
// The remaining operations can never fail.
638671
BinOp::Eq
639672
| BinOp::Ne
640673
| BinOp::Le
@@ -645,8 +678,6 @@ impl<'tcx> Validator<'_, 'tcx> {
645678
| BinOp::Add
646679
| BinOp::Sub
647680
| BinOp::Mul
648-
| BinOp::Div
649-
| BinOp::Rem
650681
| BinOp::BitXor
651682
| BinOp::BitAnd
652683
| BinOp::BitOr
@@ -658,11 +689,6 @@ impl<'tcx> Validator<'_, 'tcx> {
658689
self.validate_operand(rhs)?;
659690
}
660691

661-
Rvalue::NullaryOp(op, _) => match op {
662-
NullOp::Box => return Err(Unpromotable),
663-
NullOp::SizeOf => {}
664-
},
665-
666692
Rvalue::AddressOf(_, place) => {
667693
// We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
668694
// no problem, only using it is.

src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,41 +24,41 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 8, align: 4) {
27-
╾─alloc27─╼ 03 00 00 00 │ ╾──╼....
27+
╾─alloc31─╼ 03 00 00 00 │ ╾──╼....
2828
}
2929

30-
alloc27 (size: 48, align: 4) {
31-
0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 00 00 00 00 │ ....░░░░╾──╼....
32-
0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc17─╼ 02 00 00 00 │ ....░░░░╾──╼....
33-
0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc25─╼ 03 00 00 00 │ ....*...╾──╼....
30+
alloc31 (size: 48, align: 4) {
31+
0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼....
32+
0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc14─╼ 02 00 00 00 │ ....░░░░╾──╼....
33+
0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc29─╼ 03 00 00 00 │ ....*...╾──╼....
3434
}
3535

36-
alloc12 (size: 0, align: 4) {}
36+
alloc8 (size: 0, align: 4) {}
3737

38-
alloc17 (size: 8, align: 4) {
39-
╾─alloc15─╼ ╾─alloc16─╼ │ ╾──╼╾──╼
38+
alloc14 (size: 8, align: 4) {
39+
╾─alloc12─╼ ╾─alloc13─╼ │ ╾──╼╾──╼
4040
}
4141

42-
alloc15 (size: 1, align: 1) {
42+
alloc12 (size: 1, align: 1) {
4343
05 │ .
4444
}
4545

46-
alloc16 (size: 1, align: 1) {
46+
alloc13 (size: 1, align: 1) {
4747
06 │ .
4848
}
4949

50-
alloc25 (size: 12, align: 4) {
51-
╾─a21+0x3─╼ ╾─alloc22─╼ ╾─a24+0x2─╼ │ ╾──╼╾──╼╾──╼
50+
alloc29 (size: 12, align: 4) {
51+
╾─a21+0x3─╼ ╾─alloc23─╼ ╾─a28+0x2─╼ │ ╾──╼╾──╼╾──╼
5252
}
5353

5454
alloc21 (size: 4, align: 1) {
5555
2a 45 15 6f │ *E.o
5656
}
5757

58-
alloc22 (size: 1, align: 1) {
58+
alloc23 (size: 1, align: 1) {
5959
2a │ *
6060
}
6161

62-
alloc24 (size: 4, align: 1) {
62+
alloc28 (size: 4, align: 1) {
6363
2a 45 15 6f │ *E.o
6464
}

src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,44 +24,44 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 16, align: 8) {
27-
╾───────alloc27───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
27+
╾───────alloc31───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........
2828
}
2929

30-
alloc27 (size: 72, align: 8) {
31-
0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc12───────╼ │ ....░░░░╾──────╼
30+
alloc31 (size: 72, align: 8) {
31+
0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼
3232
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░
33-
0x20 │ ╾───────alloc17───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
34-
0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc25───────╼ │ ....*...╾──────╼
33+
0x20 │ ╾───────alloc14───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........
34+
0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc29───────╼ │ ....*...╾──────╼
3535
0x40 │ 03 00 00 00 00 00 00 00 │ ........
3636
}
3737

38-
alloc12 (size: 0, align: 8) {}
38+
alloc8 (size: 0, align: 8) {}
3939

40-
alloc17 (size: 16, align: 8) {
41-
╾───────alloc15───────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼
40+
alloc14 (size: 16, align: 8) {
41+
╾───────alloc12───────╼ ╾───────alloc13───────╼ │ ╾──────╼╾──────╼
4242
}
4343

44-
alloc15 (size: 1, align: 1) {
44+
alloc12 (size: 1, align: 1) {
4545
05 │ .
4646
}
4747

48-
alloc16 (size: 1, align: 1) {
48+
alloc13 (size: 1, align: 1) {
4949
06 │ .
5050
}
5151

52-
alloc25 (size: 24, align: 8) {
53-
0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc22───────╼ │ ╾──────╼╾──────╼
54-
0x10 │ ╾─────alloc24+0x2─────╼ │ ╾──────╼
52+
alloc29 (size: 24, align: 8) {
53+
0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc23───────╼ │ ╾──────╼╾──────╼
54+
0x10 │ ╾─────alloc28+0x2─────╼ │ ╾──────╼
5555
}
5656

5757
alloc21 (size: 4, align: 1) {
5858
2a 45 15 6f │ *E.o
5959
}
6060

61-
alloc22 (size: 1, align: 1) {
61+
alloc23 (size: 1, align: 1) {
6262
2a │ *
6363
}
6464

65-
alloc24 (size: 4, align: 1) {
65+
alloc28 (size: 4, align: 1) {
6666
2a 45 15 6f │ *E.o
6767
}

src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,30 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 4, align: 4) {
27-
╾─alloc10─╼ │ ╾──╼
27+
╾─alloc11─╼ │ ╾──╼
2828
}
2929

30-
alloc10 (size: 168, align: 1) {
30+
alloc11 (size: 168, align: 1) {
3131
0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
32-
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc5──╼ │ ............╾──╼
32+
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼
3333
0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3434
0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3535
0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3636
0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3737
0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3838
0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
39-
0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc7──╼ 00 00 │ ..........╾──╼..
40-
0x90 │ ╾─a8+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
39+
0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc6──╼ 00 00 │ ..........╾──╼..
40+
0x90 │ ╾─a9+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............
4141
0xa0 │ 00 00 00 00 00 00 00 00 │ ........
4242
}
4343

44-
alloc5 (size: 4, align: 4) {
44+
alloc4 (size: 4, align: 4) {
4545
2a 00 00 00 │ *...
4646
}
4747

48-
alloc7 (fn: main)
48+
alloc6 (fn: main)
4949

50-
alloc8 (size: 100, align: 1) {
50+
alloc9 (size: 100, align: 1) {
5151
0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5252
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5353
0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................

src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,31 @@ fn main() -> () {
2424
}
2525

2626
alloc0 (static: FOO, size: 8, align: 8) {
27-
╾───────alloc10───────╼ │ ╾──────╼
27+
╾───────alloc11───────╼ │ ╾──────╼
2828
}
2929

30-
alloc10 (size: 180, align: 1) {
30+
alloc11 (size: 180, align: 1) {
3131
0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................
32-
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc5── │ ............╾───
32+
0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾───
3333
0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............
3434
0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3535
0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3636
0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3737
0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3838
0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
3939
0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─
40-
0x90 │ ─────alloc7─────╼ 00 00 ╾─────alloc8+0x63─────╼ │ ─────╼..╾──────╼
40+
0x90 │ ─────alloc6─────╼ 00 00 ╾─────alloc9+0x63─────╼ │ ─────╼..╾──────╼
4141
0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
4242
0xb0 │ 00 00 00 00 │ ....
4343
}
4444

45-
alloc5 (size: 4, align: 4) {
45+
alloc4 (size: 4, align: 4) {
4646
2a 00 00 00 │ *...
4747
}
4848

49-
alloc7 (fn: main)
49+
alloc6 (fn: main)
5050

51-
alloc8 (size: 100, align: 1) {
51+
alloc9 (size: 100, align: 1) {
5252
0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5353
0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
5454
0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................

src/test/ui/consts/array-literal-index-oob.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,4 @@
66
fn main() {
77
&{ [1, 2, 3][4] };
88
//~^ WARN operation will panic
9-
//~| WARN reaching this expression at runtime will panic or abort
10-
//~| WARN erroneous constant used [const_err]
119
}

src/test/ui/consts/array-literal-index-oob.stderr

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,5 @@ note: the lint level is defined here
1010
LL | #![warn(const_err, unconditional_panic)]
1111
| ^^^^^^^^^^^^^^^^^^^
1212

13-
warning: reaching this expression at runtime will panic or abort
14-
--> $DIR/array-literal-index-oob.rs:7:8
15-
|
16-
LL | &{ [1, 2, 3][4] };
17-
| ---^^^^^^^^^^^^--
18-
| |
19-
| indexing out of bounds: the len is 3 but the index is 4
20-
|
21-
note: the lint level is defined here
22-
--> $DIR/array-literal-index-oob.rs:4:9
23-
|
24-
LL | #![warn(const_err, unconditional_panic)]
25-
| ^^^^^^^^^
26-
27-
warning: erroneous constant used
28-
--> $DIR/array-literal-index-oob.rs:7:5
29-
|
30-
LL | &{ [1, 2, 3][4] };
31-
| ^^^^^^^^^^^^^^^^^ referenced constant has errors
32-
33-
warning: 3 warnings emitted
13+
warning: 1 warning emitted
3414

src/test/ui/consts/const-eval/const-eval-query-stack.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// compile-flags: -Ztreat-err-as-bug
1+
//~ERROR constructed but no error reported
2+
// compile-flags: -Ztreat-err-as-bug=2
23
// build-fail
34
// failure-status: 101
45
// rustc-env:RUST_BACKTRACE=1
@@ -15,8 +16,11 @@
1516

1617
#![allow(unconditional_panic)]
1718

19+
#[warn(const_err)]
20+
const X: i32 = 1 / 0; //~WARN any use of this value will cause an error
21+
1822
fn main() {
19-
let x: &'static i32 = &(1 / 0);
20-
//~^ ERROR reaching this expression at runtime will panic or abort [const_err]
23+
let x: &'static i32 = &X;
24+
//~^ ERROR evaluation of constant expression failed
2125
println!("x={}", x);
2226
}
Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,26 @@
1-
error: reaching this expression at runtime will panic or abort
2-
--> $DIR/const-eval-query-stack.rs:19:28
1+
warning: any use of this value will cause an error
2+
--> $DIR/const-eval-query-stack.rs:20:16
33
|
4-
LL | let x: &'static i32 = &(1 / 0);
5-
| -^^^^^^^
6-
| |
7-
| dividing by zero
4+
LL | const X: i32 = 1 / 0;
5+
| ---------------^^^^^-
6+
| |
7+
| attempt to divide `1_i32` by zero
8+
|
9+
note: the lint level is defined here
10+
--> $DIR/const-eval-query-stack.rs:19:8
811
|
9-
= note: `#[deny(const_err)]` on by default
12+
LL | #[warn(const_err)]
13+
| ^^^^^^^^^
1014

15+
error[E0080]: evaluation of constant expression failed
16+
--> $DIR/const-eval-query-stack.rs:23:27
17+
|
18+
LL | let x: &'static i32 = &X;
19+
| ^-
20+
| |
21+
| referenced constant has errors
1122
query stack during panic:
12-
#0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]`
13-
#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
14-
#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]`
15-
#3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]`
16-
#4 [optimized_mir] optimizing MIR for `main`
17-
#5 [collect_and_partition_mono_items] collect_and_partition_mono_items
23+
#0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]`
24+
#1 [optimized_mir] optimizing MIR for `main`
25+
#2 [collect_and_partition_mono_items] collect_and_partition_mono_items
1826
end of query stack

0 commit comments

Comments
 (0)