Skip to content

Commit b5ace9a

Browse files
committed
Unify the const folding errors
before they differed depending on whether optimizations were on or not
1 parent edc5f73 commit b5ace9a

24 files changed

+278
-155
lines changed

src/librustc_mir/transform/const_prop.rs

Lines changed: 111 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
//! assertion failures
1313
1414

15-
15+
use rustc::hir::def::Def;
1616
use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local};
1717
use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
18-
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp};
18+
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem};
1919
use rustc::mir::visit::{Visitor, PlaceContext};
2020
use rustc::middle::const_val::ConstVal;
2121
use rustc::ty::{TyCtxt, self, Instance};
@@ -26,6 +26,10 @@ use syntax::codemap::Span;
2626
use rustc::ty::subst::Substs;
2727
use rustc_data_structures::indexed_vec::IndexVec;
2828
use rustc::ty::ParamEnv;
29+
use rustc::ty::layout::{
30+
LayoutOf, TyLayout, LayoutError,
31+
HasTyCtxt, TargetDataLayout, HasDataLayout,
32+
};
2933

3034
pub struct ConstProp;
3135

@@ -34,6 +38,15 @@ impl MirPass for ConstProp {
3438
tcx: TyCtxt<'a, 'tcx, 'tcx>,
3539
source: MirSource,
3640
mir: &mut Mir<'tcx>) {
41+
// will be evaluated by miri and produce its errors there
42+
if source.promoted.is_some() {
43+
return;
44+
}
45+
match tcx.describe_def(source.def_id) {
46+
// skip statics because they'll be evaluated by miri anyway
47+
Some(Def::Static(..)) => return,
48+
_ => {},
49+
}
3750
trace!("ConstProp starting for {:?}", source.def_id);
3851

3952
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
@@ -59,6 +72,28 @@ struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
5972
param_env: ParamEnv<'tcx>,
6073
}
6174

75+
impl<'a, 'b, 'tcx> LayoutOf<ty::Ty<'tcx>> for &'a ConstPropagator<'a, 'b, 'tcx> {
76+
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
77+
78+
fn layout_of(self, ty: ty::Ty<'tcx>) -> Self::TyLayout {
79+
self.tcx.layout_of(self.param_env.and(ty))
80+
}
81+
}
82+
83+
impl<'a, 'b, 'tcx> HasDataLayout for &'a ConstPropagator<'a, 'b, 'tcx> {
84+
#[inline]
85+
fn data_layout(&self) -> &TargetDataLayout {
86+
&self.tcx.data_layout
87+
}
88+
}
89+
90+
impl<'a, 'b, 'tcx> HasTyCtxt<'tcx> for &'a ConstPropagator<'a, 'b, 'tcx> {
91+
#[inline]
92+
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'tcx, 'tcx> {
93+
self.tcx
94+
}
95+
}
96+
6297
impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
6398
fn new(
6499
mir: &'b Mir<'tcx>,
@@ -134,15 +169,43 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
134169
}
135170
}
136171

172+
fn eval_place(&mut self, place: &Place<'tcx>) -> Option<Const<'tcx>> {
173+
match *place {
174+
Place::Local(loc) => self.places[loc].clone(),
175+
Place::Projection(ref proj) => match proj.elem {
176+
ProjectionElem::Field(field, _) => {
177+
trace!("field proj on {:?}", proj.base);
178+
let (base, ty, span) = self.eval_place(&proj.base)?;
179+
match base {
180+
Value::ByValPair(a, b) => {
181+
trace!("by val pair: {:?}, {:?}", a, b);
182+
let base_layout = self.tcx.layout_of(self.param_env.and(ty)).ok()?;
183+
trace!("layout computed");
184+
use rustc_data_structures::indexed_vec::Idx;
185+
let field_index = field.index();
186+
let val = if field_index == 0 {
187+
a
188+
} else {
189+
assert_eq!(field_index, 1);
190+
b
191+
};
192+
let field = base_layout.field(&*self, field_index).ok()?;
193+
trace!("projection resulted in: {:?}", val);
194+
Some((Value::ByVal(val), field.ty, span))
195+
},
196+
_ => None,
197+
}
198+
},
199+
_ => None,
200+
},
201+
_ => None,
202+
}
203+
}
204+
137205
fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option<Const<'tcx>> {
138206
match *op {
139207
Operand::Constant(ref c) => self.eval_constant(c),
140-
Operand::Move(ref place) | Operand::Copy(ref place) => match *place {
141-
Place::Local(loc) => self.places[loc].clone(),
142-
// FIXME(oli-obk): field and index projections
143-
Place::Projection(_) => None,
144-
_ => None,
145-
},
208+
Operand::Move(ref place) | Operand::Copy(ref place) => self.eval_place(place),
146209
}
147210
}
148211

