Skip to content

Commit 819cde5

Browse files
committed
Show the values and computation that would overflow a const evaluation or propagation
1 parent e093b65 commit 819cde5

File tree

202 files changed

+1273
-986
lines changed

Some content is hidden

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

202 files changed

+1273
-986
lines changed

src/librustc_codegen_ssa/mir/block.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
380380
// checked operation, just a comparison with the minimum
381381
// value, so we have to check for the assert message.
382382
if !bx.check_overflow() {
383-
if let AssertKind::OverflowNeg = *msg {
383+
if let AssertKind::OverflowNeg(_) = *msg {
384384
const_cond = Some(expected);
385385
}
386386
}

src/librustc_middle/mir/mod.rs

+88-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
//!
33
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
44
5+
// ignore-tidy-filelength
6+
57
use crate::mir::interpret::{GlobalAlloc, Scalar};
68
use crate::mir::visit::MirVisitable;
79
use crate::ty::adjustment::PointerCast;
@@ -1246,10 +1248,10 @@ pub enum TerminatorKind<'tcx> {
12461248
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable, PartialEq)]
12471249
pub enum AssertKind<O> {
12481250
BoundsCheck { len: O, index: O },
1249-
Overflow(BinOp),
1250-
OverflowNeg,
1251-
DivisionByZero,
1252-
RemainderByZero,
1251+
Overflow(BinOp, O, O),
1252+
OverflowNeg(O),
1253+
DivisionByZero(O),
1254+
RemainderByZero(O),
12531255
ResumedAfterReturn(GeneratorKind),
12541256
ResumedAfterPanic(GeneratorKind),
12551257
}
@@ -1522,17 +1524,17 @@ impl<O> AssertKind<O> {
15221524
pub fn description(&self) -> &'static str {
15231525
use AssertKind::*;
15241526
match self {
1525-
Overflow(BinOp::Add) => "attempt to add with overflow",
1526-
Overflow(BinOp::Sub) => "attempt to subtract with overflow",
1527-
Overflow(BinOp::Mul) => "attempt to multiply with overflow",
1528-
Overflow(BinOp::Div) => "attempt to divide with overflow",
1529-
Overflow(BinOp::Rem) => "attempt to calculate the remainder with overflow",
1530-
OverflowNeg => "attempt to negate with overflow",
1531-
Overflow(BinOp::Shr) => "attempt to shift right with overflow",
1532-
Overflow(BinOp::Shl) => "attempt to shift left with overflow",
1533-
Overflow(op) => bug!("{:?} cannot overflow", op),
1534-
DivisionByZero => "attempt to divide by zero",
1535-
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
1527+
Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
1528+
Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
1529+
Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
1530+
Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
1531+
Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
1532+
OverflowNeg(_) => "attempt to negate with overflow",
1533+
Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
1534+
Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
1535+
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
1536+
DivisionByZero(_) => "attempt to divide by zero",
1537+
RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
15361538
ResumedAfterReturn(GeneratorKind::Gen) => "generator resumed after completion",
15371539
ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
15381540
ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
@@ -1546,12 +1548,54 @@ impl<O> AssertKind<O> {
15461548
where
15471549
O: Debug,
15481550
{
1551+
use AssertKind::*;
15491552
match self {
1550-
AssertKind::BoundsCheck { ref len, ref index } => write!(
1553+
BoundsCheck { ref len, ref index } => write!(
15511554
f,
15521555
"\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}",
15531556
len, index
15541557
),
1558+
1559+
OverflowNeg(op) => {
1560+
write!(f, "\"attempt to negate {{}} which would overflow\", {:?}", op)
1561+
}
1562+
DivisionByZero(op) => write!(f, "\"attempt to divide {{}} by zero\", {:?}", op),
1563+
RemainderByZero(op) => write!(
1564+
f,
1565+
"\"attempt to calculate the remainder of {{}} with a divisor of zero\", {:?}",
1566+
op
1567+
),
1568+
Overflow(BinOp::Add, l, r) => write!(
1569+
f,
1570+
"\"attempt to compute `{{}} + {{}}` which would overflow\", {:?}, {:?}",
1571+
l, r
1572+
),
1573+
Overflow(BinOp::Sub, l, r) => write!(
1574+
f,
1575+
"\"attempt to compute `{{}} - {{}}` which would overflow\", {:?}, {:?}",
1576+
l, r
1577+
),
1578+
Overflow(BinOp::Mul, l, r) => write!(
1579+
f,
1580+
"\"attempt to compute `{{}} * {{}}` which would overflow\", {:?}, {:?}",
1581+
l, r
1582+
),
1583+
Overflow(BinOp::Div, l, r) => write!(
1584+
f,
1585+
"\"attempt to compute `{{}} / {{}}` which would overflow\", {:?}, {:?}",
1586+
l, r
1587+
),
1588+
Overflow(BinOp::Rem, l, r) => write!(
1589+
f,
1590+
"\"attempt to compute the remainder of `{{}} % {{}}` which would overflow\", {:?}, {:?}",
1591+
l, r
1592+
),
1593+
Overflow(BinOp::Shr, _, r) => {
1594+
write!(f, "\"attempt to shift right by {{}} which would overflow\", {:?}", r)
1595+
}
1596+
Overflow(BinOp::Shl, _, r) => {
1597+
write!(f, "\"attempt to shift left by {{}} which would overflow\", {:?}", r)
1598+
}
15551599
_ => write!(f, "\"{}\"", self.description()),
15561600
}
15571601
}
@@ -1564,6 +1608,34 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
15641608
BoundsCheck { ref len, ref index } => {
15651609
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index)
15661610
}
1611+
OverflowNeg(op) => write!(f, "attempt to negate {:#?} which would overflow", op),
1612+
DivisionByZero(op) => write!(f, "attempt to divide {:#?} by zero", op),
1613+
RemainderByZero(op) => {
1614+
write!(f, "attempt to calculate the remainder of {:#?} with a divisor of zero", op)
1615+
}
1616+
Overflow(BinOp::Add, l, r) => {
1617+
write!(f, "attempt to compute `{:#?} + {:#?}` which would overflow", l, r)
1618+
}
1619+
Overflow(BinOp::Sub, l, r) => {
1620+
write!(f, "attempt to compute `{:#?} - {:#?}` which would overflow", l, r)
1621+
}
1622+
Overflow(BinOp::Mul, l, r) => {
1623+
write!(f, "attempt to compute `{:#?} * {:#?}` which would overflow", l, r)
1624+
}
1625+
Overflow(BinOp::Div, l, r) => {
1626+
write!(f, "attempt to compute `{:#?} / {:#?}` which would overflow", l, r)
1627+
}
1628+
Overflow(BinOp::Rem, l, r) => write!(
1629+
f,
1630+
"attempt to compute the remainder of `{:#?} % {:#?}` which would overflow",
1631+
l, r
1632+
),
1633+
Overflow(BinOp::Shr, _, r) => {
1634+
write!(f, "attempt to shift right by {:#?} which would overflow", r)
1635+
}
1636+
Overflow(BinOp::Shl, _, r) => {
1637+
write!(f, "attempt to shift left by {:#?} which would overflow", r)
1638+
}
15671639
_ => write!(f, "{}", self.description()),
15681640
}
15691641
}

src/librustc_middle/mir/type_foldable.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,14 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
5858
Assert { ref cond, expected, ref msg, target, cleanup } => {
5959
use AssertKind::*;
6060
let msg = match msg {
61-
BoundsCheck { ref len, ref index } => {
61+
BoundsCheck { len, index } => {
6262
BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
6363
}
64-
Overflow(_)
65-
| OverflowNeg
66-
| DivisionByZero
67-
| RemainderByZero
68-
| ResumedAfterReturn(_)
69-
| ResumedAfterPanic(_) => msg.clone(),
64+
Overflow(op, l, r) => Overflow(*op, l.fold_with(folder), r.fold_with(folder)),
65+
OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
66+
DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
67+
RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
68+
ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg.clone(),
7069
};
7170
Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
7271
}
@@ -117,12 +116,11 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
117116
BoundsCheck { ref len, ref index } => {
118117
len.visit_with(visitor) || index.visit_with(visitor)
119118
}
120-
Overflow(_)
121-
| OverflowNeg
122-
| DivisionByZero
123-
| RemainderByZero
124-
| ResumedAfterReturn(_)
125-
| ResumedAfterPanic(_) => false,
119+
Overflow(_, l, r) => l.visit_with(visitor) || r.visit_with(visitor),
120+
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
121+
op.visit_with(visitor)
122+
}
123+
ResumedAfterReturn(_) | ResumedAfterPanic(_) => false,
126124
}
127125
} else {
128126
false

src/librustc_middle/mir/visit.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,13 @@ macro_rules! make_mir_visitor {
571571
self.visit_operand(len, location);
572572
self.visit_operand(index, location);
573573
}
574-
Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
574+
Overflow(_, l, r) => {
575+
self.visit_operand(l, location);
576+
self.visit_operand(r, location);
577+
}
578+
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
579+
self.visit_operand(op, location);
580+
}
575581
ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
576582
// Nothing to visit
577583
}

