about summary refs log tree commit diff
path: root/src/librustc_mir
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc_mir')
-rw-r--r--src/librustc_mir/Cargo.toml2
-rw-r--r--src/librustc_mir/borrow_check/mod.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs137
-rw-r--r--src/librustc_mir/borrow_check/nll/invalidation.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs4
-rw-r--r--src/librustc_mir/build/expr/as_place.rs6
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs13
-rw-r--r--src/librustc_mir/interpret/terminator.rs35
-rw-r--r--src/librustc_mir/lib.rs8
-rw-r--r--src/librustc_mir/transform/const_prop.rs20
-rw-r--r--src/librustc_mir/transform/generator.rs2
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,
     };