diff options
Diffstat (limited to 'src/librustc_mir')
| -rw-r--r-- | src/librustc_mir/Cargo.toml | 2 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/mod.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/constraint_generation.rs | 137 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/invalidation.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/type_check/mod.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/build/expr/as_place.rs | 6 | ||||
| -rw-r--r-- | src/librustc_mir/build/expr/as_rvalue.rs | 13 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/terminator.rs | 35 | ||||
| -rw-r--r-- | src/librustc_mir/lib.rs | 8 | ||||
| -rw-r--r-- | src/librustc_mir/transform/const_prop.rs | 20 | ||||
| -rw-r--r-- | src/librustc_mir/transform/generator.rs | 2 |
11 files changed, 168 insertions, 67 deletions
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 2adbd03b24f..21008c73728 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -20,7 +20,7 @@ rustc = { path = "../librustc" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } -serialize = { path = "../libserialize" } +rustc_serialize = { path = "../libserialize", package = "serialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } byteorder = { version = "1.1", features = ["i128"] } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 8d27a32a285..92285c47db4 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -733,8 +733,8 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx cleanup: _, } => { self.consume_operand(loc, (cond, span), flow_state); - use rustc::mir::interpret::{InterpError::Panic, PanicMessage}; - if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg { + use rustc::mir::interpret::PanicMessage; + if let PanicMessage::BoundsCheck { ref len, ref index } = *msg { self.consume_operand(loc, (len, span), flow_state); self.consume_operand(loc, (index, span), flow_state); } diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 055568f0a27..95c3299693b 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -3,12 +3,15 @@ use crate::borrow_check::location::LocationTable; use crate::borrow_check::nll::ToRegionVid; use crate::borrow_check::nll::facts::AllFacts; use crate::borrow_check::nll::region_infer::values::LivenessValues; +use crate::borrow_check::places_conflict; use rustc::infer::InferCtxt; use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; -use rustc::mir::{BasicBlock, BasicBlockData, Location, Body, Place, PlaceBase, Rvalue}; -use rustc::mir::{SourceInfo, Statement, Terminator}; -use rustc::mir::UserTypeProjection; +use rustc::mir::{ + BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection, + ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, + UserTypeProjection, +}; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty}; use rustc::ty::subst::SubstsRef; @@ -27,6 +30,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>( liveness_constraints, location_table, all_facts, + body, }; for (bb, data) in body.basic_blocks().iter_enumerated() { @@ -41,6 +45,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> { location_table: &'cg LocationTable, liveness_constraints: &'cg mut LivenessValues<RegionVid>, borrow_set: &'cg BorrowSet<'tcx>, + body: &'cg Body<'tcx>, } impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { @@ -114,6 +119,17 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { self.location_table .start_index(location.successor_within_block()), )); + + // If there are borrows on this now dead local, we need to record them as `killed`. + if let StatementKind::StorageDead(ref local) = statement.kind { + record_killed_borrows_for_local( + all_facts, + self.borrow_set, + self.location_table, + local, + location, + ); + } } self.super_statement(statement, location); @@ -127,20 +143,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { ) { // When we see `X = ...`, then kill borrows of // `(*X).foo` and so forth. - if let Some(all_facts) = self.all_facts { - if let Place { - base: PlaceBase::Local(temp), - projection: None, - } = place { - if let Some(borrow_indices) = self.borrow_set.local_map.get(temp) { - all_facts.killed.reserve(borrow_indices.len()); - for &borrow_index in borrow_indices { - let location_index = self.location_table.mid_index(location); - all_facts.killed.push((borrow_index, location_index)); - } - } - } - } + self.record_killed_borrows_for_place(place, location); self.super_assign(place, rvalue, location); } @@ -167,6 +170,14 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> { } } + // A `Call` terminator's return value can be a local which has borrows, + // so we need to record those as `killed` as well. + if let TerminatorKind::Call { ref destination, .. } = terminator.kind { + if let Some((place, _)) = destination { + self.record_killed_borrows_for_place(place, location); + } + } + self.super_terminator(terminator, location); } @@ -201,4 +212,96 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> { self.liveness_constraints.add_element(vid, location); }); } + + /// When recording facts for Polonius, records the borrows on the specified place + /// as `killed`. For example, when assigning to a local, or on a call's return destination. + fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Location) { + if let Some(all_facts) = self.all_facts { + // Depending on the `Place` we're killing: + // - if it's a local, or a single deref of a local, + // we kill all the borrows on the local. + // - if it's a deeper projection, we have to filter which + // of the borrows are killed: the ones whose `borrowed_place` + // conflicts with the `place`. + match place { + Place { + base: PlaceBase::Local(local), + projection: None, + } | + Place { + base: PlaceBase::Local(local), + projection: Some(box Projection { + base: None, + elem: ProjectionElem::Deref, + }), + } => { + debug!( + "Recording `killed` facts for borrows of local={:?} at location={:?}", + local, location + ); + + record_killed_borrows_for_local( + all_facts, + self.borrow_set, + self.location_table, + local, + location, + ); + } + + Place { + base: PlaceBase::Static(_), + .. + } => { + // Ignore kills of static or static mut variables. + } + + Place { + base: PlaceBase::Local(local), + projection: Some(_), + } => { + // Kill conflicting borrows of the innermost local. + debug!( + "Recording `killed` facts for borrows of \ + innermost projected local={:?} at location={:?}", + local, location + ); + + if let Some(borrow_indices) = self.borrow_set.local_map.get(local) { + for &borrow_index in borrow_indices { + let places_conflict = places_conflict::places_conflict( + self.infcx.tcx, + self.body, + &self.borrow_set.borrows[borrow_index].borrowed_place, + place, + places_conflict::PlaceConflictBias::NoOverlap, + ); + + if places_conflict { + let location_index = self.location_table.mid_index(location); + all_facts.killed.push((borrow_index, location_index)); + } + } + } + } + } + } + } +} + +/// When recording facts for Polonius, records the borrows on the specified local as `killed`. +fn record_killed_borrows_for_local( + all_facts: &mut AllFacts, + borrow_set: &BorrowSet<'_>, + location_table: &LocationTable, + local: &Local, + location: Location, +) { + if let Some(borrow_indices) = borrow_set.local_map.get(local) { + all_facts.killed.reserve(borrow_indices.len()); + for &borrow_index in borrow_indices { + let location_index = location_table.mid_index(location); + all_facts.killed.push((borrow_index, location_index)); + } + } } diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 90df0c91c72..aa9e68bd7de 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -207,8 +207,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { cleanup: _, } => { self.consume_operand(location, cond); - use rustc::mir::interpret::{InterpError::Panic, PanicMessage::BoundsCheck}; - if let Panic(BoundsCheck { ref len, ref index }) = *msg { + use rustc::mir::interpret::PanicMessage; + if let PanicMessage::BoundsCheck { ref len, ref index } = *msg { self.consume_operand(location, len); self.consume_operand(location, index); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 6ce2f968ed7..59a8c8d34d2 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -28,7 +28,7 @@ use rustc::infer::canonical::QueryRegionConstraints; use rustc::infer::outlives::env::RegionBoundPairs; use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::mir::interpret::{InterpError::Panic, ConstValue, PanicMessage}; +use rustc::mir::interpret::{ConstValue, PanicMessage}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor, NonMutatingUseContext}; use rustc::mir::*; @@ -1606,7 +1606,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); } - if let Panic(PanicMessage::BoundsCheck { ref len, ref index }) = *msg { + if let PanicMessage::BoundsCheck { ref len, ref index } = *msg { if len.ty(body, tcx) != tcx.types.usize { span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 42d08a728e0..7a428a2ec9f 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -4,7 +4,7 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; -use rustc::mir::interpret::{InterpError::Panic, PanicMessage::BoundsCheck}; +use rustc::mir::interpret::{PanicMessage::BoundsCheck}; use rustc::mir::*; use rustc::ty::{CanonicalUserTypeAnnotation, Variance}; @@ -105,10 +105,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ), ); - let msg = Panic(BoundsCheck { + let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(idx)), - }); + }; let success = this.assert(block, Operand::Move(lt), true, msg, expr_span); success.and(slice.index(idx)) } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 8790ebc4169..92daf06e6f8 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -7,7 +7,7 @@ use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::middle::region; -use rustc::mir::interpret::{InterpError::Panic, PanicMessage}; +use rustc::mir::interpret::PanicMessage; use rustc::mir::*; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts}; use syntax_pos::Span; @@ -101,7 +101,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Operand::Move(is_min), false, - Panic(PanicMessage::OverflowNeg), + PanicMessage::OverflowNeg, expr_span, ); } @@ -401,7 +401,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val = result_value.clone().field(val_fld, ty); let of = result_value.field(of_fld, bool_ty); - let err = Panic(PanicMessage::Overflow(op)); + let err = PanicMessage::Overflow(op); block = self.assert(block, Operand::Move(of), false, err, span); @@ -411,11 +411,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Checking division and remainder is more complex, since we 1. always check // and 2. there are two possible failure cases, divide-by-zero and overflow. - let (zero_err, overflow_err) = if op == BinOp::Div { - (Panic(PanicMessage::DivisionByZero), Panic(PanicMessage::Overflow(op))) + let zero_err = if op == BinOp::Div { + PanicMessage::DivisionByZero } else { - (Panic(PanicMessage::RemainderByZero), Panic(PanicMessage::Overflow(op))) + PanicMessage::RemainderByZero }; + let overflow_err = PanicMessage::Overflow(op); // Check for / 0 let is_zero = self.temp(bool_ty, span); diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index a85b77c7b81..27bd0f88896 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,7 +7,7 @@ use syntax::source_map::Span; use rustc_target::spec::abi::Abi; use super::{ - InterpResult, PointerArithmetic, InterpError, Scalar, PanicMessage, + InterpResult, PointerArithmetic, InterpError, Scalar, InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, }; @@ -135,28 +135,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.goto_block(Some(target))?; } else { // Compute error message - use rustc::mir::interpret::InterpError::*; - return match *msg { - Panic(PanicMessage::BoundsCheck { ref len, ref index }) => { + use rustc::mir::interpret::PanicMessage::*; + return match msg { + BoundsCheck { ref len, ref index } => { let len = self.read_immediate(self.eval_operand(len, None)?) .expect("can't eval len").to_scalar()? .to_bits(self.memory().pointer_size())? as u64; let index = self.read_immediate(self.eval_operand(index, None)?) .expect("can't eval index").to_scalar()? .to_bits(self.memory().pointer_size())? as u64; - err!(Panic(PanicMessage::BoundsCheck { len, index })) + err!(Panic(BoundsCheck { len, index })) } - Panic(PanicMessage::Overflow(op)) => - Err(Panic(PanicMessage::Overflow(op)).into()), - Panic(PanicMessage::OverflowNeg) => - Err(Panic(PanicMessage::OverflowNeg).into()), - Panic(PanicMessage::DivisionByZero) => - Err(Panic(PanicMessage::DivisionByZero).into()), - Panic(PanicMessage::RemainderByZero) => - Err(Panic(PanicMessage::RemainderByZero).into()), - GeneratorResumedAfterReturn | - GeneratorResumedAfterPanic => unimplemented!(), - _ => bug!(), + Overflow(op) => + err!(Panic(Overflow(*op))), + OverflowNeg => + err!(Panic(OverflowNeg)), + DivisionByZero => + err!(Panic(DivisionByZero)), + RemainderByZero => + err!(Panic(RemainderByZero)), + GeneratorResumedAfterReturn => + err!(Panic(GeneratorResumedAfterReturn)), + GeneratorResumedAfterPanic => + err!(Panic(GeneratorResumedAfterPanic)), + Panic { .. } => + bug!("`Panic` variant cannot occur in MIR"), }; } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f5e4661afa6..964f04d79b9 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -30,13 +30,9 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![deny(unused_lifetimes)] #[macro_use] extern crate log; -#[macro_use] -extern crate rustc; +#[macro_use] extern crate rustc; #[macro_use] extern crate rustc_data_structures; -#[allow(unused_extern_crates)] -extern crate serialize as rustc_serialize; // used by deriving -#[macro_use] -extern crate syntax; +#[macro_use] extern crate syntax; mod error_codes; diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 37fcd744a38..7a2d78b2e98 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -13,7 +13,7 @@ use rustc::mir::{ use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, }; -use rustc::mir::interpret::{InterpError::Panic, Scalar, GlobalId, InterpResult, PanicMessage}; +use rustc::mir::interpret::{Scalar, GlobalId, InterpResult, InterpError, PanicMessage}; use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use syntax_pos::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; @@ -314,8 +314,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | HeapAllocNonPowerOfTwoAlignment(_) | Unreachable | ReadFromReturnPointer - | GeneratorResumedAfterReturn - | GeneratorResumedAfterPanic | ReferencedConstant | InfiniteLoop => { @@ -595,7 +593,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ) } else { if overflow { - let err = Panic(PanicMessage::Overflow(op)).into(); + let err = InterpError::Panic(PanicMessage::Overflow(op)).into(); let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); return None; } @@ -809,7 +807,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { self.super_terminator(terminator, location); let source_info = terminator.source_info; match &mut terminator.kind { - TerminatorKind::Assert { expected, msg, ref mut cond, .. } => { + TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => { if let Some(value) = self.eval_operand(&cond, source_info) { trace!("assertion on {:?} should be {:?}", value, expected); let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected)); @@ -831,13 +829,13 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { .hir() .as_local_hir_id(self.source.def_id()) .expect("some part of a failing const eval must be local"); - use rustc::mir::interpret::InterpError::*; let msg = match msg { - Panic(PanicMessage::Overflow(_)) | - Panic(PanicMessage::OverflowNeg) | - Panic(PanicMessage::DivisionByZero) | - Panic(PanicMessage::RemainderByZero) => msg.description().to_owned(), - Panic(PanicMessage::BoundsCheck { ref len, ref index }) => { + PanicMessage::Overflow(_) | + PanicMessage::OverflowNeg | + PanicMessage::DivisionByZero | + PanicMessage::RemainderByZero => + msg.description().to_owned(), + PanicMessage::BoundsCheck { ref len, ref index } => { let len = self .eval_operand(len, source_info) .expect("len must be const"); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index af412edbdc2..5461a2e470c 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -1016,7 +1016,7 @@ fn create_generator_resume_function<'tcx>( let mut cases = create_cases(body, &transform, |point| Some(point.resume)); - use rustc::mir::interpret::InterpError::{ + use rustc::mir::interpret::PanicMessage::{ GeneratorResumedAfterPanic, GeneratorResumedAfterReturn, }; |