src/librustc_middle/ty/consts.rs

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use crate::mir::interpret::truncate;
2+
use rustc_target::abi::Size;
3+
4+
#[derive(Copy, Clone)]
5+
/// A type for representing any integer. Only used for printing.
6+
// FIXME: Use this for the integer-tree representation needed for type level ints and
7+
// const generics?
8+
pub struct ConstInt {
9+
/// Number of bytes of the integer. Only 1, 2, 4, 8, 16 are legal values.
10+
size: u8,
11+
/// Whether the value is of a signed integer type.
12+
signed: bool,
13+
/// Whether the value is a `usize` or `isize` type.
14+
is_ptr_sized_integral: bool,
15+
/// Raw memory of the integer. All bytes beyond the `size` are unused and must be zero.
16+
raw: u128,
17+
}
18+
19+
impl ConstInt {
20+
pub fn new(raw: u128, size: Size, signed: bool, is_ptr_sized_integral: bool) -> Self {
21+
assert!(raw <= truncate(u128::MAX, size));
22+
Self { raw, size: size.bytes() as u8, signed, is_ptr_sized_integral }
23+
}
24+
}
25+
26+
impl std::fmt::Debug for ConstInt {
27+
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28+
let Self { size, signed, raw, is_ptr_sized_integral } = *self;
29+
if signed {
30+
let bit_size = size * 8;
31+
let min = 1u128 << (bit_size - 1);
32+
let max = min - 1;
33+
if raw == min {
34+
match (size, is_ptr_sized_integral) {
35+
(_, true) => write!(fmt, "isize::MIN"),
36+
(1, _) => write!(fmt, "i8::MIN"),
37+
(2, _) => write!(fmt, "i16::MIN"),
38+
(4, _) => write!(fmt, "i32::MIN"),
39+
(8, _) => write!(fmt, "i64::MIN"),
40+
(16, _) => write!(fmt, "i128::MIN"),
41+
_ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
42+
}
43+
} else if raw == max {
44+
match (size, is_ptr_sized_integral) {
45+
(_, true) => write!(fmt, "isize::MAX"),
46+
(1, _) => write!(fmt, "i8::MAX"),
47+
(2, _) => write!(fmt, "i16::MAX"),
48+
(4, _) => write!(fmt, "i32::MAX"),
49+
(8, _) => write!(fmt, "i64::MAX"),
50+
(16, _) => write!(fmt, "i128::MAX"),
51+
_ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
52+
}
53+
} else {
54+
match size {
55+
1 => write!(fmt, "{}", raw as i8)?,
56+
2 => write!(fmt, "{}", raw as i16)?,
57+
4 => write!(fmt, "{}", raw as i32)?,
58+
8 => write!(fmt, "{}", raw as i64)?,
59+
16 => write!(fmt, "{}", raw as i128)?,
60+
_ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
61+
}
62+
if fmt.alternate() {
63+
match (size, is_ptr_sized_integral) {
64+
(_, true) => write!(fmt, "_isize")?,
65+
(1, _) => write!(fmt, "_i8")?,
66+
(2, _) => write!(fmt, "_i16")?,
67+
(4, _) => write!(fmt, "_i32")?,
68+
(8, _) => write!(fmt, "_i64")?,
69+
(16, _) => write!(fmt, "_i128")?,
70+
_ => bug!(),
71+
}
72+
}
73+
Ok(())
74+
}
75+
} else {
76+
let max = truncate(u128::MAX, Size::from_bytes(size));
77+
if raw == max {
78+
match (size, is_ptr_sized_integral) {
79+
(_, true) => write!(fmt, "usize::MAX"),
80+
(1, _) => write!(fmt, "u8::MAX"),
81+
(2, _) => write!(fmt, "u16::MAX"),
82+
(4, _) => write!(fmt, "u32::MAX"),
83+
(8, _) => write!(fmt, "u64::MAX"),
84+
(16, _) => write!(fmt, "u128::MAX"),
85+
_ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
86+
}
87+
} else {
88+
match size {
89+
1 => write!(fmt, "{}", raw as u8)?,
90+
2 => write!(fmt, "{}", raw as u16)?,
91+
4 => write!(fmt, "{}", raw as u32)?,
92+
8 => write!(fmt, "{}", raw as u64)?,
93+
16 => write!(fmt, "{}", raw as u128)?,
94+
_ => bug!("ConstInt 0x{:x} with size = {} and signed = {}", raw, size, signed),
95+
}
96+
if fmt.alternate() {
97+
match (size, is_ptr_sized_integral) {
98+
(_, true) => write!(fmt, "_usize")?,
99+
(1, _) => write!(fmt, "_u8")?,
100+
(2, _) => write!(fmt, "_u16")?,
101+
(4, _) => write!(fmt, "_u32")?,
102+
(8, _) => write!(fmt, "_u64")?,
103+
(16, _) => write!(fmt, "_u128")?,
104+
_ => bug!(),
105+
}
106+
}
107+
Ok(())
108+
}
109+
}
110+
}
111+
}

