diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 577b8f2080fcd..2e11da4d585ef 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -482,17 +482,40 @@ impl<'tcx> Validator<'_, 'tcx> { match op { BinOp::Div | BinOp::Rem => { if lhs_ty.is_integral() { + let sz = lhs_ty.primitive_size(self.tcx); // Integer division: the RHS must be a non-zero const. - let const_val = match rhs { + let rhs_val = match rhs { Operand::Constant(c) => { - c.const_.try_eval_bits(self.tcx, self.param_env) + c.const_.try_eval_scalar_int(self.tcx, self.param_env) } _ => None, }; - match const_val { + match rhs_val.map(|x| x.try_to_uint(sz).unwrap()) { + // for the zero test, int vs uint does not matter Some(x) if x != 0 => {} // okay _ => return Err(Unpromotable), // value not known or 0 -- not okay } + // Furthermore, for signed divison, we also have to exclude `int::MIN / -1`. + if lhs_ty.is_signed() { + match rhs_val.map(|x| x.try_to_int(sz).unwrap()) { + Some(-1) | None => { + // The RHS is -1 or unknown, so we have to be careful. + // But is the LHS int::MIN? + let lhs_val = match lhs { + Operand::Constant(c) => c + .const_ + .try_eval_scalar_int(self.tcx, self.param_env), + _ => None, + }; + let lhs_min = sz.signed_int_min(); + match lhs_val.map(|x| x.try_to_int(sz).unwrap()) { + Some(x) if x != lhs_min => {} // okay + _ => return Err(Unpromotable), // value not known or int::MIN -- not okay + } + } + _ => {} + } + } } } // The remaining operations can never fail. diff --git a/tests/ui/consts/promote-not.rs b/tests/ui/consts/promote-not.rs index 907617052f119..47a06e8a72b71 100644 --- a/tests/ui/consts/promote-not.rs +++ b/tests/ui/consts/promote-not.rs @@ -49,6 +49,10 @@ fn main() { // 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+1)/(1-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(i32::MIN/-1); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(i32::MIN/(0-1)); //~ ERROR temporary value dropped while borrowed + let _val: &'static _ = &(-128i8/-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/tests/ui/consts/promote-not.stderr b/tests/ui/consts/promote-not.stderr index 524d69817217d..67ac5922efd96 100644 --- a/tests/ui/consts/promote-not.stderr +++ b/tests/ui/consts/promote-not.stderr @@ -105,6 +105,50 @@ LL | } error[E0716]: temporary value dropped while borrowed --> $DIR/promote-not.rs:52:29 | +LL | let _val: &'static _ = &((1+1)/(1-1)); + | ---------- ^^^^^^^^^^^^^ creates a temporary value 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:53:29 + | +LL | let _val: &'static _ = &(i32::MIN/-1); + | ---------- ^^^^^^^^^^^^^ creates a temporary value 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:54:29 + | +LL | let _val: &'static _ = &(i32::MIN/(0-1)); + | ---------- ^^^^^^^^^^^^^^^^ creates a temporary value 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:55:29 + | +LL | let _val: &'static _ = &(-128i8/-1); + | ---------- ^^^^^^^^^^^ creates a temporary value 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:56:29 + | LL | let _val: &'static _ = &(1%0); | ---------- ^^^^^ creates a temporary value which is freed while still in use | | @@ -114,7 +158,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:53:29 + --> $DIR/promote-not.rs:57:29 | LL | let _val: &'static _ = &(1%(1-1)); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -125,7 +169,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:54:29 + --> $DIR/promote-not.rs:58:29 | LL | let _val: &'static _ = &([1,2,3][4]+1); | ---------- ^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -136,7 +180,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:57:29 + --> $DIR/promote-not.rs:61:29 | LL | let _val: &'static _ = &TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -147,7 +191,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:59:29 + --> $DIR/promote-not.rs:63:29 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -158,7 +202,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:59:30 + --> $DIR/promote-not.rs:63:30 | LL | let _val: &'static _ = &&TEST_DROP; | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -169,7 +213,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:62:29 + --> $DIR/promote-not.rs:66:29 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -180,7 +224,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:62:31 + --> $DIR/promote-not.rs:66:31 | LL | let _val: &'static _ = &(&TEST_DROP,); | ---------- ^^^^^^^^^ creates a temporary value which is freed while still in use @@ -191,7 +235,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:65:29 + --> $DIR/promote-not.rs:69:29 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use @@ -202,7 +246,7 @@ LL | } | - temporary value is freed at the end of this statement error[E0716]: temporary value dropped while borrowed - --> $DIR/promote-not.rs:65:31 + --> $DIR/promote-not.rs:69:31 | LL | let _val: &'static _ = &[&TEST_DROP; 1]; | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement @@ -210,6 +254,6 @@ LL | let _val: &'static _ = &[&TEST_DROP; 1]; | | creates a temporary value which is freed while still in use | type annotation requires that borrow lasts for `'static` -error: aborting due to 20 previous errors +error: aborting due to 24 previous errors For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/consts/promotion.rs b/tests/ui/consts/promotion.rs index 211dcf8a4e8f2..b18495a4a6bf5 100644 --- a/tests/ui/consts/promotion.rs +++ b/tests/ui/consts/promotion.rs @@ -28,8 +28,11 @@ fn main() { // make sure that this does not cause trouble despite overflowing assert_static(&(0-1)); - // div-by-non-0 is okay + // div-by-non-0 (and also not MIN/-1) is okay assert_static(&(1/1)); + assert_static(&(0/1)); + assert_static(&(1/-1)); + assert_static(&(i32::MIN/1)); assert_static(&(1%1)); // in-bounds array access is okay