From 5be27b7a70926c8ae4ae2a35f9984f6e04042849 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jan 2021 14:47:45 +0100 Subject: [PATCH 1/5] avoid promoting division, modulo and indexing operations that could fail --- .../rustc_mir/src/transform/promote_consts.rs | 52 +++++++--- ...allocation2.main.ConstProp.after.32bit.mir | 28 +++--- ...allocation2.main.ConstProp.after.64bit.mir | 30 +++--- ...allocation3.main.ConstProp.after.32bit.mir | 16 ++-- ...allocation3.main.ConstProp.after.64bit.mir | 14 +-- src/test/ui/consts/array-literal-index-oob.rs | 2 - .../ui/consts/array-literal-index-oob.stderr | 22 +---- .../const-eval/const-eval-query-stack.rs | 10 +- .../const-eval/const-eval-query-stack.stderr | 34 ++++--- .../const-eval/promoted_errors.noopt.stderr | 94 +++++++------------ .../const-eval/promoted_errors.opt.stderr | 80 +++++++--------- ...ted_errors.opt_with_overflow_checks.stderr | 94 +++++++------------ .../ui/consts/const-eval/promoted_errors.rs | 45 +++++---- src/test/ui/consts/promote-not.rs | 7 ++ src/test/ui/consts/promote-not.stderr | 59 +++++++++++- src/test/ui/consts/promoted_div_by_zero.rs | 9 -- src/test/ui/consts/promotion.rs | 12 ++- 17 files changed, 317 insertions(+), 291 deletions(-) delete mode 100644 src/test/ui/consts/promoted_div_by_zero.rs diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index cac5abb1059a8..ce3e03e3c6dd5 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -505,6 +505,10 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} ProjectionElem::Index(local) => { + // This could be OOB, so reject for implicit promotion. + if !self.explicit { + return Err(Unpromotable); + } self.validate_local(local)?; } @@ -589,9 +593,7 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match rvalue { - Rvalue::Use(operand) - | Rvalue::Repeat(operand, _) - | Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => { + Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { self.validate_operand(operand)?; } @@ -616,10 +618,26 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(operand)?; } + Rvalue::NullaryOp(op, _) => match op { + NullOp::Box => return Err(Unpromotable), + NullOp::SizeOf => {} + }, + + Rvalue::UnaryOp(op, operand) => { + match op { + // These operations can never fail. + UnOp::Neg | UnOp::Not => {} + } + + self.validate_operand(operand)?; + } + Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => { let op = *op; - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { - // raw pointer operations are not allowed inside consts and thus not promotable + let lhs_ty = lhs.ty(self.body, self.tcx); + + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() { + // Raw and fn pointer operations are not allowed inside consts and thus not promotable. assert!(matches!( op, BinOp::Eq @@ -634,7 +652,22 @@ impl<'tcx> Validator<'_, 'tcx> { } match op { - // FIXME: reject operations that can fail -- namely, division and modulo. + BinOp::Div | BinOp::Rem => { + if !self.explicit && lhs_ty.is_integral() { + // Integer division: the RHS must be a non-zero const. + let const_val = match rhs { + Operand::Constant(c) => { + c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty) + } + _ => None, + }; + match const_val { + Some(x) if x != 0 => {} // okay + _ => return Err(Unpromotable), // value not known or 0 -- not okay + } + } + } + // The remaining operations can never fail. BinOp::Eq | BinOp::Ne | BinOp::Le @@ -645,8 +678,6 @@ impl<'tcx> Validator<'_, 'tcx> { | BinOp::Add | BinOp::Sub | BinOp::Mul - | BinOp::Div - | BinOp::Rem | BinOp::BitXor | BinOp::BitAnd | BinOp::BitOr @@ -658,11 +689,6 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(rhs)?; } - Rvalue::NullaryOp(op, _) => match op { - NullOp::Box => return Err(Unpromotable), - NullOp::SizeOf => {} - }, - Rvalue::AddressOf(_, place) => { // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is // no problem, only using it is. diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index d2e764f856f08..9fe3234f6ae4a 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -24,41 +24,41 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc27─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc31─╼ 03 00 00 00 │ ╾──╼.... } -alloc27 (size: 48, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc17─╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc25─╼ 03 00 00 00 │ ....*...╾──╼.... +alloc31 (size: 48, align: 4) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc14─╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc29─╼ 03 00 00 00 │ ....*...╾──╼.... } -alloc12 (size: 0, align: 4) {} +alloc8 (size: 0, align: 4) {} -alloc17 (size: 8, align: 4) { - ╾─alloc15─╼ ╾─alloc16─╼ │ ╾──╼╾──╼ +alloc14 (size: 8, align: 4) { + ╾─alloc12─╼ ╾─alloc13─╼ │ ╾──╼╾──╼ } -alloc15 (size: 1, align: 1) { +alloc12 (size: 1, align: 1) { 05 │ . } -alloc16 (size: 1, align: 1) { +alloc13 (size: 1, align: 1) { 06 │ . } -alloc25 (size: 12, align: 4) { - ╾─a21+0x3─╼ ╾─alloc22─╼ ╾─a24+0x2─╼ │ ╾──╼╾──╼╾──╼ +alloc29 (size: 12, align: 4) { + ╾─a21+0x3─╼ ╾─alloc23─╼ ╾─a28+0x2─╼ │ ╾──╼╾──╼╾──╼ } alloc21 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc22 (size: 1, align: 1) { +alloc23 (size: 1, align: 1) { 2a │ * } -alloc24 (size: 4, align: 1) { +alloc28 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index 00bf91f90bf61..3039f8ffab7e3 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -24,44 +24,44 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc27───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc31───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc27 (size: 72, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc12───────╼ │ ....░░░░╾──────╼ +alloc31 (size: 72, align: 8) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc17───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc25───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc14───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc29───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } -alloc12 (size: 0, align: 8) {} +alloc8 (size: 0, align: 8) {} -alloc17 (size: 16, align: 8) { - ╾───────alloc15───────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼ +alloc14 (size: 16, align: 8) { + ╾───────alloc12───────╼ ╾───────alloc13───────╼ │ ╾──────╼╾──────╼ } -alloc15 (size: 1, align: 1) { +alloc12 (size: 1, align: 1) { 05 │ . } -alloc16 (size: 1, align: 1) { +alloc13 (size: 1, align: 1) { 06 │ . } -alloc25 (size: 24, align: 8) { - 0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc22───────╼ │ ╾──────╼╾──────╼ - 0x10 │ ╾─────alloc24+0x2─────╼ │ ╾──────╼ +alloc29 (size: 24, align: 8) { + 0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc23───────╼ │ ╾──────╼╾──────╼ + 0x10 │ ╾─────alloc28+0x2─────╼ │ ╾──────╼ } alloc21 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc22 (size: 1, align: 1) { +alloc23 (size: 1, align: 1) { 2a │ * } -alloc24 (size: 4, align: 1) { +alloc28 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index 519002da392e2..cf7d82ef15e6a 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -24,30 +24,30 @@ fn main() -> () { } alloc0 (static: FOO, size: 4, align: 4) { - ╾─alloc10─╼ │ ╾──╼ + ╾─alloc11─╼ │ ╾──╼ } -alloc10 (size: 168, align: 1) { +alloc11 (size: 168, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc5──╼ │ ............╾──╼ + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼ 0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc7──╼ 00 00 │ ..........╾──╼.. - 0x90 │ ╾─a8+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ + 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc6──╼ 00 00 │ ..........╾──╼.. + 0x90 │ ╾─a9+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ 0xa0 │ 00 00 00 00 00 00 00 00 │ ........ } -alloc5 (size: 4, align: 4) { +alloc4 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc7 (fn: main) +alloc6 (fn: main) -alloc8 (size: 100, align: 1) { +alloc9 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index 73c4288c32e9d..f2227c40fcb0b 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -24,12 +24,12 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 8) { - ╾───────alloc10───────╼ │ ╾──────╼ + ╾───────alloc11───────╼ │ ╾──────╼ } -alloc10 (size: 180, align: 1) { +alloc11 (size: 180, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc5── │ ............╾─── + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾─── 0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ @@ -37,18 +37,18 @@ alloc10 (size: 180, align: 1) { 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─ - 0x90 │ ─────alloc7─────╼ 00 00 ╾─────alloc8+0x63─────╼ │ ─────╼..╾──────╼ + 0x90 │ ─────alloc6─────╼ 00 00 ╾─────alloc9+0x63─────╼ │ ─────╼..╾──────╼ 0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0xb0 │ 00 00 00 00 │ .... } -alloc5 (size: 4, align: 4) { +alloc4 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc7 (fn: main) +alloc6 (fn: main) -alloc8 (size: 100, align: 1) { +alloc9 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/ui/consts/array-literal-index-oob.rs b/src/test/ui/consts/array-literal-index-oob.rs index f36ebf38db4fe..9b3f735b1f849 100644 --- a/src/test/ui/consts/array-literal-index-oob.rs +++ b/src/test/ui/consts/array-literal-index-oob.rs @@ -6,6 +6,4 @@ fn main() { &{ [1, 2, 3][4] }; //~^ WARN operation will panic - //~| WARN reaching this expression at runtime will panic or abort - //~| WARN erroneous constant used [const_err] } diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index 5916ea6d323e6..f96b8d48b3e7c 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -10,25 +10,5 @@ note: the lint level is defined here LL | #![warn(const_err, unconditional_panic)] | ^^^^^^^^^^^^^^^^^^^ -warning: reaching this expression at runtime will panic or abort - --> $DIR/array-literal-index-oob.rs:7:8 - | -LL | &{ [1, 2, 3][4] }; - | ---^^^^^^^^^^^^-- - | | - | indexing out of bounds: the len is 3 but the index is 4 - | -note: the lint level is defined here - --> $DIR/array-literal-index-oob.rs:4:9 - | -LL | #![warn(const_err, unconditional_panic)] - | ^^^^^^^^^ - -warning: erroneous constant used - --> $DIR/array-literal-index-oob.rs:7:5 - | -LL | &{ [1, 2, 3][4] }; - | ^^^^^^^^^^^^^^^^^ referenced constant has errors - -warning: 3 warnings emitted +warning: 1 warning emitted diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.rs b/src/test/ui/consts/const-eval/const-eval-query-stack.rs index 8a6f7de1c9fbd..39803c8f257e0 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.rs +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.rs @@ -1,4 +1,5 @@ -// compile-flags: -Ztreat-err-as-bug +//~ERROR constructed but no error reported +// compile-flags: -Ztreat-err-as-bug=2 // build-fail // failure-status: 101 // rustc-env:RUST_BACKTRACE=1 @@ -15,8 +16,11 @@ #![allow(unconditional_panic)] +#[warn(const_err)] +const X: i32 = 1 / 0; //~WARN any use of this value will cause an error + fn main() { - let x: &'static i32 = &(1 / 0); - //~^ ERROR reaching this expression at runtime will panic or abort [const_err] + let x: &'static i32 = &X; + //~^ ERROR evaluation of constant expression failed println!("x={}", x); } diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index 8c57fd37e88f6..0016d301e598c 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -1,18 +1,26 @@ -error: reaching this expression at runtime will panic or abort - --> $DIR/const-eval-query-stack.rs:19:28 +warning: any use of this value will cause an error + --> $DIR/const-eval-query-stack.rs:20:16 | -LL | let x: &'static i32 = &(1 / 0); - | -^^^^^^^ - | | - | dividing by zero +LL | const X: i32 = 1 / 0; + | ---------------^^^^^- + | | + | attempt to divide `1_i32` by zero + | +note: the lint level is defined here + --> $DIR/const-eval-query-stack.rs:19:8 | - = note: `#[deny(const_err)]` on by default +LL | #[warn(const_err)] + | ^^^^^^^^^ +error[E0080]: evaluation of constant expression failed + --> $DIR/const-eval-query-stack.rs:23:27 + | +LL | let x: &'static i32 = &X; + | ^- + | | + | referenced constant has errors query stack during panic: -#0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]` -#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` -#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` -#3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` -#4 [optimized_mir] optimizing MIR for `main` -#5 [collect_and_partition_mono_items] collect_and_partition_mono_items +#0 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` +#1 [optimized_mir] optimizing MIR for `main` +#2 [collect_and_partition_mono_items] collect_and_partition_mono_items end of query stack diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr index ce83d8e9bb0c9..b71235e51c0a0 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -1,8 +1,8 @@ warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:12:20 + --> $DIR/promoted_errors.rs:13:5 | -LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow +LL | 0 - 1 + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -10,29 +10,24 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^^^^^^^^^^^ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:14:14 - | -LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:9:41 - | -LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ dividing by zero +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:13:5 + | +LL | 0 - 1 + | ^^^^^ + | | + | attempt to compute `0_u32 - 1_u32`, which would overflow + | inside `overflow` at $DIR/promoted_errors.rs:13:5 + | inside `X` at $DIR/promoted_errors.rs:31:29 +... +LL | / const X: () = { +LL | | let _x: &'static u32 = &overflow(); +LL | | +LL | | let _x: &'static i32 = &div_by_zero1(); +... | +LL | | let _x: &'static i32 = &oob(); +LL | | }; + | |__- | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:9 @@ -40,41 +35,18 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^ -warning: erroneous constant used - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ referenced constant has errors - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:20:14 - | -LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ dividing by zero - -warning: erroneous constant used - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ referenced constant has errors - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:26:14 +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:31:28 | -LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero +LL | / const X: () = { +LL | | let _x: &'static u32 = &overflow(); + | | ^^^^^^^^^^^ referenced constant has errors +LL | | +LL | | let _x: &'static i32 = &div_by_zero1(); +... | +LL | | let _x: &'static i32 = &oob(); +LL | | }; + | |__- -warning: 10 warnings emitted +warning: 3 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr index 2c66b175cfc2b..e5108f67e16c2 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr @@ -1,8 +1,8 @@ warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:14:14 + --> $DIR/promoted_errors.rs:13:5 | -LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow +LL | 0 - 1 + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -11,10 +11,10 @@ LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^^^^^^^^^^^ warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:16:20 + --> $DIR/promoted_errors.rs:17:5 | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero +LL | 1 / 0 + | ^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:41 @@ -22,11 +22,24 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^^^^^^^^^^^ -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:16:20 +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:17:5 | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ dividing by zero +LL | 1 / 0 + | ^^^^^ + | | + | attempt to divide `1_i32` by zero + | inside `div_by_zero1` at $DIR/promoted_errors.rs:17:5 + | inside `X` at $DIR/promoted_errors.rs:33:29 +... +LL | / const X: () = { +LL | | let _x: &'static u32 = &overflow(); +LL | | +LL | | let _x: &'static i32 = &div_by_zero1(); +... | +LL | | let _x: &'static i32 = &oob(); +LL | | }; + | |__- | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:9 @@ -34,41 +47,18 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^ -warning: erroneous constant used - --> $DIR/promoted_errors.rs:16:20 +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:33:28 | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ referenced constant has errors +LL | / const X: () = { +LL | | let _x: &'static u32 = &overflow(); +LL | | +LL | | let _x: &'static i32 = &div_by_zero1(); + | | ^^^^^^^^^^^^^^^ referenced constant has errors +... | +LL | | let _x: &'static i32 = &oob(); +LL | | }; + | |__- -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:20:14 - | -LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ dividing by zero - -warning: erroneous constant used - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ referenced constant has errors - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:26:14 - | -LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero - -warning: 9 warnings emitted +warning: 4 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr index ce83d8e9bb0c9..b71235e51c0a0 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -1,8 +1,8 @@ warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:12:20 + --> $DIR/promoted_errors.rs:13:5 | -LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow +LL | 0 - 1 + | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -10,29 +10,24 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^^^^^^^^^^^ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:14:14 - | -LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:9:41 - | -LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ dividing by zero +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:13:5 + | +LL | 0 - 1 + | ^^^^^ + | | + | attempt to compute `0_u32 - 1_u32`, which would overflow + | inside `overflow` at $DIR/promoted_errors.rs:13:5 + | inside `X` at $DIR/promoted_errors.rs:31:29 +... +LL | / const X: () = { +LL | | let _x: &'static u32 = &overflow(); +LL | | +LL | | let _x: &'static i32 = &div_by_zero1(); +... | +LL | | let _x: &'static i32 = &oob(); +LL | | }; + | |__- | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:9 @@ -40,41 +35,18 @@ note: the lint level is defined here LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] | ^^^^^^^^^ -warning: erroneous constant used - --> $DIR/promoted_errors.rs:16:20 - | -LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ referenced constant has errors - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:20:14 - | -LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide `1_i32` by zero - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero - -warning: reaching this expression at runtime will panic or abort - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ dividing by zero - -warning: erroneous constant used - --> $DIR/promoted_errors.rs:22:20 - | -LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ referenced constant has errors - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:26:14 +warning: any use of this value will cause an error + --> $DIR/promoted_errors.rs:31:28 | -LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero +LL | / const X: () = { +LL | | let _x: &'static u32 = &overflow(); + | | ^^^^^^^^^^^ referenced constant has errors +LL | | +LL | | let _x: &'static i32 = &div_by_zero1(); +... | +LL | | let _x: &'static i32 = &oob(); +LL | | }; + | |__- -warning: 10 warnings emitted +warning: 3 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index 142ce75eebc80..1f3b3eef509b1 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -8,21 +8,34 @@ #![warn(const_err, arithmetic_overflow, unconditional_panic)] +// The only way to have promoteds that fail is in `const fn` called from `const`/`static`. +const fn overflow() -> u32 { + 0 - 1 //~WARN arithmetic_overflow + //[opt_with_overflow_checks,noopt]~^ WARN any use of this value will cause an error +} +const fn div_by_zero1() -> i32 { + 1 / 0 //[opt]~WARN unconditional_panic + //[opt]~^ WARN any use of this value will cause an error +} +const fn div_by_zero2() -> i32 { + 1 / (1-1) +} +const fn div_by_zero3() -> i32 { + 1 / (false as i32) +} +const fn oob() -> i32 { + [1,2,3][4] +} + +const X: () = { + let _x: &'static u32 = &overflow(); + //[opt_with_overflow_checks,noopt]~^ WARN any use of this value will cause an error + let _x: &'static i32 = &div_by_zero1(); + //[opt]~^ WARN any use of this value will cause an error + let _x: &'static i32 = &div_by_zero2(); + let _x: &'static i32 = &div_by_zero3(); + let _x: &'static i32 = &oob(); +}; + fn main() { - println!("{}", 0u32 - 1); - //[opt_with_overflow_checks,noopt]~^ WARN [arithmetic_overflow] - let _x = 0u32 - 1; - //~^ WARN [arithmetic_overflow] - println!("{}", 1 / (1 - 1)); - //~^ WARN [unconditional_panic] - //~| WARN panic or abort [const_err] - //~| WARN erroneous constant used [const_err] - let _x = 1 / (1 - 1); - //~^ WARN [unconditional_panic] - println!("{}", 1 / (false as u32)); - //~^ WARN [unconditional_panic] - //~| WARN panic or abort [const_err] - //~| WARN erroneous constant used [const_err] - let _x = 1 / (false as u32); - //~^ WARN [unconditional_panic] } diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs index 1e4d8586b872c..0d0c78b0fc260 100644 --- a/src/test/ui/consts/promote-not.rs +++ b/src/test/ui/consts/promote-not.rs @@ -44,4 +44,11 @@ fn main() { // We must not promote things with interior mutability. Not even if we "project it away". let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed + + // No promotion of fallible operations. + let _val: &'static _ = &(1/0); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(1/(1-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed } diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr index 6e76d9ee6c165..108d0da7a674a 100644 --- a/src/test/ui/consts/promote-not.stderr +++ b/src/test/ui/consts/promote-not.stderr @@ -65,7 +65,7 @@ LL | let _val: &'static _ = &(Cell::new(1), 2).0; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` -LL | let _val: &'static _ = &(Cell::new(1), 2).1; +... LL | } | - temporary value is freed at the end of this statement @@ -76,9 +76,64 @@ LL | let _val: &'static _ = &(Cell::new(1), 2).1; | ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use | | | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:49:29 + | +LL | let _val: &'static _ = &(1/0); + | ---------- ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:50:29 + | +LL | let _val: &'static _ = &(1/(1-1)); + | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:51:29 + | +LL | let _val: &'static _ = &(1%0); + | ---------- ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +... +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:52:29 + | +LL | let _val: &'static _ = &(1%(1-1)); + | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | let _val: &'static _ = &([1,2,3][4]+1); +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:53:29 + | +LL | let _val: &'static _ = &([1,2,3][4]+1); + | ---------- ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` LL | } | - temporary value is freed at the end of this statement -error: aborting due to 8 previous errors +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/promoted_div_by_zero.rs b/src/test/ui/consts/promoted_div_by_zero.rs deleted file mode 100644 index b4503f691ffd9..0000000000000 --- a/src/test/ui/consts/promoted_div_by_zero.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![allow(unconditional_panic, const_err)] - -// run-fail -// error-pattern: attempt to divide by zero -// ignore-emscripten no processes - -fn main() { - let x = &(1 / (1 - 1)); -} diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index b6e7127a9b779..3d95296421335 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -1,4 +1,4 @@ -// check-pass +// run-pass // compile-flags: -O @@ -25,4 +25,14 @@ fn main() { // make sure that these do not cause trouble despite overflowing baz_u32(&(0-1)); baz_i32(&-i32::MIN); + + // div-by-non-0 is okay + baz_i32(&(1/1)); + baz_i32(&(1%1)); + + // Top-level projections do not get promoted, so no error here. + if false { + #[allow(unconditional_panic)] + baz_i32(&[1,2,3][4]); + } } From 69a997bef25e47ce0884a69a52a4120b0fe1b9c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jan 2021 18:41:10 +0100 Subject: [PATCH 2/5] update const_err description --- compiler/rustc_lint_defs/src/builtin.rs | 33 ++++++------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 20052ad9bfcbd..658372ac336a8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -238,41 +238,22 @@ declare_lint! { /// /// ```rust,compile_fail /// #![allow(unconditional_panic)] - /// let x: &'static i32 = &(1 / 0); + /// const C: i32 = 1/0; /// ``` /// /// {{produces}} /// /// ### Explanation /// - /// This lint detects code that is very likely incorrect. If this lint is - /// allowed, then the code will not be evaluated at compile-time, and - /// instead continue to generate code to evaluate at runtime, which may - /// panic during runtime. + /// This lint detects constants that fail to evaluate. Allowing the lint will accept the + /// constant declaration, but any use of this constant will still lead to a hard error. This is + /// a future incompatibility lint; the plan is to eventually entirely forbid even declaring + /// constants that cannot be evaluated. See [issue #71800] for more details. /// - /// Note that this lint may trigger in either inside or outside of a - /// [const context]. Outside of a [const context], the compiler can - /// sometimes evaluate an expression at compile-time in order to generate - /// more efficient code. As the compiler becomes better at doing this, it - /// needs to decide what to do when it encounters code that it knows for - /// certain will panic or is otherwise incorrect. Making this a hard error - /// would prevent existing code that exhibited this behavior from - /// compiling, breaking backwards-compatibility. However, this is almost - /// certainly incorrect code, so this is a deny-by-default lint. For more - /// details, see [RFC 1229] and [issue #28238]. - /// - /// Note that there are several other more specific lints associated with - /// compile-time evaluation, such as [`arithmetic_overflow`], - /// [`unconditional_panic`]. - /// - /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context - /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md - /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238 - /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow - /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic + /// [issue #71800]: https://github.com/rust-lang/rust/issues/71800 pub CONST_ERR, Deny, - "constant evaluation detected erroneous expression", + "constant evaluation encountered erroneous expression", report_in_external_macro } From f62cecd80761ae3de9134c5a021bcaa4aed9337e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jan 2021 20:03:22 +0100 Subject: [PATCH 3/5] do promote array indexing if we know it is in-bounds --- .../rustc_mir/src/transform/promote_consts.rs | 64 ++++++++++++++----- ...allocation2.main.ConstProp.after.32bit.mir | 28 ++++---- ...allocation2.main.ConstProp.after.64bit.mir | 30 ++++----- ...allocation3.main.ConstProp.after.32bit.mir | 16 ++--- ...allocation3.main.ConstProp.after.64bit.mir | 14 ++-- src/test/ui/consts/promotion.rs | 3 + 6 files changed, 96 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index ce3e03e3c6dd5..d8758e045443c 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -415,10 +415,11 @@ impl<'tcx> Validator<'_, 'tcx> { // FIXME(eddyb) maybe cache this? fn validate_local(&self, local: Local) -> Result<(), Unpromotable> { if let TempState::Defined { location: loc, .. } = self.temps[local] { - let num_stmts = self.body[loc.block].statements.len(); + let block = &self.body[loc.block]; + let num_stmts = block.statements.len(); if loc.statement_index < num_stmts { - let statement = &self.body[loc.block].statements[loc.statement_index]; + let statement = &block.statements[loc.statement_index]; match &statement.kind { StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs), _ => { @@ -430,7 +431,7 @@ impl<'tcx> Validator<'_, 'tcx> { } } } else { - let terminator = self.body[loc.block].terminator(); + let terminator = block.terminator(); match &terminator.kind { TerminatorKind::Call { func, args, .. } => self.validate_call(func, args), TerminatorKind::Yield { .. } => Err(Unpromotable), @@ -452,22 +453,15 @@ impl<'tcx> Validator<'_, 'tcx> { match elem { ProjectionElem::Deref => { let mut promotable = false; - // The `is_empty` predicate is introduced to exclude the case - // where the projection operations are [ .field, * ]. - // The reason is because promotion will be illegal if field - // accesses precede the dereferencing. + // We need to make sure this is a `Deref` of a local with no further projections. // Discussion can be found at // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247 - // There may be opportunity for generalization, but this needs to be - // accounted for. - if place_base.projection.is_empty() { + if let Some(local) = place_base.as_local() { // This is a special treatment for cases like *&STATIC where STATIC is a // global static variable. // This pattern is generated only when global static variables are directly // accessed and is qualified for promotion safely. - if let TempState::Defined { location, .. } = - self.temps[place_base.local] - { + if let TempState::Defined { location, .. } = self.temps[local] { let def_stmt = self.body[location.block] .statements .get(location.statement_index); @@ -505,9 +499,49 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} ProjectionElem::Index(local) => { - // This could be OOB, so reject for implicit promotion. if !self.explicit { - return Err(Unpromotable); + let mut promotable = false; + // Only accept if we can predict the index and are indexing an array. + let val = if let TempState::Defined { location: loc, .. } = + self.temps[local] + { + let block = &self.body[loc.block]; + if loc.statement_index < block.statements.len() { + let statement = &block.statements[loc.statement_index]; + match &statement.kind { + StatementKind::Assign(box ( + _, + Rvalue::Use(Operand::Constant(c)), + )) => c.literal.try_eval_usize(self.tcx, self.param_env), + _ => None, + } + } else { + None + } + } else { + None + }; + if let Some(idx) = val { + // Determine the type of the thing we are indexing. + let ty = place_base.ty(self.body, self.tcx).ty; + match ty.kind() { + ty::Array(_, len) => { + // It's an array; determine its length. + if let Some(len) = + len.try_eval_usize(self.tcx, self.param_env) + { + // If the index is in-bounds, go ahead. + if idx < len { + promotable = true; + } + } + } + _ => {} + } + } + if !promotable { + return Err(Unpromotable); + } } self.validate_local(local)?; } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index 9fe3234f6ae4a..d2e764f856f08 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -24,41 +24,41 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc31─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc27─╼ 03 00 00 00 │ ╾──╼.... } -alloc31 (size: 48, align: 4) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc14─╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc29─╼ 03 00 00 00 │ ....*...╾──╼.... +alloc27 (size: 48, align: 4) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 00 00 00 00 │ ....░░░░╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc17─╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc25─╼ 03 00 00 00 │ ....*...╾──╼.... } -alloc8 (size: 0, align: 4) {} +alloc12 (size: 0, align: 4) {} -alloc14 (size: 8, align: 4) { - ╾─alloc12─╼ ╾─alloc13─╼ │ ╾──╼╾──╼ +alloc17 (size: 8, align: 4) { + ╾─alloc15─╼ ╾─alloc16─╼ │ ╾──╼╾──╼ } -alloc12 (size: 1, align: 1) { +alloc15 (size: 1, align: 1) { 05 │ . } -alloc13 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 06 │ . } -alloc29 (size: 12, align: 4) { - ╾─a21+0x3─╼ ╾─alloc23─╼ ╾─a28+0x2─╼ │ ╾──╼╾──╼╾──╼ +alloc25 (size: 12, align: 4) { + ╾─a21+0x3─╼ ╾─alloc22─╼ ╾─a24+0x2─╼ │ ╾──╼╾──╼╾──╼ } alloc21 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc23 (size: 1, align: 1) { +alloc22 (size: 1, align: 1) { 2a │ * } -alloc28 (size: 4, align: 1) { +alloc24 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index 3039f8ffab7e3..00bf91f90bf61 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -24,44 +24,44 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc31───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc27───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc31 (size: 72, align: 8) { - 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼ +alloc27 (size: 72, align: 8) { + 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc12───────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc14───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc29───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc17───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc25───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } -alloc8 (size: 0, align: 8) {} +alloc12 (size: 0, align: 8) {} -alloc14 (size: 16, align: 8) { - ╾───────alloc12───────╼ ╾───────alloc13───────╼ │ ╾──────╼╾──────╼ +alloc17 (size: 16, align: 8) { + ╾───────alloc15───────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼ } -alloc12 (size: 1, align: 1) { +alloc15 (size: 1, align: 1) { 05 │ . } -alloc13 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 06 │ . } -alloc29 (size: 24, align: 8) { - 0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc23───────╼ │ ╾──────╼╾──────╼ - 0x10 │ ╾─────alloc28+0x2─────╼ │ ╾──────╼ +alloc25 (size: 24, align: 8) { + 0x00 │ ╾─────alloc21+0x3─────╼ ╾───────alloc22───────╼ │ ╾──────╼╾──────╼ + 0x10 │ ╾─────alloc24+0x2─────╼ │ ╾──────╼ } alloc21 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc23 (size: 1, align: 1) { +alloc22 (size: 1, align: 1) { 2a │ * } -alloc28 (size: 4, align: 1) { +alloc24 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir index cf7d82ef15e6a..519002da392e2 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir @@ -24,30 +24,30 @@ fn main() -> () { } alloc0 (static: FOO, size: 4, align: 4) { - ╾─alloc11─╼ │ ╾──╼ + ╾─alloc10─╼ │ ╾──╼ } -alloc11 (size: 168, align: 1) { +alloc10 (size: 168, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc4──╼ │ ............╾──╼ + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾─alloc5──╼ │ ............╾──╼ 0x20 │ 01 ef cd ab 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x50 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ - 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc6──╼ 00 00 │ ..........╾──╼.. - 0x90 │ ╾─a9+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ + 0x80 │ 00 00 00 00 00 00 00 00 00 00 ╾─alloc7──╼ 00 00 │ ..........╾──╼.. + 0x90 │ ╾─a8+0x63─╼ 00 00 00 00 00 00 00 00 00 00 00 00 │ ╾──╼............ 0xa0 │ 00 00 00 00 00 00 00 00 │ ........ } -alloc4 (size: 4, align: 4) { +alloc5 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc6 (fn: main) +alloc7 (fn: main) -alloc9 (size: 100, align: 1) { +alloc8 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir index f2227c40fcb0b..73c4288c32e9d 100644 --- a/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir +++ b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir @@ -24,12 +24,12 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 8) { - ╾───────alloc11───────╼ │ ╾──────╼ + ╾───────alloc10───────╼ │ ╾──────╼ } -alloc11 (size: 180, align: 1) { +alloc10 (size: 180, align: 1) { 0x00 │ ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab ab │ ................ - 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc4── │ ............╾─── + 0x10 │ ab ab ab ab ab ab ab ab ab ab ab ab ╾──alloc5── │ ............╾─── 0x20 │ ──────────╼ 01 ef cd ab 00 00 00 00 00 00 00 00 │ ───╼............ 0x30 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x40 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ @@ -37,18 +37,18 @@ alloc11 (size: 180, align: 1) { 0x60 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x70 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x80 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ╾──── │ ..............╾─ - 0x90 │ ─────alloc6─────╼ 00 00 ╾─────alloc9+0x63─────╼ │ ─────╼..╾──────╼ + 0x90 │ ─────alloc7─────╼ 00 00 ╾─────alloc8+0x63─────╼ │ ─────╼..╾──────╼ 0xa0 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0xb0 │ 00 00 00 00 │ .... } -alloc4 (size: 4, align: 4) { +alloc5 (size: 4, align: 4) { 2a 00 00 00 │ *... } -alloc6 (fn: main) +alloc7 (fn: main) -alloc9 (size: 100, align: 1) { +alloc8 (size: 100, align: 1) { 0x00 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ 0x20 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................ diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index 3d95296421335..e7726dd0a4b5b 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -30,6 +30,9 @@ fn main() { baz_i32(&(1/1)); baz_i32(&(1%1)); + // in-bounds array access is okay + baz_i32(&([1,2,3][0] + 1)); + // Top-level projections do not get promoted, so no error here. if false { #[allow(unconditional_panic)] From 0c7fd2c6855d9bdb5275537d59f3af525edba330 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jan 2021 20:11:23 +0100 Subject: [PATCH 4/5] expand successful-promotion test a bit --- src/test/ui/consts/promotion.rs | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index e7726dd0a4b5b..580c6d62f10af 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -1,41 +1,43 @@ -// run-pass +// revisions: noopt opt opt_with_overflow_checks +//[noopt]compile-flags: -C opt-level=0 +//[opt]compile-flags: -O +//[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O -// compile-flags: -O +// build-pass +#[allow(arithmetic_overflow)] -fn foo(_: &'static [&'static str]) {} -fn bar(_: &'static [&'static str; 3]) {} -const fn baz_i32(_: &'static i32) {} -const fn baz_u32(_: &'static u32) {} +const fn assert_static(_: &'static T) {} const fn fail() -> i32 { 1/0 } const C: i32 = { // Promoted that fails to evaluate in dead code -- this must work // (for backwards compatibility reasons). if false { - baz_i32(&fail()); + assert_static(&fail()); } 42 }; fn main() { - foo(&["a", "b", "c"]); - bar(&["d", "e", "f"]); + assert_static(&["a", "b", "c"]); + assert_static(&["d", "e", "f"]); assert_eq!(C, 42); // make sure that these do not cause trouble despite overflowing - baz_u32(&(0-1)); - baz_i32(&-i32::MIN); + assert_static(&(0-1)); + assert_static(&-i32::MIN); // div-by-non-0 is okay - baz_i32(&(1/1)); - baz_i32(&(1%1)); + assert_static(&(1/1)); + assert_static(&(1%1)); // in-bounds array access is okay - baz_i32(&([1,2,3][0] + 1)); + assert_static(&([1,2,3][0] + 1)); + assert_static(&[[1,2][1]]); - // Top-level projections do not get promoted, so no error here. + // Top-level projections are not part of the promoted, so no error here. if false { #[allow(unconditional_panic)] - baz_i32(&[1,2,3][4]); + assert_static(&[1,2,3][4]); } } From ccaabc9479c5627c38aa3a693f765a400b92e32d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jan 2021 10:56:28 +0100 Subject: [PATCH 5/5] re-bless ui tests --- .../const-eval/promoted_errors.noopt.stderr | 14 +--------- .../const-eval/promoted_errors.opt.stderr | 26 +------------------ ...ted_errors.opt_with_overflow_checks.stderr | 14 +--------- .../ui/consts/const-eval/promoted_errors.rs | 4 +-- 4 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr index b71235e51c0a0..1cd1be5309b90 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -1,15 +1,3 @@ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:13:5 - | -LL | 0 - 1 - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:9:20 - | -LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:13:5 | @@ -48,5 +36,5 @@ LL | | let _x: &'static i32 = &oob(); LL | | }; | |__- -warning: 3 warnings emitted +warning: 2 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr index e5108f67e16c2..ca62e21b61385 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr @@ -1,27 +1,3 @@ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:13:5 - | -LL | 0 - 1 - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:9:20 - | -LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - -warning: this operation will panic at runtime - --> $DIR/promoted_errors.rs:17:5 - | -LL | 1 / 0 - | ^^^^^ attempt to divide `1_i32` by zero - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:9:41 - | -LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:17:5 | @@ -60,5 +36,5 @@ LL | | let _x: &'static i32 = &oob(); LL | | }; | |__- -warning: 4 warnings emitted +warning: 2 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr index b71235e51c0a0..1cd1be5309b90 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -1,15 +1,3 @@ -warning: this arithmetic operation will overflow - --> $DIR/promoted_errors.rs:13:5 - | -LL | 0 - 1 - | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow - | -note: the lint level is defined here - --> $DIR/promoted_errors.rs:9:20 - | -LL | #![warn(const_err, arithmetic_overflow, unconditional_panic)] - | ^^^^^^^^^^^^^^^^^^^ - warning: any use of this value will cause an error --> $DIR/promoted_errors.rs:13:5 | @@ -48,5 +36,5 @@ LL | | let _x: &'static i32 = &oob(); LL | | }; | |__- -warning: 3 warnings emitted +warning: 2 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.rs b/src/test/ui/consts/const-eval/promoted_errors.rs index 1f3b3eef509b1..a2136c8d09be4 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.rs +++ b/src/test/ui/consts/const-eval/promoted_errors.rs @@ -10,11 +10,11 @@ // The only way to have promoteds that fail is in `const fn` called from `const`/`static`. const fn overflow() -> u32 { - 0 - 1 //~WARN arithmetic_overflow + 0 - 1 //[opt_with_overflow_checks,noopt]~^ WARN any use of this value will cause an error } const fn div_by_zero1() -> i32 { - 1 / 0 //[opt]~WARN unconditional_panic + 1 / 0 //[opt]~^ WARN any use of this value will cause an error } const fn div_by_zero2() -> i32 {