src/librustc_middle/ty/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ pub use self::trait_def::TraitDef;
8484

8585
pub use self::query::queries;
8686

87+
pub use self::consts::ConstInt;
88+
8789
pub mod adjustment;
8890
pub mod binding;
8991
pub mod cast;
@@ -108,6 +110,7 @@ pub mod trait_def;
108110
pub mod util;
109111
pub mod walk;
110112

113+
mod consts;
111114
mod context;
112115
mod diagnostics;
113116
mod instance;

src/librustc_middle/ty/print/pretty.rs

+7-30
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
2-
use crate::mir::interpret::{
3-
sign_extend, truncate, AllocId, ConstValue, GlobalAlloc, Pointer, Scalar,
4-
};
2+
use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar};
53
use crate::ty::layout::IntegerExt;
64
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
7-
use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
5+
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
86
use rustc_apfloat::ieee::{Double, Single};
97
use rustc_apfloat::Float;
108
use rustc_ast::ast;
@@ -981,35 +979,14 @@ pub trait PrettyPrinter<'tcx>:
981979
}
982980
// Int
983981
(Scalar::Raw { data, .. }, ty::Uint(ui)) => {
984-
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
985-
let max = truncate(u128::MAX, bit_size);
986-
987-
let ui_str = ui.name_str();
988-
if data == max {
989-
p!(write("{}::MAX", ui_str))
990-
} else {
991-
if print_ty { p!(write("{}{}", data, ui_str)) } else { p!(write("{}", data)) }
992-
};
982+
let size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
983+
let int = ConstInt::new(data, size, false, ty.is_ptr_sized_integral());
984+
if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
993985
}
994986
(Scalar::Raw { data, .. }, ty::Int(i)) => {
995987
let size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size();
996-
let bit_size = size.bits() as u128;
997-
let min = 1u128 << (bit_size - 1);
998-
let max = min - 1;
999-
1000-
let i_str = i.name_str();
1001-
match data {
1002-
d if d == min => p!(write("{}::MIN", i_str)),
1003-
d if d == max => p!(write("{}::MAX", i_str)),
1004-
_ => {
1005-
let data = sign_extend(data, size) as i128;
1006-
if print_ty {
1007-
p!(write("{}{}", data, i_str))
1008-
} else {
1009-
p!(write("{}", data))
1010-
}
1011-
}
1012-
}
988+
let int = ConstInt::new(data, size, true, ty.is_ptr_sized_integral());
989+
if print_ty { p!(write("{:#?}", int)) } else { p!(write("{:?}", int)) }
1013990
}
1014991
// Char
1015992
(Scalar::Raw { data, .. }, ty::Char) if char::from_u32(data as u32).is_some() => {

0 commit comments

Comments
 (0)