diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 79dba2c5db8fb..150ffefd207f7 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -521,31 +521,37 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { None } + /// Check for overflow for a unary op. Like check_binary_op, safe to call even if the operand + /// needs substs. In that case, no work is done. fn check_unary_op( &mut self, op: UnOp, arg: &Operand<'tcx>, source_info: SourceInfo, ) -> Option<()> { - if self.use_ecx(|this| { - let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?; - let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?; - Ok(overflow) - })? { - // `AssertKind` only has an `OverflowNeg` variant, so make sure that is - // appropriate to use. - assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); - self.report_assert_as_lint( - lint::builtin::ARITHMETIC_OVERFLOW, - source_info, - "this arithmetic operation will overflow", - AssertKind::OverflowNeg, - )?; + if !arg.needs_subst() { + if self.use_ecx(|this| { + let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?; + let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?; + Ok(overflow) + })? { + // `AssertKind` only has an `OverflowNeg` variant, so make sure that is + // appropriate to use. + assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow"); + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::OverflowNeg, + )?; + } } Some(()) } + /// Check a binary operand for overflow. Safe to call with values that need substs -- those + /// values just won't be checked. fn check_binary_op( &mut self, op: BinOp, @@ -553,40 +559,44 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { right: &Operand<'tcx>, source_info: SourceInfo, ) -> Option<()> { - let r = - self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?; - // Check for exceeding shifts *even if* we cannot evaluate the LHS. - if op == BinOp::Shr || op == BinOp::Shl { - // We need the type of the LHS. We cannot use `place_layout` as that is the type - // of the result, which for checked binops is not the same! - let left_ty = left.ty(&self.local_decls, self.tcx); - let left_size_bits = self.ecx.layout_of(left_ty).ok()?.size.bits(); - let right_size = r.layout.size; - let r_bits = r.to_scalar().ok(); - // This is basically `force_bits`. - let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok()); - if r_bits.map_or(false, |b| b >= left_size_bits as u128) { - self.report_assert_as_lint( - lint::builtin::ARITHMETIC_OVERFLOW, - source_info, - "this arithmetic operation will overflow", - AssertKind::Overflow(op), - )?; + if !right.needs_subst() { + let r = + self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?; + // Check for exceeding shifts *even if* we cannot evaluate the LHS. + if op == BinOp::Shr || op == BinOp::Shl { + // We need the type of the LHS. We cannot use `place_layout` as that is the type + // of the result, which for checked binops is not the same! + let left_ty = left.ty(&self.local_decls, self.tcx); + let left_size_bits = self.ecx.layout_of(left_ty).ok()?.size.bits(); + let right_size = r.layout.size; + let r_bits = r.to_scalar().ok(); + // This is basically `force_bits`. + let r_bits = r_bits.and_then(|r| r.to_bits_or_ptr(right_size, &self.tcx).ok()); + if r_bits.map_or(false, |b| b >= left_size_bits as u128) { + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::Overflow(op), + )?; + } } - } - // The remaining operators are handled through `overflowing_binary_op`. - if self.use_ecx(|this| { - let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; - let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?; - Ok(overflow) - })? { - self.report_assert_as_lint( - lint::builtin::ARITHMETIC_OVERFLOW, - source_info, - "this arithmetic operation will overflow", - AssertKind::Overflow(op), - )?; + if !left.needs_subst() { + // The remaining operators are handled through `overflowing_binary_op`. + if self.use_ecx(|this| { + let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?; + let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?; + Ok(overflow) + })? { + self.report_assert_as_lint( + lint::builtin::ARITHMETIC_OVERFLOW, + source_info, + "this arithmetic operation will overflow", + AssertKind::Overflow(op), + )?; + } + } } Some(()) diff --git a/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs b/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs index 4444cdfcda9c7..92153d7940aac 100644 --- a/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs +++ b/src/test/ui/consts/const-eval/ice-generic-assoc-const.rs @@ -1,4 +1,5 @@ -// check-pass +// build-pass +#![crate_type = "lib"] pub trait Nullable { const NULL: Self; @@ -13,6 +14,3 @@ impl Nullable for *const T { *self == Self::NULL } } - -fn main() { -}