diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index f232d039f66..65649c82da6 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1087,13 +1087,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, stability::check_unused_or_stable_features(tcx) }); - - time(time_passes, - "MIR linting", - || for def_id in tcx.body_owners() { - mir::check_const_err::check(tcx, def_id) - }); - time(time_passes, "lint checking", || lint::check_crate(tcx)); return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); diff --git a/src/librustc_mir/check_const_err.rs b/src/librustc_mir/check_const_err.rs deleted file mode 100644 index 9827dd58cd6..00000000000 --- a/src/librustc_mir/check_const_err.rs +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Lints statically known runtime failures - -use rustc::mir::*; -use rustc::hir; -use rustc::hir::map::Node; -use rustc::mir::visit::Visitor; -use rustc::mir::interpret::{Value, PrimVal, GlobalId}; -use rustc::middle::const_val::{ConstVal, ConstEvalErr, ErrKind}; -use rustc::hir::def::Def; -use rustc::traits; -use interpret::eval_body_with_mir; -use rustc::ty::{TyCtxt, ParamEnv}; -use rustc::ty::Instance; -use rustc::ty::layout::LayoutOf; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; - -fn is_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - if let Some(node) = tcx.hir.get_if_local(def_id) { - match node { - Node::NodeItem(&hir::Item { - node: hir::ItemConst(..), .. - }) => true, - _ => false - } - } else { - match tcx.describe_def(def_id) { - Some(Def::Const(_)) => true, - _ => false - } - } -} - -pub fn check<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { - let mir = &tcx.optimized_mir(def_id); - let substs = Substs::identity_for_item(tcx, def_id); - let instance = Instance::new(def_id, substs); - let param_env = tcx.param_env(def_id); - - if is_const(tcx, def_id) { - let cid = GlobalId { - instance, - promoted: None, - }; - eval_body_with_mir(tcx, cid, mir, param_env); - } - - ConstErrVisitor { - tcx, - mir, - }.visit_mir(mir); - let outer_def_id = if tcx.is_closure(def_id) { - tcx.closure_base_def_id(def_id) - } else { - def_id - }; - let generics = tcx.generics_of(outer_def_id); - // FIXME: miri should be able to eval stuff that doesn't need info - // from the generics - if generics.parent_types as usize + generics.types.len() > 0 { - return; - } - for i in 0.. mir.promoted.len() { - use rustc_data_structures::indexed_vec::Idx; - let cid = GlobalId { - instance, - promoted: Some(Promoted::new(i)), - }; - eval_body_with_mir(tcx, cid, mir, param_env); - } -} - -struct ConstErrVisitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mir: &'a Mir<'tcx>, -} - -impl<'a, 'tcx> ConstErrVisitor<'a, 'tcx> { - fn eval_op(&self, op: &Operand<'tcx>) -> Option { - let op = match *op { - Operand::Constant(ref c) => c, - _ => return None, - }; - match op.literal { - Literal::Value { value } => match value.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => Some(b), - _ => return None, - }, - _ => None, - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for ConstErrVisitor<'a, 'tcx> { - fn visit_terminator(&mut self, - block: BasicBlock, - terminator: &Terminator<'tcx>, - location: Location) { - self.super_terminator(block, terminator, location); - match terminator.kind { - TerminatorKind::Assert { ref cond, expected, ref msg, .. } => { - let cond = match self.eval_op(cond) { - Some(val) => val, - None => return, - }; - if (cond == 1) == expected { - return; - } - assert!(cond <= 1); - // If we know we always panic, and the error message - // is also constant, then we can produce a warning. - - let kind = match *msg { - AssertMessage::BoundsCheck { ref len, ref index } => { - let len = match self.eval_op(len) { - Some(val) => val, - None => return, - }; - let index = match self.eval_op(index) { - Some(val) => val, - None => return, - }; - ErrKind::IndexOutOfBounds { - len: len as u64, - index: index as u64 - } - } - AssertMessage::Math(ref err) => ErrKind::Math(err.clone()), - AssertMessage::GeneratorResumedAfterReturn | - // FIXME(oli-obk): can we report a const_err warning here? - AssertMessage::GeneratorResumedAfterPanic => return, - }; - let span = terminator.source_info.span; - let msg = ConstEvalErr{ span, kind }; - let scope_info = match self.mir.visibility_scope_info { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return, - }; - let node_id = scope_info[terminator.source_info.scope].lint_root; - self.tcx.lint_node(::rustc::lint::builtin::CONST_ERR, - node_id, - msg.span, - &msg.description().into_oneline().into_owned()); - }, - _ => {}, - } - } - fn visit_rvalue(&mut self, - rvalue: &Rvalue<'tcx>, - location: Location) { - self.super_rvalue(rvalue, location); - use rustc::mir::BinOp; - match *rvalue { - Rvalue::BinaryOp(BinOp::Shr, ref lop, ref rop) | - Rvalue::BinaryOp(BinOp::Shl, ref lop, ref rop) => { - let val = match self.eval_op(rop) { - Some(val) => val, - None => return, - }; - let ty = lop.ty(self.mir, self.tcx); - let param_env = ParamEnv::empty(traits::Reveal::All); - let bits = (self.tcx, param_env).layout_of(ty).unwrap().size.bits(); - if val >= bits as u128 { - let data = &self.mir[location.block]; - let stmt_idx = location.statement_index; - let source_info = if stmt_idx < data.statements.len() { - data.statements[stmt_idx].source_info - } else { - data.terminator().source_info - }; - let span = source_info.span; - let scope_info = match self.mir.visibility_scope_info { - ClearCrossCrate::Set(ref data) => data, - ClearCrossCrate::Clear => return, - }; - let node_id = scope_info[source_info.scope].lint_root; - self.tcx.lint_node( - ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, - node_id, - span, - "bitshift exceeds the type's number of bits"); - } - } - _ => {} - } - } -} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f6b38dcc001..c31e95fd826 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -71,7 +71,6 @@ pub mod transform; pub mod util; pub mod interpret; pub mod monomorphize; -pub mod check_const_err; pub use hair::pattern::check_crate as matchck_crate; use rustc::ty::maps::Providers; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 3b37e755af3..35fce184beb 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -212,8 +212,30 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { let instance = Instance::new(self.source.def_id, substs); let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap(); - let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?; + let param_env = ParamEnv::empty(traits::Reveal::All); + let bits = (self.tcx, param_env).layout_of(left.ty).unwrap().size.bits(); + if r >= bits as u128 { + let data = &self.mir[location.block]; + let stmt_idx = location.statement_index; + let source_info = if stmt_idx < data.statements.len() { + data.statements[stmt_idx].source_info + } else { + data.terminator().source_info + }; + let span = source_info.span; + let scope_info = match self.mir.visibility_scope_info { + ClearCrossCrate::Set(ref data) => data, + ClearCrossCrate::Clear => return, + }; + let node_id = scope_info[source_info.scope].lint_root; + self.tcx.lint_node( + ::rustc::lint::builtin::EXCEEDING_BITSHIFTS, + node_id, + span, + "bitshift exceeds the type's number of bits"); + } + let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); match ecx.binary_op(op, l, left.1, r, right.1) { Ok((val, overflow)) => {