@@ -235,18 +298,24 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
235298
let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
236299
if op == BinOp::Shr || op == BinOp::Shl {
237300
let param_env = self.tcx.param_env(self.source.def_id);
238-
let bits = self.tcx.layout_of(param_env.and(place_ty)).unwrap().size.bits();
301+
let left_ty = left.ty(self.mir, self.tcx);
302+
let bits = self.tcx.layout_of(param_env.and(left_ty)).unwrap().size.bits();
239303
if r.to_bytes().ok().map_or(false, |b| b >= bits as u128) {
240304
let scope_info = match self.mir.visibility_scope_info {
241305
ClearCrossCrate::Set(ref data) => data,
242306
ClearCrossCrate::Clear => return None,
243307
};
308+
let dir = if op == BinOp::Shr {
309+
"right"
310+
} else {
311+
"left"
312+
};
244313
let node_id = scope_info[source_info.scope].lint_root;
245314
self.tcx.lint_node(
246315
::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
247316
node_id,
248317
span,
249-
"bitshift exceeds the type's number of bits");
318+
&format!("attempt to shift {} with overflow", dir));
250319
return None;
251320
}
252321
}
@@ -334,6 +403,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
334403
Copy | Move |
335404
StorageDead | StorageLive |
336405
Validate |
406+
Projection(_) |
337407
Inspect => {},
338408
_ => self.can_const_prop[local] = false,
339409
}
@@ -364,6 +434,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
364434
.to_ty(self.tcx);
365435
if let Some(value) = self.const_prop(rval, place_ty, statement.source_info) {
366436
if let Place::Local(local) = *place {
437+
trace!("checking whether {:?} can be stored to {:?}", value, local);
367438
if self.can_const_prop[local] {
368439
trace!("storing {:?} to {:?}", value, local);
369440
assert!(self.places[local].is_none());
@@ -384,7 +455,22 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
384455
self.super_terminator_kind(block, kind, location);
385456
if let TerminatorKind::Assert { expected, msg, cond, .. } = kind {
386457
if let Some(value) = self.eval_operand(cond) {
458+
trace!("assertion on {:?} should be {:?}", value, expected);
387459
if Value::ByVal(PrimVal::from_bool(*expected)) != value.0 {
460+
// poison all places this operand references so that further code
461+
// doesn't use the invalid value
462+
match cond {
463+
Operand::Move(ref place) | Operand::Copy(ref place) => {
464+
let mut place = place;
465+
while let Place::Projection(ref proj) = *place {
466+
place = &proj.base;
467+
}
468+
if let Place::Local(local) = *place {
469+
self.places[local] = None;
470+
}
471+
},
472+
Operand::Constant(_) => {}
473+
}
388474
let span = self.mir[block]
389475
.terminator
390476
.as_ref()
@@ -396,21 +482,12 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
396482
.hir
397483
.as_local_node_id(self.source.def_id)
398484
.expect("some part of a failing const eval must be local");
399-
let mut lint = self.tcx.struct_span_lint_node(
400-
::rustc::lint::builtin::CONST_ERR,
401-
node_id,
402-
span,
403-
"constant evaluation error",
404-
);
405485
use rustc::mir::AssertMessage::*;
406-
match msg {
486+
let msg = match msg {
407487
// Need proper const propagator for these
408488
GeneratorResumedAfterReturn |
409-
GeneratorResumedAfterPanic => {
410-
lint.cancel();
411-
return;
412-
},
413-
Math(ref err) => lint.span_label(span, err.description()),
489+
GeneratorResumedAfterPanic => return,
490+
Math(ref err) => err.description().to_owned(),
414491
BoundsCheck { ref len, ref index } => {
415492
let len = self.eval_operand(len).expect("len must be const");
416493
let len = match len.0 {
@@ -424,17 +501,20 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
424501
Value::ByVal(PrimVal::Bytes(n)) => n,
425502
_ => bug!("const index not primitive: {:?}", index),
426503
};
427-
lint.span_label(
428-
span,
429-
format!(
430-
"index out of bounds: \
431-
the len is {} but the index is {}",
432-
len,
433-
index,
434-
),
504+
format!(
505+
"index out of bounds: \
506+
the len is {} but the index is {}",
507+
len,
508+
index,
435509
)
436510
},
437-
}.emit();
511+
};
512+
self.tcx.lint_node(
513+
::rustc::lint::builtin::CONST_ERR,
514+
node_id,
515+
span,
516+
&msg,
517+
);
438518
}
439519
}
440520
}

src/test/compile-fail/const-err-early.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111
#![deny(const_err)]
1212

1313
pub const A: i8 = -std::i8::MIN; //~ ERROR E0080
14-
//~| ERROR const_err
15-
//~| ERROR const_err
14+
//~^ ERROR attempt to negate with overflow
15+
//~| ERROR constant evaluation error
1616
pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080
17+
//~^ ERROR attempt to add with overflow
1718
pub const C: u8 = 200u8 * 4; //~ ERROR E0080
19+
//~^ ERROR attempt to multiply with overflow
1820
pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080
21+
//~^ ERROR attempt to subtract with overflow
1922
pub const E: u8 = [5u8][1];
2023
//~^ ERROR E0080
2124

src/test/compile-fail/const-err-multi.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
pub const A: i8 = -std::i8::MIN;
1414
//~^ ERROR E0080
15-
//~| ERROR const_err
16-
//~| ERROR const_err
15+
//~| ERROR attempt to negate with overflow
16+
//~| ERROR constant evaluation error
1717
pub const B: i8 = A;
1818
//~^ ERROR E0080
1919
pub const C: u8 = A as u8;

src/test/compile-fail/const-err2.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// needed because negating int::MIN will behave differently between
12+
// optimized compilation and unoptimized compilation and thus would
13+
// lead to different lints being emitted
14+
// compile-flags: -O
15+
1116
#![feature(rustc_attrs)]
1217
#![allow(exceeding_bitshifts)]
1318
#![deny(const_err)]

src/test/compile-fail/const-eval-overflow2.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,54 @@ const VALS_I8: (i8,) =
2525
(
2626
i8::MIN - 1,
2727
//~^ ERROR constant evaluation error
28+
//~| ERROR attempt to subtract with overflow
2829
);
2930

3031
const VALS_I16: (i16,) =
3132
(
3233
i16::MIN - 1,
3334
//~^ ERROR constant evaluation error
35+
//~| ERROR attempt to subtract with overflow
3436
);
3537

3638
const VALS_I32: (i32,) =
3739
(
3840
i32::MIN - 1,
3941
//~^ ERROR constant evaluation error
42+
//~| ERROR attempt to subtract with overflow
4043
);
4144

4245
const VALS_I64: (i64,) =
4346
(
4447
i64::MIN - 1,
4548
//~^ ERROR constant evaluation error
49+
//~| ERROR attempt to subtract with overflow
4650
);
4751

4852
const VALS_U8: (u8,) =
4953
(
5054
u8::MIN - 1,
5155
//~^ ERROR constant evaluation error
56+
//~| ERROR attempt to subtract with overflow
5257
);
5358

5459
const VALS_U16: (u16,) = (
5560
u16::MIN - 1,
5661
//~^ ERROR constant evaluation error
62+
//~| ERROR attempt to subtract with overflow
5763
);
5864

5965
const VALS_U32: (u32,) = (
6066
u32::MIN - 1,
6167
//~^ ERROR constant evaluation error
68+
//~| ERROR attempt to subtract with overflow
6269
);
6370

6471
const VALS_U64: (u64,) =
6572
(
6673
u64::MIN - 1,
6774
//~^ ERROR constant evaluation error
75+
//~| ERROR attempt to subtract with overflow
6876
);
6977

7078
fn main() {

src/test/compile-fail/const-eval-overflow2b.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,54 @@ const VALS_I8: (i8,) =
2525
(
2626
i8::MAX + 1,
2727
//~^ ERROR constant evaluation error
28+
//~| ERROR attempt to add with overflow
2829
);
2930

3031
const VALS_I16: (i16,) =
3132
(
3233
i16::MAX + 1,
3334
//~^ ERROR constant evaluation error
35+
//~| ERROR attempt to add with overflow
3436
);
3537

3638
const VALS_I32: (i32,) =
3739
(
3840
i32::MAX + 1,
3941
//~^ ERROR constant evaluation error
42+
//~| ERROR attempt to add with overflow
4043
);
4144

4245
const VALS_I64: (i64,) =
4346
(
4447
i64::MAX + 1,
4548
//~^ ERROR constant evaluation error
49+
//~| ERROR attempt to add with overflow
4650
);
4751

4852
const VALS_U8: (u8,) =
4953
(
5054
u8::MAX + 1,
5155
//~^ ERROR constant evaluation error
56+
//~| ERROR attempt to add with overflow
5257
);
5358

5459
const VALS_U16: (u16,) = (
5560
u16::MAX + 1,
5661
//~^ ERROR constant evaluation error
62+
//~| ERROR attempt to add with overflow
5763
);
5864

5965
const VALS_U32: (u32,) = (
6066
u32::MAX + 1,
6167
//~^ ERROR constant evaluation error
68+
//~| ERROR attempt to add with overflow
6269
);
6370

6471
const VALS_U64: (u64,) =
6572
(
6673
u64::MAX + 1,
6774
//~^ ERROR constant evaluation error
75+
//~| ERROR attempt to add with overflow
6876
);
6977

7078
fn main() {

0 commit comments

Comments
 (0)