]> git.lizzy.rs Git - rust.git/commitdiff
Merge remote-tracking branch 'origin/master' into gen
authorAlex Crichton <alex@alexcrichton.com>
Wed, 16 Aug 2017 18:33:10 +0000 (11:33 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 16 Aug 2017 18:33:10 +0000 (11:33 -0700)
1  2 
src/librustc_borrowck/borrowck/mod.rs
src/librustc_borrowck/diagnostics.rs
src/librustc_data_structures/indexed_set.rs
src/librustc_driver/driver.rs
src/librustc_mir/dataflow/mod.rs
src/librustc_mir/dataflow/move_paths/builder.rs
src/librustc_mir/transform/mod.rs
src/librustc_mir/util/mod.rs

index c1c35be540cab6bd10d816c4a66f1f6ca347995d,8c79534d209ef8549dffb4c120cc6fc8e6785ad8..80ca16d23f52209c3a0a58cc3dfa88a4a2b7cfcf
@@@ -36,7 -36,9 +36,9 @@@ use rustc::middle::region::{self, Regio
  use rustc::middle::free_region::RegionRelations;
  use rustc::ty::{self, TyCtxt};
  use rustc::ty::maps::Providers;
 -
 +use rustc::util::nodemap::FxHashMap;
+ use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
  use std::fmt;
  use std::rc::Rc;
  use std::hash::{Hash, Hasher};
@@@ -98,8 -100,9 +100,8 @@@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, '
      let body_id = tcx.hir.body_owned_by(owner_id);
      let tables = tcx.typeck_tables_of(owner_def_id);
      let region_maps = tcx.region_maps(owner_def_id);
 -    let bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
 -
 -    let body = bccx.tcx.hir.body(body_id);
 +    let body = tcx.hir.body(body_id);
 +    let bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id, body };
  
      // Eventually, borrowck will always read the MIR, but at the
      // moment we do not. So, for now, we always force MIR to be
@@@ -136,9 -139,10 +138,9 @@@ fn build_borrowck_dataflow_data<'a, 'c
  {
      // Check the body of fn items.
      let tcx = this.tcx;
 -    let body = tcx.hir.body(body_id);
      let id_range = {
          let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.hir);
 -        visitor.visit_body(body);
 +        visitor.visit_body(this.body);
          visitor.result()
      };
      let (all_loans, move_data) =
      let mut loan_dfcx =
          DataFlowContext::new(this.tcx,
                               "borrowck",
 -                             Some(body),
 +                             Some(this.body),
                               cfg,
                               LoanDataFlowOperator,
                               id_range,
                             loan.kill_scope.node_id(), loan_idx);
      }
      loan_dfcx.add_kills_from_flow_exits(cfg);
 -    loan_dfcx.propagate(cfg, body);
 +    loan_dfcx.propagate(cfg, this.body);
  
      let flowed_moves = move_data::FlowedMoveData::new(move_data,
                                                        this,
                                                        cfg,
                                                        id_range,
 -                                                      body);
 +                                                      this.body);
  
      Some(AnalysisData { all_loans,
                          loans: loan_dfcx,
@@@ -195,8 -199,7 +197,8 @@@ pub fn build_borrowck_dataflow_data_for
      let owner_def_id = tcx.hir.local_def_id(owner_id);
      let tables = tcx.typeck_tables_of(owner_def_id);
      let region_maps = tcx.region_maps(owner_def_id);
 -    let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id };
 +    let body = tcx.hir.body(body_id);
 +    let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id, body };
  
      let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
      (bccx, dataflow_data.unwrap())
@@@ -215,10 -218,27 +217,29 @@@ pub struct BorrowckCtxt<'a, 'tcx: 'a> 
      region_maps: Rc<RegionMaps>,
  
      owner_def_id: DefId,
 +
 +    body: &'tcx hir::Body,
  }
  
+ impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> {
+     fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
+                                                          sp: S,
+                                                          msg: &str,
+                                                          code: &str)
+                                                          -> DiagnosticBuilder<'a>
+     {
+         self.tcx.sess.struct_span_err_with_code(sp, msg, code)
+     }
+     fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
+                                                sp: S,
+                                                msg: &str)
+                                                -> DiagnosticBuilder<'a>
+     {
+         self.tcx.sess.struct_span_err(sp, msg)
+     }
+ }
  ///////////////////////////////////////////////////////////////////////////
  // Loans and loan paths
  
@@@ -329,7 -349,7 +350,7 @@@ fn closure_to_block(closure_id: DefInde
      let closure_id = tcx.hir.def_index_to_node_id(closure_id);
      match tcx.hir.get(closure_id) {
          hir_map::NodeExpr(expr) => match expr.node {
 -            hir::ExprClosure(.., body_id, _) => {
 +            hir::ExprClosure(.., body_id, _, _) => {
                  body_id.node_id
              }
              _ => {
@@@ -529,7 -549,9 +550,7 @@@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> 
              _ => { }
          }
  
 -        let mut db = self.bckerr_to_diag(&err);
 -        self.note_and_explain_bckerr(&mut db, err);
 -        db.emit();
 +        self.report_bckerr(&err);
      }
  
      pub fn report_use_of_moved_value(&self,
              move_data::Declared => {
                  // If this is an uninitialized variable, just emit a simple warning
                  // and return.
-                 struct_span_err!(
-                     self.tcx.sess, use_span, E0381,
-                     "{} of possibly uninitialized variable: `{}`",
-                     verb,
-                     self.loan_path_to_string(lp))
-                 .span_label(use_span, format!("use of possibly uninitialized `{}`",
-                     self.loan_path_to_string(lp)))
-                 .emit();
+                 self.cannot_act_on_uninitialized_variable(use_span,
+                                                           verb,
+                                                           &self.loan_path_to_string(lp),
+                                                           Origin::Ast)
+                     .span_label(use_span, format!("use of possibly uninitialized `{}`",
+                                                   self.loan_path_to_string(lp)))
+                     .emit();
                  return;
              }
              _ => {
  
              move_data::Captured =>
                  (match self.tcx.hir.expect_expr(the_move.id).node {
 -                    hir::ExprClosure(.., fn_decl_span) => fn_decl_span,
 +                    hir::ExprClosure(.., fn_decl_span, _) => fn_decl_span,
                      ref r => bug!("Captured({}) maps to non-closure: {:?}",
                                    the_move.id, r),
                  }, " (into closure)"),
                                                  lp: &LoanPath<'tcx>,
                                                  assign:
                                                  &move_data::Assignment) {
-         let mut err = struct_span_err!(
-             self.tcx.sess, span, E0384,
-             "re-assignment of immutable variable `{}`",
-             self.loan_path_to_string(lp));
+         let mut err = self.cannot_reassign_immutable(span,
+                                                      &self.loan_path_to_string(lp),
+                                                      Origin::Ast);
          err.span_label(span, "re-assignment of immutable variable");
          if span != assign.span {
              err.span_label(assign.span, format!("first assignment to `{}`",
          self.tcx.sess.span_err_with_code(s, msg, code);
      }
  
 -    fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> {
 -        let span = err.span.clone();
 +    fn report_bckerr(&self, err: &BckError<'tcx>) {
 +        let error_span = err.span.clone();
  
          match err.code {
              err_mutbl => {
                      }
                  };
  
 -                match err.cause {
 +                let mut db = match err.cause {
                      MutabilityViolation => {
 -                        struct_span_err!(self.tcx.sess, span, E0594, "cannot assign to {}", descr)
 +                        struct_span_err!(self.tcx.sess,
 +                                         error_span,
 +                                         E0594,
 +                                         "cannot assign to {}",
 +                                         descr)
                      }
                      BorrowViolation(euv::ClosureCapture(_)) => {
 -                        struct_span_err!(self.tcx.sess, span, E0595,
 +                        struct_span_err!(self.tcx.sess, error_span, E0595,
                                           "closure cannot assign to {}", descr)
                      }
                      BorrowViolation(euv::OverloadedOperator) |
                      BorrowViolation(euv::AutoUnsafe) |
                      BorrowViolation(euv::ForLoop) |
                      BorrowViolation(euv::MatchDiscriminant) => {
 -                        struct_span_err!(self.tcx.sess, span, E0596,
 +                        struct_span_err!(self.tcx.sess, error_span, E0596,
                                           "cannot borrow {} as mutable", descr)
                      }
                      BorrowViolation(euv::ClosureInvocation) => {
                          span_bug!(err.span,
                              "err_mutbl with a closure invocation");
                      }
 -                }
 +                };
 +
 +                self.note_and_explain_mutbl_error(&mut db, &err, &error_span);
 +                self.note_immutability_blame(&mut db, err.cmt.immutability_blame());
 +                db.emit();
              }
 -            err_out_of_scope(..) => {
 +            err_out_of_scope(super_scope, sub_scope, cause) => {
                  let msg = match opt_loan_path(&err.cmt) {
                      None => "borrowed value".to_string(),
                      Some(lp) => {
                          format!("`{}`", self.loan_path_to_string(&lp))
                      }
                  };
 -                struct_span_err!(self.tcx.sess, span, E0597, "{} does not live long enough", msg)
 +
 +                // When you have a borrow that lives across a yield,
 +                // that reference winds up captured in the generator
 +                // type. Regionck then constraints it to live as long
 +                // as the generator itself. If that borrow is borrowing
 +                // data owned by the generator, this winds up resulting in
 +                // an `err_out_of_scope` error:
 +                //
 +                // ```
 +                // {
 +                //     let g = || {
 +                //         let a = &3; // this borrow is forced to ... -+
 +                //         yield ();          //                        |
 +                //         println!("{}", a); //                        |
 +                //     };                     //                        |
 +                // } <----------------------... live until here --------+
 +                // ```
 +                //
 +                // To detect this case, we look for cases where the
 +                // `super_scope` (lifetime of the value) is within the
 +                // body, but the `sub_scope` is not.
 +                debug!("err_out_of_scope: self.body.is_generator = {:?}",
 +                       self.body.is_generator);
 +                let maybe_borrow_across_yield = if self.body.is_generator {
 +                    let body_extent = region::CodeExtent::Misc(self.body.id().node_id);
 +                    debug!("err_out_of_scope: body_extent = {:?}", body_extent);
 +                    debug!("err_out_of_scope: super_scope = {:?}", super_scope);
 +                    debug!("err_out_of_scope: sub_scope = {:?}", sub_scope);
 +                    match (super_scope, sub_scope) {
 +                        (&ty::RegionKind::ReScope(value_extent),
 +                         &ty::RegionKind::ReScope(loan_extent)) => {
 +                            if {
 +                                // value_extent <= body_extent &&
 +                                self.region_maps.is_subscope_of(value_extent, body_extent) &&
 +                                    // body_extent <= loan_extent
 +                                    self.region_maps.is_subscope_of(body_extent, loan_extent)
 +                            } {
 +                                // We now know that this is a case
 +                                // that fits the bill described above:
 +                                // a borrow of something whose scope
 +                                // is within the generator, but the
 +                                // borrow is for a scope outside the
 +                                // generator.
 +                                //
 +                                // Now look within the scope of the of
 +                                // the value being borrowed (in the
 +                                // example above, that would be the
 +                                // block remainder that starts with
 +                                // `let a`) for a yield. We can cite
 +                                // that for the user.
 +                                self.tcx.yield_in_extent(value_extent, &mut FxHashMap())
 +                            } else {
 +                                None
 +                            }
 +                        }
 +                        _ => None,
 +                    }
 +                } else {
 +                    None
 +                };
 +
 +                if let Some(yield_span) = maybe_borrow_across_yield {
 +                    debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span);
 +                    struct_span_err!(self.tcx.sess,
 +                                     error_span,
 +                                     E0626,
 +                                     "borrow may still be in use when generator yields")
 +                        .span_label(yield_span, "possible yield occurs here")
 +                        .emit();
 +                    return;
 +                }
 +
 +                let mut db = struct_span_err!(self.tcx.sess,
 +                                              error_span,
 +                                              E0597,
 +                                              "{} does not live long enough",
 +                                              msg);
 +
 +                let (value_kind, value_msg) = match err.cmt.cat {
 +                    mc::Categorization::Rvalue(..) =>
 +                        ("temporary value", "temporary value created here"),
 +                    _ =>
 +                        ("borrowed value", "borrow occurs here")
 +                };
 +
 +                let is_closure = match cause {
 +                    euv::ClosureCapture(s) => {
 +                        // The primary span starts out as the closure creation point.
 +                        // Change the primary span here to highlight the use of the variable
 +                        // in the closure, because it seems more natural. Highlight
 +                        // closure creation point as a secondary span.
 +                        match db.span.primary_span() {
 +                            Some(primary) => {
 +                                db.span = MultiSpan::from_span(s);
 +                                db.span_label(primary, "capture occurs here");
 +                                db.span_label(s, "does not live long enough");
 +                                true
 +                            }
 +                            None => false
 +                        }
 +                    }
 +                    _ => {
 +                        db.span_label(error_span, "does not live long enough");
 +                        false
 +                    }
 +                };
 +
 +                let sub_span = self.region_end_span(sub_scope);
 +                let super_span = self.region_end_span(super_scope);
 +
 +                match (sub_span, super_span) {
 +                    (Some(s1), Some(s2)) if s1 == s2 => {
 +                        if !is_closure {
 +                            db.span = MultiSpan::from_span(s1);
 +                            db.span_label(error_span, value_msg);
 +                            let msg = match opt_loan_path(&err.cmt) {
 +                                None => value_kind.to_string(),
 +                                Some(lp) => {
 +                                    format!("`{}`", self.loan_path_to_string(&lp))
 +                                }
 +                            };
 +                            db.span_label(s1,
 +                                          format!("{} dropped here while still borrowed", msg));
 +                        } else {
 +                            db.span_label(s1, format!("{} dropped before borrower", value_kind));
 +                        }
 +                        db.note("values in a scope are dropped in the opposite order \
 +                                they are created");
 +                    }
 +                    (Some(s1), Some(s2)) if !is_closure => {
 +                        db.span = MultiSpan::from_span(s2);
 +                        db.span_label(error_span, value_msg);
 +                        let msg = match opt_loan_path(&err.cmt) {
 +                            None => value_kind.to_string(),
 +                            Some(lp) => {
 +                                format!("`{}`", self.loan_path_to_string(&lp))
 +                            }
 +                        };
 +                        db.span_label(s2, format!("{} dropped here while still borrowed", msg));
 +                        db.span_label(s1, format!("{} needs to live until here", value_kind));
 +                    }
 +                    _ => {
 +                        match sub_span {
 +                            Some(s) => {
 +                                db.span_label(s, format!("{} needs to live until here",
 +                                                          value_kind));
 +                            }
 +                            None => {
 +                                self.tcx.note_and_explain_region(
 +                                    &mut db,
 +                                    "borrowed value must be valid for ",
 +                                    sub_scope,
 +                                    "...");
 +                            }
 +                        }
 +                        match super_span {
 +                            Some(s) => {
 +                                db.span_label(s, format!("{} only lives until here", value_kind));
 +                            }
 +                            None => {
 +                                self.tcx.note_and_explain_region(
 +                                    &mut db,
 +                                    "...but borrowed value is only valid for ",
 +                                    super_scope,
 +                                    "");
 +                            }
 +                        }
 +                    }
 +                }
 +
 +                if let Some(_) = statement_scope_span(self.tcx, super_scope) {
 +                    db.note("consider using a `let` binding to increase its lifetime");
 +                }
 +
 +                db.emit();
              }
 -            err_borrowed_pointer_too_short(..) => {
 +            err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
                  let descr = self.cmt_to_path_or_string(&err.cmt);
 -                struct_span_err!(self.tcx.sess, span, E0598,
 -                                 "lifetime of {} is too short to guarantee \
 -                                  its contents can be safely reborrowed",
 -                                 descr)
 +                let mut db = struct_span_err!(self.tcx.sess, error_span, E0598,
 +                                              "lifetime of {} is too short to guarantee \
 +                                               its contents can be safely reborrowed",
 +                                              descr);
 +
 +                let descr = match opt_loan_path(&err.cmt) {
 +                    Some(lp) => {
 +                        format!("`{}`", self.loan_path_to_string(&lp))
 +                    }
 +                    None => self.cmt_to_string(&err.cmt),
 +                };
 +                self.tcx.note_and_explain_region(
 +                    &mut db,
 +                    &format!("{} would have to be valid for ",
 +                            descr),
 +                    loan_scope,
 +                    "...");
 +                self.tcx.note_and_explain_region(
 +                    &mut db,
 +                    &format!("...but {} is only valid for ", descr),
 +                    ptr_scope,
 +                    "");
 +
 +                db.emit();
              }
          }
      }
          }
      }
  
 -    fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) {
 -        let error_span = err.span.clone();
 -        match err.code {
 -            err_mutbl => {
 -                self.note_and_explain_mutbl_error(db, &err, &error_span);
 -                self.note_immutability_blame(db, err.cmt.immutability_blame());
 -            }
 -            err_out_of_scope(super_scope, sub_scope, cause) => {
 -                let (value_kind, value_msg) = match err.cmt.cat {
 -                    mc::Categorization::Rvalue(..) =>
 -                        ("temporary value", "temporary value created here"),
 -                    _ =>
 -                        ("borrowed value", "borrow occurs here")
 -                };
 -
 -                let is_closure = match cause {
 -                    euv::ClosureCapture(s) => {
 -                        // The primary span starts out as the closure creation point.
 -                        // Change the primary span here to highlight the use of the variable
 -                        // in the closure, because it seems more natural. Highlight
 -                        // closure creation point as a secondary span.
 -                        match db.span.primary_span() {
 -                            Some(primary) => {
 -                                db.span = MultiSpan::from_span(s);
 -                                db.span_label(primary, "capture occurs here");
 -                                db.span_label(s, "does not live long enough");
 -                                true
 -                            }
 -                            None => false
 -                        }
 -                    }
 -                    _ => {
 -                        db.span_label(error_span, "does not live long enough");
 -                        false
 -                    }
 -                };
 -
 -                let sub_span = self.region_end_span(sub_scope);
 -                let super_span = self.region_end_span(super_scope);
 -
 -                match (sub_span, super_span) {
 -                    (Some(s1), Some(s2)) if s1 == s2 => {
 -                        if !is_closure {
 -                            db.span = MultiSpan::from_span(s1);
 -                            db.span_label(error_span, value_msg);
 -                            let msg = match opt_loan_path(&err.cmt) {
 -                                None => value_kind.to_string(),
 -                                Some(lp) => {
 -                                    format!("`{}`", self.loan_path_to_string(&lp))
 -                                }
 -                            };
 -                            db.span_label(s1,
 -                                          format!("{} dropped here while still borrowed", msg));
 -                        } else {
 -                            db.span_label(s1, format!("{} dropped before borrower", value_kind));
 -                        }
 -                        db.note("values in a scope are dropped in the opposite order \
 -                                they are created");
 -                    }
 -                    (Some(s1), Some(s2)) if !is_closure => {
 -                        db.span = MultiSpan::from_span(s2);
 -                        db.span_label(error_span, value_msg);
 -                        let msg = match opt_loan_path(&err.cmt) {
 -                            None => value_kind.to_string(),
 -                            Some(lp) => {
 -                                format!("`{}`", self.loan_path_to_string(&lp))
 -                            }
 -                        };
 -                        db.span_label(s2, format!("{} dropped here while still borrowed", msg));
 -                        db.span_label(s1, format!("{} needs to live until here", value_kind));
 -                    }
 -                    _ => {
 -                        match sub_span {
 -                            Some(s) => {
 -                                db.span_label(s, format!("{} needs to live until here",
 -                                                          value_kind));
 -                            }
 -                            None => {
 -                                self.tcx.note_and_explain_region(
 -                                    db,
 -                                    "borrowed value must be valid for ",
 -                                    sub_scope,
 -                                    "...");
 -                            }
 -                        }
 -                        match super_span {
 -                            Some(s) => {
 -                                db.span_label(s, format!("{} only lives until here", value_kind));
 -                            }
 -                            None => {
 -                                self.tcx.note_and_explain_region(
 -                                    db,
 -                                    "...but borrowed value is only valid for ",
 -                                    super_scope,
 -                                    "");
 -                            }
 -                        }
 -                    }
 -                }
 -
 -                if let Some(_) = statement_scope_span(self.tcx, super_scope) {
 -                    db.note("consider using a `let` binding to increase its lifetime");
 -                }
 -            }
 -
 -            err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
 -                let descr = match opt_loan_path(&err.cmt) {
 -                    Some(lp) => {
 -                        format!("`{}`", self.loan_path_to_string(&lp))
 -                    }
 -                    None => self.cmt_to_string(&err.cmt),
 -                };
 -                self.tcx.note_and_explain_region(
 -                    db,
 -                    &format!("{} would have to be valid for ",
 -                            descr),
 -                    loan_scope,
 -                    "...");
 -                self.tcx.note_and_explain_region(
 -                    db,
 -                    &format!("...but {} is only valid for ", descr),
 -                    ptr_scope,
 -                    "");
 -            }
 -        }
 -    }
 -
      fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>,
                                      error_span: &Span) {
          match err.cmt.note {
index 517b4e7f99b4d06d82ca06ebe14c703e3ac88bb4,1f1fc4cc65fbe8e3f3bdf04e9d8e0c9660c9d466..50a9dccaa2bb8fa7aff8eb10ac8602f41f62048d
@@@ -63,27 -63,6 +63,6 @@@ Now that the closure has its own copy o
  about safety.
  "##,
  
- E0381: r##"
- It is not allowed to use or capture an uninitialized variable. For example:
- ```compile_fail,E0381
- fn main() {
-     let x: i32;
-     let y = x; // error, use of possibly uninitialized variable
- }
- ```
- To fix this, ensure that any declared variables are initialized before being
- used. Example:
- ```
- fn main() {
-     let x: i32 = 0;
-     let y = x; // ok!
- }
- ```
- "##,
  E0382: r##"
  This error occurs when an attempt is made to use a variable after its contents
  have been moved elsewhere. For example:
@@@ -182,28 -161,6 +161,6 @@@ x = Foo { a: 2 }
  ```
  "##,
  
- E0384: r##"
- This error occurs when an attempt is made to reassign an immutable variable.
- For example:
- ```compile_fail,E0384
- fn main() {
-     let x = 3;
-     x = 5; // error, reassignment of immutable variable
- }
- ```
- By default, variables in Rust are immutable. To fix this error, add the keyword
- `mut` after the keyword `let` when declaring the variable. For example:
- ```
- fn main() {
-     let mut x = 3;
-     x = 5;
- }
- ```
- "##,
  /*E0386: r##"
  This error occurs when an attempt is made to mutate the target of a mutable
  reference stored inside an immutable container.
@@@ -360,512 -317,6 +317,6 @@@ fn main() 
  ```
  "##,
  
- E0499: r##"
- A variable was borrowed as mutable more than once. Erroneous code example:
- ```compile_fail,E0499
- let mut i = 0;
- let mut x = &mut i;
- let mut a = &mut i;
- // error: cannot borrow `i` as mutable more than once at a time
- ```
- Please note that in rust, you can either have many immutable references, or one
- mutable reference. Take a look at
- https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
- for more information. Example:
- ```
- let mut i = 0;
- let mut x = &mut i; // ok!
- // or:
- let mut i = 0;
- let a = &i; // ok!
- let b = &i; // still ok!
- let c = &i; // still ok!
- ```
- "##,
- E0500: r##"
- A borrowed variable was used in another closure. Example of erroneous code:
- ```compile_fail
- fn you_know_nothing(jon_snow: &mut i32) {
-     let nights_watch = || {
-         *jon_snow = 2;
-     };
-     let starks = || {
-         *jon_snow = 3; // error: closure requires unique access to `jon_snow`
-                        //        but it is already borrowed
-     };
- }
- ```
- In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it
- cannot be borrowed by the `starks` closure at the same time. To fix this issue,
- you can put the closure in its own scope:
- ```
- fn you_know_nothing(jon_snow: &mut i32) {
-     {
-         let nights_watch = || {
-             *jon_snow = 2;
-         };
-     } // At this point, `jon_snow` is free.
-     let starks = || {
-         *jon_snow = 3;
-     };
- }
- ```
- Or, if the type implements the `Clone` trait, you can clone it between
- closures:
- ```
- fn you_know_nothing(jon_snow: &mut i32) {
-     let mut jon_copy = jon_snow.clone();
-     let nights_watch = || {
-         jon_copy = 2;
-     };
-     let starks = || {
-         *jon_snow = 3;
-     };
- }
- ```
- "##,
- E0501: r##"
- This error indicates that a mutable variable is being used while it is still
- captured by a closure. Because the closure has borrowed the variable, it is not
- available for use until the closure goes out of scope.
- Note that a capture will either move or borrow a variable, but in this
- situation, the closure is borrowing the variable. Take a look at
- http://rustbyexample.com/fn/closures/capture.html for more information about
- capturing.
- Example of erroneous code:
- ```compile_fail,E0501
- fn inside_closure(x: &mut i32) {
-     // Actions which require unique access
- }
- fn outside_closure(x: &mut i32) {
-     // Actions which require unique access
- }
- fn foo(a: &mut i32) {
-     let bar = || {
-         inside_closure(a)
-     };
-     outside_closure(a); // error: cannot borrow `*a` as mutable because previous
-                         //        closure requires unique access.
- }
- ```
- To fix this error, you can place the closure in its own scope:
- ```
- fn inside_closure(x: &mut i32) {}
- fn outside_closure(x: &mut i32) {}
- fn foo(a: &mut i32) {
-     {
-         let bar = || {
-             inside_closure(a)
-         };
-     } // borrow on `a` ends.
-     outside_closure(a); // ok!
- }
- ```
- Or you can pass the variable as a parameter to the closure:
- ```
- fn inside_closure(x: &mut i32) {}
- fn outside_closure(x: &mut i32) {}
- fn foo(a: &mut i32) {
-     let bar = |s: &mut i32| {
-         inside_closure(s)
-     };
-     outside_closure(a);
-     bar(a);
- }
- ```
- It may be possible to define the closure later:
- ```
- fn inside_closure(x: &mut i32) {}
- fn outside_closure(x: &mut i32) {}
- fn foo(a: &mut i32) {
-     outside_closure(a);
-     let bar = || {
-         inside_closure(a)
-     };
- }
- ```
- "##,
- E0502: r##"
- This error indicates that you are trying to borrow a variable as mutable when it
- has already been borrowed as immutable.
- Example of erroneous code:
- ```compile_fail,E0502
- fn bar(x: &mut i32) {}
- fn foo(a: &mut i32) {
-     let ref y = a; // a is borrowed as immutable.
-     bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
-             //        as immutable
- }
- ```
- To fix this error, ensure that you don't have any other references to the
- variable before trying to access it mutably:
- ```
- fn bar(x: &mut i32) {}
- fn foo(a: &mut i32) {
-     bar(a);
-     let ref y = a; // ok!
- }
- ```
- For more information on the rust ownership system, take a look at
- https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html.
- "##,
- E0503: r##"
- A value was used after it was mutably borrowed.
- Example of erroneous code:
- ```compile_fail,E0503
- fn main() {
-     let mut value = 3;
-     // Create a mutable borrow of `value`. This borrow
-     // lives until the end of this function.
-     let _borrow = &mut value;
-     let _sum = value + 1; // error: cannot use `value` because
-                           //        it was mutably borrowed
- }
- ```
- In this example, `value` is mutably borrowed by `borrow` and cannot be
- used to calculate `sum`. This is not possible because this would violate
- Rust's mutability rules.
- You can fix this error by limiting the scope of the borrow:
- ```
- fn main() {
-     let mut value = 3;
-     // By creating a new block, you can limit the scope
-     // of the reference.
-     {
-         let _borrow = &mut value; // Use `_borrow` inside this block.
-     }
-     // The block has ended and with it the borrow.
-     // You can now use `value` again.
-     let _sum = value + 1;
- }
- ```
- Or by cloning `value` before borrowing it:
- ```
- fn main() {
-     let mut value = 3;
-     // We clone `value`, creating a copy.
-     let value_cloned = value.clone();
-     // The mutable borrow is a reference to `value` and
-     // not to `value_cloned`...
-     let _borrow = &mut value;
-     // ... which means we can still use `value_cloned`,
-     let _sum = value_cloned + 1;
-     // even though the borrow only ends here.
- }
- ```
- You can find more information about borrowing in the rust-book:
- http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
- "##,
- E0504: r##"
- This error occurs when an attempt is made to move a borrowed variable into a
- closure.
- Example of erroneous code:
- ```compile_fail,E0504
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let fancy_num = FancyNum { num: 5 };
-     let fancy_ref = &fancy_num;
-     let x = move || {
-         println!("child function: {}", fancy_num.num);
-         // error: cannot move `fancy_num` into closure because it is borrowed
-     };
-     x();
-     println!("main function: {}", fancy_ref.num);
- }
- ```
- Here, `fancy_num` is borrowed by `fancy_ref` and so cannot be moved into
- the closure `x`. There is no way to move a value into a closure while it is
- borrowed, as that would invalidate the borrow.
- If the closure can't outlive the value being moved, try using a reference
- rather than moving:
- ```
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let fancy_num = FancyNum { num: 5 };
-     let fancy_ref = &fancy_num;
-     let x = move || {
-         // fancy_ref is usable here because it doesn't move `fancy_num`
-         println!("child function: {}", fancy_ref.num);
-     };
-     x();
-     println!("main function: {}", fancy_num.num);
- }
- ```
- If the value has to be borrowed and then moved, try limiting the lifetime of
- the borrow using a scoped block:
- ```
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let fancy_num = FancyNum { num: 5 };
-     {
-         let fancy_ref = &fancy_num;
-         println!("main function: {}", fancy_ref.num);
-         // `fancy_ref` goes out of scope here
-     }
-     let x = move || {
-         // `fancy_num` can be moved now (no more references exist)
-         println!("child function: {}", fancy_num.num);
-     };
-     x();
- }
- ```
- If the lifetime of a reference isn't enough, such as in the case of threading,
- consider using an `Arc` to create a reference-counted value:
- ```
- use std::sync::Arc;
- use std::thread;
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let fancy_ref1 = Arc::new(FancyNum { num: 5 });
-     let fancy_ref2 = fancy_ref1.clone();
-     let x = thread::spawn(move || {
-         // `fancy_ref1` can be moved and has a `'static` lifetime
-         println!("child thread: {}", fancy_ref1.num);
-     });
-     x.join().expect("child thread should finish");
-     println!("main thread: {}", fancy_ref2.num);
- }
- ```
- "##,
- E0505: r##"
- A value was moved out while it was still borrowed.
- Erroneous code example:
- ```compile_fail,E0505
- struct Value {}
- fn eat(val: Value) {}
- fn main() {
-     let x = Value{};
-     {
-         let _ref_to_val: &Value = &x;
-         eat(x);
-     }
- }
- ```
- Here, the function `eat` takes the ownership of `x`. However,
- `x` cannot be moved because it was borrowed to `_ref_to_val`.
- To fix that you can do few different things:
- * Try to avoid moving the variable.
- * Release borrow before move.
- * Implement the `Copy` trait on the type.
- Examples:
- ```
- struct Value {}
- fn eat(val: &Value) {}
- fn main() {
-     let x = Value{};
-     {
-         let _ref_to_val: &Value = &x;
-         eat(&x); // pass by reference, if it's possible
-     }
- }
- ```
- Or:
- ```
- struct Value {}
- fn eat(val: Value) {}
- fn main() {
-     let x = Value{};
-     {
-         let _ref_to_val: &Value = &x;
-     }
-     eat(x); // release borrow and then move it.
- }
- ```
- Or:
- ```
- #[derive(Clone, Copy)] // implement Copy trait
- struct Value {}
- fn eat(val: Value) {}
- fn main() {
-     let x = Value{};
-     {
-         let _ref_to_val: &Value = &x;
-         eat(x); // it will be copied here.
-     }
- }
- ```
- You can find more information about borrowing in the rust-book:
- http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
- "##,
- E0506: r##"
- This error occurs when an attempt is made to assign to a borrowed value.
- Example of erroneous code:
- ```compile_fail,E0506
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let mut fancy_num = FancyNum { num: 5 };
-     let fancy_ref = &fancy_num;
-     fancy_num = FancyNum { num: 6 };
-     // error: cannot assign to `fancy_num` because it is borrowed
-     println!("Num: {}, Ref: {}", fancy_num.num, fancy_ref.num);
- }
- ```
- Because `fancy_ref` still holds a reference to `fancy_num`, `fancy_num` can't
- be assigned to a new value as it would invalidate the reference.
- Alternatively, we can move out of `fancy_num` into a second `fancy_num`:
- ```
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let mut fancy_num = FancyNum { num: 5 };
-     let moved_num = fancy_num;
-     fancy_num = FancyNum { num: 6 };
-     println!("Num: {}, Moved num: {}", fancy_num.num, moved_num.num);
- }
- ```
- If the value has to be borrowed, try limiting the lifetime of the borrow using
- a scoped block:
- ```
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let mut fancy_num = FancyNum { num: 5 };
-     {
-         let fancy_ref = &fancy_num;
-         println!("Ref: {}", fancy_ref.num);
-     }
-     // Works because `fancy_ref` is no longer in scope
-     fancy_num = FancyNum { num: 6 };
-     println!("Num: {}", fancy_num.num);
- }
- ```
- Or by moving the reference into a function:
- ```
- struct FancyNum {
-     num: u8,
- }
- fn main() {
-     let mut fancy_num = FancyNum { num: 5 };
-     print_fancy_ref(&fancy_num);
-     // Works because function borrow has ended
-     fancy_num = FancyNum { num: 6 };
-     println!("Num: {}", fancy_num.num);
- }
- fn print_fancy_ref(fancy_ref: &FancyNum){
-     println!("Ref: {}", fancy_ref.num);
- }
- ```
- "##,
  E0507: r##"
  You tried to move out of a value which was borrowed. Erroneous code example:
  
@@@ -1201,97 -652,10 +652,96 @@@ x.x = Some(&y)
  ```
  "##,
  
 +E0626: r##"
 +This error occurs because a borrow in a generator persists across a
 +yield point.
 +
 +```compile_fail,E0626
 +# #![feature(generators, generator_trait)]
 +# use std::ops::Generator;
 +let mut b = || {
 +    let a = &3; // <-- This borrow...
 +    yield (); // ...is still in scope here, when the yield occurs.
 +    println!("{}", a);
 +};
 +b.resume();
 +```
 +
 +At present, it is not permitted to have a yield that occurs while a
 +borrow is still in scope. To resolve this error, the borrow must
 +either be "contained" to a smaller scope that does not overlap the
 +yield or else eliminated in another way. So, for example, we might
 +resolve the previous example by removing the borrow and just storing
 +the integer by value:
 +
 +```
 +# #![feature(generators, generator_trait)]
 +# use std::ops::Generator;
 +let mut b = || {
 +    let a = 3;
 +    yield ();
 +    println!("{}", a);
 +};
 +b.resume();
 +```
 +
 +This is a very simple case, of course. In more complex cases, we may
 +wish to have more than one reference to the value that was borrowed --
 +in those cases, something like the `Rc` or `Arc` types may be useful.
 +
 +This error also frequently arises with iteration:
 +
 +```compile_fail,E0626
 +# #![feature(generators, generator_trait)]
 +# use std::ops::Generator;
 +let mut b = || {
 +  let v = vec![1,2,3];
 +  for &x in &v { // <-- borrow of `v` is still in scope...
 +    yield x; // ...when this yield occurs.
 +  }
 +};
 +b.resume();
 +```
 +
 +Such cases can sometimes be resolved by iterating "by value" (or using
 +`into_iter()`) to avoid borrowing:
 +
 +```
 +# #![feature(generators, generator_trait)]
 +# use std::ops::Generator;
 +let mut b = || {
 +  let v = vec![1,2,3];
 +  for x in v { // <-- Take ownership of the values instead!
 +    yield x; // <-- Now yield is OK.
 +  }
 +};
 +b.resume();
 +```
 +
 +If taking ownership is not an option, using indices can work too:
 +
 +```
 +# #![feature(generators, generator_trait)]
 +# use std::ops::Generator;
 +let mut b = || {
 +  let v = vec![1,2,3];
 +  let len = v.len(); // (*)
 +  for i in 0..len {
 +    let x = v[i]; // (*)
 +    yield x; // <-- Now yield is OK.
 +  }
 +};
 +b.resume();
 +
 +// (*) -- Unfortunately, these temporaries are currently required.
 +// See <https://github.com/rust-lang/rust/issues/43122>.
 +```
 +"##,
 +
  }
  
  register_diagnostics! {
  //    E0385, // {} in an aliasable location
-     E0524, // two closures require unique access to `..` at the same time
      E0594, // cannot assign to {}
      E0598, // lifetime of {} is too short to guarantee its contents can be...
  }
index cc56289a5633467998551c93a0a27facc6ee7b99,9cb6806e9ade5b831b605b9cdaa607a980d2ca71..47fa21e3bf0b2bf6a1e47f4d6c78b94c1aca9246
@@@ -9,11 -9,9 +9,11 @@@
  // except according to those terms.
  
  use std::fmt;
 +use std::iter;
  use std::marker::PhantomData;
  use std::mem;
  use std::ops::{Deref, DerefMut, Range};
 +use std::slice;
  use bitslice::{BitSlice, Word};
  use bitslice::{bitwise, Union, Subtract};
  use indexed_vec::Idx;
@@@ -23,7 -21,6 +23,7 @@@
  ///
  /// In other words, `T` is the type used to index into the bitvector
  /// this type uses to represent the set of object it holds.
 +#[derive(Eq, PartialEq)]
  pub struct IdxSetBuf<T: Idx> {
      _pd: PhantomData<fn(&T)>,
      bits: Vec<Word>,
@@@ -112,13 -109,6 +112,13 @@@ impl<T: Idx> IdxSet<T> 
          }
      }
  
 +    /// Removes all elements
 +    pub fn clear(&mut self) {
 +        for b in &mut self.bits {
 +            *b = 0;
 +        }
 +    }
 +
      /// Removes `elem` from the set `self`; returns true iff this changed `self`.
      pub fn remove(&mut self, elem: &T) -> bool {
          self.bits.clear_bit(elem.index())
          bitwise(self.words_mut(), other.words(), &Subtract)
      }
  
 +    pub fn iter(&self) -> Iter<T> {
 +        Iter {
 +            cur: None,
 +            iter: self.words().iter().enumerate(),
 +            _pd: PhantomData,
 +        }
 +    }
++
+     /// Calls `f` on each index value held in this set, up to the
+     /// bound `max_bits` on the size of universe of indexes.
+     pub fn each_bit<F>(&self, max_bits: usize, f: F) where F: FnMut(T) {
+         each_bit(self, max_bits, f)
+     }
+     /// Removes all elements from this set.
+     pub fn reset_to_empty(&mut self) {
+         for word in self.words_mut() { *word = 0; }
+     }
+     pub fn elems(&self, universe_size: usize) -> Elems<T> {
+         Elems { i: 0, set: self, universe_size: universe_size }
+     }
+ }
+ pub struct Elems<'a, T: Idx> { i: usize, set: &'a IdxSet<T>, universe_size: usize }
+ impl<'a, T: Idx> Iterator for Elems<'a, T> {
+     type Item = T;
+     fn next(&mut self) -> Option<T> {
+         if self.i >= self.universe_size { return None; }
+         let mut i = self.i;
+         loop {
+             if i >= self.universe_size {
+                 self.i = i; // (mark iteration as complete.)
+                 return None;
+             }
+             if self.set.contains(&T::new(i)) {
+                 self.i = i + 1; // (next element to start at.)
+                 return Some(T::new(i));
+             }
+             i = i + 1;
+         }
+     }
+ }
+ fn each_bit<T: Idx, F>(words: &IdxSet<T>, max_bits: usize, mut f: F) where F: FnMut(T) {
+     let usize_bits: usize = mem::size_of::<usize>() * 8;
+     for (word_index, &word) in words.words().iter().enumerate() {
+         if word != 0 {
+             let base_index = word_index * usize_bits;
+             for offset in 0..usize_bits {
+                 let bit = 1 << offset;
+                 if (word & bit) != 0 {
+                     // NB: we round up the total number of bits
+                     // that we store in any given bit set so that
+                     // it is an even multiple of usize::BITS. This
+                     // means that there may be some stray bits at
+                     // the end that do not correspond to any
+                     // actual value; that's why we first check
+                     // that we are in range of bits_per_block.
+                     let bit_index = base_index + offset as usize;
+                     if bit_index >= max_bits {
+                         return;
+                     } else {
+                         f(Idx::new(bit_index));
+                     }
+                 }
+             }
+         }
+     }
  }
 +
 +pub struct Iter<'a, T: Idx> {
 +    cur: Option<(Word, usize)>,
 +    iter: iter::Enumerate<slice::Iter<'a, Word>>,
 +    _pd: PhantomData<fn(&T)>,
 +}
 +
 +impl<'a, T: Idx> Iterator for Iter<'a, T> {
 +    type Item = T;
 +
 +    fn next(&mut self) -> Option<T> {
 +        let word_bits = mem::size_of::<Word>() * 8;
 +        loop {
 +            if let Some((ref mut word, offset)) = self.cur {
 +                let bit_pos = word.trailing_zeros() as usize;
 +                if bit_pos != word_bits {
 +                    let bit = 1 << bit_pos;
 +                    *word ^= bit;
 +                    return Some(T::new(bit_pos + offset))
 +                }
 +            }
 +
 +            match self.iter.next() {
 +                Some((i, word)) => self.cur = Some((*word, word_bits * i)),
 +                None => return None,
 +            }
 +        }
 +    }
 +}
index 749b983e453fcd12e79b963e4ac8b6483259e15f,0c729b5a3fc87ed16ec48c50693e7a0d427681f8..19d237b7761d355cf0be02dc0ee48d454a40fad1
@@@ -970,7 -970,12 +970,12 @@@ pub fn phase_3_run_analysis_passes<'tcx
      // We compute "constant qualifications" between MIR_CONST and MIR_VALIDATED.
  
      // What we need to run borrowck etc.
      passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
+     // FIXME: ariel points SimplifyBranches should run after
+     // mir-borrowck; otherwise code within `if false { ... }` would
+     // not be checked.
      passes.push_pass(MIR_VALIDATED,
                       mir::transform::simplify_branches::SimplifyBranches::new("initial"));
      passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
  
      // borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED.
  
+     // FIXME: niko says this should be a query (see rustc::ty::maps)
+     // instead of a pass.
+     passes.push_pass(MIR_VALIDATED, mir::transform::borrow_check::BorrowckMir);
      // These next passes must be executed together
      passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
      passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
      passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
      passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation);
      passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals);
 +
 +    passes.push_pass(MIR_OPTIMIZED, mir::transform::generator::StateTransform);
      passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
      passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
  
index e4fd2b0e8f7c6a3e9fae731d67290d2d584b5b0d,e460848450e0be4f41d300bcb461b185d245d07a..cdf991a0933f3b809fd354276278119c4a31434d
@@@ -8,16 -8,17 +8,17 @@@
  // option. This file may not be copied, modified, or distributed
  // except according to those terms.
  
- use syntax::ast;
+ use syntax::ast::{self, MetaItem};
  
  use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
  use rustc_data_structures::indexed_vec::Idx;
  use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
  
- use rustc::ty::{TyCtxt};
- use rustc::mir::{self, Mir};
+ use rustc::ty::{self, TyCtxt};
+ use rustc::mir::{self, Mir, BasicBlock, BasicBlockData, Location, Statement, Terminator};
+ use rustc::session::Session;
  
- use std::fmt::Debug;
+ use std::fmt::{self, Debug};
  use std::io;
  use std::mem;
  use std::path::PathBuf;
@@@ -25,9 -26,11 +26,11 @@@ use std::usize
  
  pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
  pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements};
+ pub use self::impls::borrows::{Borrows, BorrowData, BorrowIndex};
  pub(crate) use self::drop_flag_effects::*;
  
+ use self::move_paths::MoveData;
  mod drop_flag_effects;
  mod graphviz;
  mod impls;
@@@ -44,11 -47,22 +47,22 @@@ pub(crate) struct DataflowBuilder<'a, '
  }
  
  pub trait Dataflow<BD: BitDenotation> {
-     fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug;
+     /// Sets up and runs the dataflow problem, using `p` to render results if
+     /// implementation so chooses.
+     fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
+         let _ = p; // default implementation does not instrument process.
+         self.build_sets();
+         self.propagate();
+     }
+     /// Sets up the entry, gen, and kill sets for this instance of a dataflow problem.
+     fn build_sets(&mut self);
+     /// Finds a fixed-point solution to this instance of a dataflow problem.
+     fn propagate(&mut self);
  }
  
- impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD>
-     where BD: BitDenotation + DataflowOperator
+ impl<'a, 'tcx: 'a, BD> Dataflow<BD> for DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
  {
      fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
          self.flow_state.build_sets();
          self.flow_state.propagate();
          self.post_dataflow_instrumentation(|c,i| p(c,i)).unwrap();
      }
+     fn build_sets(&mut self) { self.flow_state.build_sets(); }
+     fn propagate(&mut self) { self.flow_state.propagate(); }
+ }
+ pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
+     for attr in attrs {
+         if attr.check_name("rustc_mir") {
+             let items = attr.meta_item_list();
+             for item in items.iter().flat_map(|l| l.iter()) {
+                 match item.meta_item() {
+                     Some(mi) if mi.check_name(name) => return Some(mi.clone()),
+                     _ => continue
+                 }
+             }
+         }
+     }
+     return None;
+ }
+ pub struct MoveDataParamEnv<'tcx> {
+     pub(crate) move_data: MoveData<'tcx>,
+     pub(crate) param_env: ty::ParamEnv<'tcx>,
+ }
+ pub(crate) fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 mir: &Mir<'tcx>,
+                                 node_id: ast::NodeId,
+                                 attributes: &[ast::Attribute],
+                                 dead_unwinds: &IdxSet<BasicBlock>,
+                                 bd: BD,
+                                 p: P)
+                                 -> DataflowResults<BD>
+     where BD: BitDenotation,
+           P: Fn(&BD, BD::Idx) -> &fmt::Debug
+ {
+     let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
+         if let Some(item) = has_rustc_mir_with(attrs, name) {
+             if let Some(s) = item.value_str() {
+                 return Some(s.to_string())
+             } else {
+                 sess.span_err(
+                     item.span,
+                     &format!("{} attribute requires a path", item.name()));
+                 return None;
+             }
+         }
+         return None;
+     };
+     let print_preflow_to =
+         name_found(tcx.sess, attributes, "borrowck_graphviz_preflow");
+     let print_postflow_to =
+         name_found(tcx.sess, attributes, "borrowck_graphviz_postflow");
+     let mut mbcx = DataflowBuilder {
+         node_id,
+         print_preflow_to,
+         print_postflow_to,
+         flow_state: DataflowAnalysis::new(tcx, mir, dead_unwinds, bd),
+     };
+     mbcx.dataflow(p);
+     mbcx.flow_state.results()
  }
  
- struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O>
-     where O: 'b + BitDenotation
+ struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O> where O: 'b + BitDenotation
  {
      builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
      changed: bool,
  }
  
- impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD>
-     where BD: BitDenotation + DataflowOperator
+ impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
  {
      fn propagate(&mut self) {
          let mut temp = IdxSetBuf::new_empty(self.flow_state.sets.bits_per_block);
  
              let sets = &mut self.flow_state.sets.for_block(bb.index());
              for j_stmt in 0..statements.len() {
-                 self.flow_state.operator.statement_effect(sets, bb, j_stmt);
+                 let location = Location { block: bb, statement_index: j_stmt };
+                 self.flow_state.operator.statement_effect(sets, location);
              }
  
              if terminator.is_some() {
-                 let stmts_len = statements.len();
-                 self.flow_state.operator.terminator_effect(sets, bb, stmts_len);
+                 let location = Location { block: bb, statement_index: statements.len() };
+                 self.flow_state.operator.terminator_effect(sets, location);
              }
          }
      }
  }
  
- impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD>
-     where BD: BitDenotation + DataflowOperator
+ impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation
  {
      fn reset(&mut self, bits: &mut IdxSet<BD::Idx>) {
          let e = if BD::bottom_value() {!0} else {0};
@@@ -147,8 -223,7 +223,7 @@@ fn dataflow_path(context: &str, prepost
      path
  }
  
- impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD>
-     where BD: BitDenotation
+ impl<'a, 'tcx: 'a, BD> DataflowBuilder<'a, 'tcx, BD> where BD: BitDenotation
  {
      fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
          where P: Fn(&BD, BD::Idx) -> &Debug
@@@ -189,21 -264,108 +264,108 @@@ impl<E:Idx> Bits<E> 
      }
  }
  
- pub struct DataflowAnalysis<'a, 'tcx: 'a, O>
-     where O: BitDenotation
+ /// DataflowResultsConsumer abstracts over walking the MIR with some
+ /// already constructed dataflow results.
+ ///
+ /// It abstracts over the FlowState and also completely hides the
+ /// underlying flow analysis results, because it needs to handle cases
+ /// where we are combining the results of *multiple* flow analyses
+ /// (e.g. borrows + inits + uninits).
+ pub trait DataflowResultsConsumer<'a, 'tcx: 'a> {
+     type FlowState;
+     // Observation Hooks: override (at least one of) these to get analysis feedback.
+     fn visit_block_entry(&mut self,
+                          _bb: BasicBlock,
+                          _flow_state: &Self::FlowState) {}
+     fn visit_statement_entry(&mut self,
+                              _loc: Location,
+                              _stmt: &Statement<'tcx>,
+                              _flow_state: &Self::FlowState) {}
+     fn visit_terminator_entry(&mut self,
+                               _loc: Location,
+                               _term: &Terminator<'tcx>,
+                               _flow_state: &Self::FlowState) {}
+     // Main entry point: this drives the processing of results.
+     fn analyze_results(&mut self, flow_uninit: &mut Self::FlowState) {
+         let flow = flow_uninit;
+         for bb in self.mir().basic_blocks().indices() {
+             self.reset_to_entry_of(bb, flow);
+             self.process_basic_block(bb, flow);
+         }
+     }
+     fn process_basic_block(&mut self, bb: BasicBlock, flow_state: &mut Self::FlowState) {
+         let BasicBlockData { ref statements, ref terminator, is_cleanup: _ } =
+             self.mir()[bb];
+         let mut location = Location { block: bb, statement_index: 0 };
+         for stmt in statements.iter() {
+             self.reconstruct_statement_effect(location, flow_state);
+             self.visit_statement_entry(location, stmt, flow_state);
+             self.apply_local_effect(location, flow_state);
+             location.statement_index += 1;
+         }
+         if let Some(ref term) = *terminator {
+             self.reconstruct_terminator_effect(location, flow_state);
+             self.visit_terminator_entry(location, term, flow_state);
+             // We don't need to apply the effect of the terminator,
+             // since we are only visiting dataflow state on control
+             // flow entry to the various nodes. (But we still need to
+             // reconstruct the effect, because the visit method might
+             // inspect it.)
+         }
+     }
+     // Delegated Hooks: Provide access to the MIR and process the flow state.
+     fn mir(&self) -> &'a Mir<'tcx>;
+     // reset the state bitvector to represent the entry to block `bb`.
+     fn reset_to_entry_of(&mut self,
+                          bb: BasicBlock,
+                          flow_state: &mut Self::FlowState);
+     // build gen + kill sets for statement at `loc`.
+     fn reconstruct_statement_effect(&mut self,
+                                     loc: Location,
+                                     flow_state: &mut Self::FlowState);
+     // build gen + kill sets for terminator for `loc`.
+     fn reconstruct_terminator_effect(&mut self,
+                                      loc: Location,
+                                      flow_state: &mut Self::FlowState);
+     // apply current gen + kill sets to `flow_state`.
+     //
+     // (`bb` and `stmt_idx` parameters can be ignored if desired by
+     // client. For the terminator, the `stmt_idx` will be the number
+     // of statements in the block.)
+     fn apply_local_effect(&mut self,
+                           loc: Location,
+                           flow_state: &mut Self::FlowState);
+ }
+ pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
  {
      flow_state: DataflowState<O>,
      dead_unwinds: &'a IdxSet<mir::BasicBlock>,
      mir: &'a Mir<'tcx>,
  }
  
- impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O>
-     where O: BitDenotation
+ impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O> where O: BitDenotation
  {
      pub fn results(self) -> DataflowResults<O> {
          DataflowResults(self.flow_state)
      }
  
+     pub fn flow_state(&self) -> &DataflowState<O> { &self.flow_state }
      pub fn mir(&self) -> &'a Mir<'tcx> { self.mir }
  }
  
@@@ -213,10 -375,14 +375,14 @@@ impl<O: BitDenotation> DataflowResults<
      pub fn sets(&self) -> &AllSets<O::Idx> {
          &self.0.sets
      }
+     pub fn operator(&self) -> &O {
+         &self.0.operator
+     }
  }
  
- // FIXME: This type shouldn't be public, but the graphviz::MirWithFlowState trait
- // references it in a method signature. Look into using `pub(crate)` to address this.
+ /// State of a dataflow analysis; couples a collection of bit sets
+ /// with operator used to initialize and merge bits during analysis.
  pub struct DataflowState<O: BitDenotation>
  {
      /// All the sets for the analysis. (Factored into its
      pub(crate) operator: O,
  }
  
+ impl<O: BitDenotation> DataflowState<O> {
+     pub fn each_bit<F>(&self, words: &IdxSet<O::Idx>, f: F) where F: FnMut(O::Idx)
+     {
+         let bits_per_block = self.operator.bits_per_block();
+         words.each_bit(bits_per_block, f)
+     }
+     pub fn interpret_set<'c, P>(&self,
+                                 o: &'c O,
+                                 words: &IdxSet<O::Idx>,
+                                 render_idx: &P)
+                                 -> Vec<&'c Debug>
+         where P: Fn(&O, O::Idx) -> &Debug
+     {
+         let mut v = Vec::new();
+         self.each_bit(words, |i| {
+             v.push(render_idx(o, i));
+         });
+         v
+     }
+ }
  #[derive(Debug)]
  pub struct AllSets<E: Idx> {
      /// Analysis bitwidth for each block.
      on_entry_sets: Bits<E>,
  }
  
+ /// Triple of sets associated with a given block.
+ ///
+ /// Generally, one sets up `on_entry`, `gen_set`, and `kill_set` for
+ /// each block individually, and then runs the dataflow analysis which
+ /// iteratively modifies the various `on_entry` sets (but leaves the
+ /// other two sets unchanged, since they represent the effect of the
+ /// block, which should be invariant over the course of the analysis).
+ ///
+ /// It is best to ensure that the intersection of `gen_set` and
+ /// `kill_set` is empty; otherwise the results of the dataflow will
+ /// have a hidden dependency on what order the bits are generated and
+ /// killed during the iteration. (This is such a good idea that the
+ /// `fn gen` and `fn kill` methods that set their state enforce this
+ /// for you.)
  pub struct BlockSets<'a, E: Idx> {
+     /// Dataflow state immediately before control flow enters the given block.
      pub(crate) on_entry: &'a mut IdxSet<E>,
+     /// Bits that are set to 1 by the time we exit the given block.
      pub(crate) gen_set: &'a mut IdxSet<E>,
+     /// Bits that are set to 0 by the time we exit the given block.
      pub(crate) kill_set: &'a mut IdxSet<E>,
  }
  
@@@ -302,7 -509,7 +509,7 @@@ pub trait DataflowOperator: BitwiseOper
      fn bottom_value() -> bool;
  }
  
- pub trait BitDenotation {
+ pub trait BitDenotation: DataflowOperator {
      /// Specifies what index type is used to access the bitvector.
      type Idx: Idx;
  
      /// the MIR.
      fn statement_effect(&self,
                          sets: &mut BlockSets<Self::Idx>,
-                         bb: mir::BasicBlock,
-                         idx_stmt: usize);
+                         location: Location);
  
      /// Mutates the block-sets (the flow sets for the given
      /// basic block) according to the effects of evaluating
      /// terminator took.
      fn terminator_effect(&self,
                           sets: &mut BlockSets<Self::Idx>,
-                          bb: mir::BasicBlock,
-                          idx_term: usize);
+                          location: Location);
  
      /// Mutates the block-sets according to the (flow-dependent)
      /// effect of a successful return from a Call terminator.
                               dest_lval: &mir::Lvalue);
  }
  
- impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
-     where D: BitDenotation + DataflowOperator
+ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
  {
      pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 mir: &'a Mir<'tcx>,
      }
  }
  
- impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D>
-     where D: BitDenotation + DataflowOperator
+ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
  {
      /// Propagates the bits of `in_out` into all the successors of `bb`,
      /// using bitwise operator denoted by `self.operator`.
          match bb_data.terminator().kind {
              mir::TerminatorKind::Return |
              mir::TerminatorKind::Resume |
 +            mir::TerminatorKind::GeneratorDrop |
              mir::TerminatorKind::Unreachable => {}
              mir::TerminatorKind::Goto { ref target } |
              mir::TerminatorKind::Assert { ref target, cleanup: None, .. } |
 +            mir::TerminatorKind::Yield { resume: ref target, drop: None, .. } |
              mir::TerminatorKind::Drop { ref target, location: _, unwind: None } |
              mir::TerminatorKind::DropAndReplace {
                  ref target, value: _, location: _, unwind: None
              } => {
                  self.propagate_bits_into_entry_set_for(in_out, changed, target);
              }
 +            mir::TerminatorKind::Yield { resume: ref target, drop: Some(ref drop), .. } => {
 +                self.propagate_bits_into_entry_set_for(in_out, changed, target);
 +                self.propagate_bits_into_entry_set_for(in_out, changed, drop);
 +            }
              mir::TerminatorKind::Assert { ref target, cleanup: Some(ref unwind), .. } |
              mir::TerminatorKind::Drop { ref target, location: _, unwind: Some(ref unwind) } |
              mir::TerminatorKind::DropAndReplace {
index 0000000000000000000000000000000000000000,c45c91011d9f4028f6fb4967d5828b28af594ca8..86298c3b83e29ce63a07876f88d0c49f6f610bbf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,332 +1,337 @@@
+ // 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 <LICENSE-APACHE or
+ // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+ // option. This file may not be copied, modified, or distributed
+ // except according to those terms.
+ use rustc::ty::{self, TyCtxt};
+ use rustc::mir::*;
+ use rustc::mir::tcx::RvalueInitializationState;
+ use rustc::util::nodemap::FxHashMap;
+ use rustc_data_structures::indexed_vec::{IndexVec};
+ use syntax::codemap::DUMMY_SP;
+ use std::collections::hash_map::Entry;
+ use std::mem;
+ use super::abs_domain::Lift;
+ use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
+ pub(super) struct MoveDataBuilder<'a, 'tcx: 'a> {
+     mir: &'a Mir<'tcx>,
+     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+     param_env: ty::ParamEnv<'tcx>,
+     data: MoveData<'tcx>,
+ }
+ pub enum MovePathError {
+     IllegalMove,
+     UnionMove { path: MovePathIndex },
+ }
+ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
+     fn new(mir: &'a Mir<'tcx>,
+            tcx: TyCtxt<'a, 'tcx, 'tcx>,
+            param_env: ty::ParamEnv<'tcx>)
+            -> Self {
+         let mut move_paths = IndexVec::new();
+         let mut path_map = IndexVec::new();
+         MoveDataBuilder {
+             mir,
+             tcx,
+             param_env,
+             data: MoveData {
+                 moves: IndexVec::new(),
+                 loc_map: LocationMap::new(mir),
+                 rev_lookup: MovePathLookup {
+                     locals: mir.local_decls.indices().map(Lvalue::Local).map(|v| {
+                         Self::new_move_path(&mut move_paths, &mut path_map, None, v)
+                     }).collect(),
+                     projections: FxHashMap(),
+                 },
+                 move_paths,
+                 path_map,
+             }
+         }
+     }
+     fn new_move_path(move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>,
+                      path_map: &mut IndexVec<MovePathIndex, Vec<MoveOutIndex>>,
+                      parent: Option<MovePathIndex>,
+                      lvalue: Lvalue<'tcx>)
+                      -> MovePathIndex
+     {
+         let move_path = move_paths.push(MovePath {
+             next_sibling: None,
+             first_child: None,
+             parent,
+             lvalue,
+         });
+         if let Some(parent) = parent {
+             let next_sibling =
+                 mem::replace(&mut move_paths[parent].first_child, Some(move_path));
+             move_paths[move_path].next_sibling = next_sibling;
+         }
+         let path_map_ent = path_map.push(vec![]);
+         assert_eq!(path_map_ent, move_path);
+         move_path
+     }
+     /// This creates a MovePath for a given lvalue, returning an `MovePathError`
+     /// if that lvalue can't be moved from.
+     ///
+     /// NOTE: lvalues behind references *do not* get a move path, which is
+     /// problematic for borrowck.
+     ///
+     /// Maybe we should have separate "borrowck" and "moveck" modes.
+     fn move_path_for(&mut self, lval: &Lvalue<'tcx>)
+                      -> Result<MovePathIndex, MovePathError>
+     {
+         debug!("lookup({:?})", lval);
+         match *lval {
+             Lvalue::Local(local) => Ok(self.data.rev_lookup.locals[local]),
+             // error: can't move out of a static
+             Lvalue::Static(..) => Err(MovePathError::IllegalMove),
+             Lvalue::Projection(ref proj) => {
+                 self.move_path_for_projection(lval, proj)
+             }
+         }
+     }
+     fn create_move_path(&mut self, lval: &Lvalue<'tcx>) {
+         // This is an assignment, not a move, so this not being a valid
+         // move path is OK.
+         let _ = self.move_path_for(lval);
+     }
+     fn move_path_for_projection(&mut self,
+                                 lval: &Lvalue<'tcx>,
+                                 proj: &LvalueProjection<'tcx>)
+                                 -> Result<MovePathIndex, MovePathError>
+     {
+         let base = try!(self.move_path_for(&proj.base));
+         let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
+         match lv_ty.sty {
+             // error: can't move out of borrowed content
+             ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
+             // error: can't move out of struct with destructor
+             ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
+                 return Err(MovePathError::IllegalMove),
+             // move out of union - always move the entire union
+             ty::TyAdt(adt, _) if adt.is_union() =>
+                 return Err(MovePathError::UnionMove { path: base }),
+             // error: can't move out of a slice
+             ty::TySlice(..) =>
+                 return Err(MovePathError::IllegalMove),
+             ty::TyArray(..) => match proj.elem {
+                 // error: can't move out of an array
+                 ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove),
+                 _ => {
+                     // FIXME: still badly broken
+                 }
+             },
+             _ => {}
+         };
+         match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) {
+             Entry::Occupied(ent) => Ok(*ent.get()),
+             Entry::Vacant(ent) => {
+                 let path = Self::new_move_path(
+                     &mut self.data.move_paths,
+                     &mut self.data.path_map,
+                     Some(base),
+                     lval.clone()
+                 );
+                 ent.insert(path);
+                 Ok(path)
+             }
+         }
+     }
+     fn finalize(self) -> MoveData<'tcx> {
+         debug!("{}", {
+             debug!("moves for {:?}:", self.mir.span);
+             for (j, mo) in self.data.moves.iter_enumerated() {
+                 debug!("    {:?} = {:?}", j, mo);
+             }
+             debug!("move paths for {:?}:", self.mir.span);
+             for (j, path) in self.data.move_paths.iter_enumerated() {
+                 debug!("    {:?} = {:?}", j, path);
+             }
+             "done dumping moves"
+         });
+         self.data
+     }
+ }
+ pub(super) fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>,
+                                      tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                      param_env: ty::ParamEnv<'tcx>)
+                                      -> MoveData<'tcx> {
+     let mut builder = MoveDataBuilder::new(mir, tcx, param_env);
+     for (bb, block) in mir.basic_blocks().iter_enumerated() {
+         for (i, stmt) in block.statements.iter().enumerate() {
+             let source = Location { block: bb, statement_index: i };
+             builder.gather_statement(source, stmt);
+         }
+         let terminator_loc = Location {
+             block: bb,
+             statement_index: block.statements.len()
+         };
+         builder.gather_terminator(terminator_loc, block.terminator());
+     }
+     builder.finalize()
+ }
+ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
+     fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) {
+         debug!("gather_statement({:?}, {:?})", loc, stmt);
+         match stmt.kind {
+             StatementKind::Assign(ref lval, ref rval) => {
+                 self.create_move_path(lval);
+                 if let RvalueInitializationState::Shallow = rval.initialization_state() {
+                     // Box starts out uninitialized - need to create a separate
+                     // move-path for the interior so it will be separate from
+                     // the exterior.
+                     self.create_move_path(&lval.clone().deref());
+                 }
+                 self.gather_rvalue(loc, rval);
+             }
+             StatementKind::StorageLive(_) |
+             StatementKind::StorageDead(_) => {}
+             StatementKind::SetDiscriminant{ .. } => {
+                 span_bug!(stmt.source_info.span,
+                           "SetDiscriminant should not exist during borrowck");
+             }
+             StatementKind::InlineAsm { .. } |
+             StatementKind::EndRegion(_) |
+             StatementKind::Validate(..) |
+             StatementKind::Nop => {}
+         }
+     }
+     fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) {
+         match *rvalue {
+             Rvalue::Use(ref operand) |
+             Rvalue::Repeat(ref operand, _) |
+             Rvalue::Cast(_, ref operand, _) |
+             Rvalue::UnaryOp(_, ref operand) => {
+                 self.gather_operand(loc, operand)
+             }
+             Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) |
+             Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => {
+                 self.gather_operand(loc, lhs);
+                 self.gather_operand(loc, rhs);
+             }
+             Rvalue::Aggregate(ref _kind, ref operands) => {
+                 for operand in operands {
+                     self.gather_operand(loc, operand);
+                 }
+             }
+             Rvalue::Ref(..) |
+             Rvalue::Discriminant(..) |
+             Rvalue::Len(..) |
+             Rvalue::NullaryOp(NullOp::SizeOf, _) |
+             Rvalue::NullaryOp(NullOp::Box, _) => {
+                 // This returns an rvalue with uninitialized contents. We can't
+                 // move out of it here because it is an rvalue - assignments always
+                 // completely initialize their lvalue.
+                 //
+                 // However, this does not matter - MIR building is careful to
+                 // only emit a shallow free for the partially-initialized
+                 // temporary.
+                 //
+                 // In any case, if we want to fix this, we have to register a
+                 // special move and change the `statement_effect` functions.
+             }
+         }
+     }
+     fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) {
+         debug!("gather_terminator({:?}, {:?})", loc, term);
+         match term.kind {
+             TerminatorKind::Goto { target: _ } |
+             TerminatorKind::Resume |
++            TerminatorKind::GeneratorDrop |
+             TerminatorKind::Unreachable => { }
+             TerminatorKind::Return => {
+                 self.gather_move(loc, &Lvalue::Local(RETURN_POINTER));
+             }
+             TerminatorKind::Assert { .. } |
+             TerminatorKind::SwitchInt { .. } => {
+                 // branching terminators - these don't move anything
+             }
++            TerminatorKind::Yield { ref value, .. } => {
++                self.gather_operand(loc, value);
++            }
++
+             TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
+                 self.gather_move(loc, location);
+             }
+             TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
+                 self.create_move_path(location);
+                 self.gather_operand(loc, value);
+             }
+             TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
+                 self.gather_operand(loc, func);
+                 for arg in args {
+                     self.gather_operand(loc, arg);
+                 }
+                 if let Some((ref destination, _bb)) = *destination {
+                     self.create_move_path(destination);
+                 }
+             }
+         }
+     }
+     fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) {
+         match *operand {
+             Operand::Constant(..) => {} // not-a-move
+             Operand::Consume(ref lval) => { // a move
+                 self.gather_move(loc, lval);
+             }
+         }
+     }
+     fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) {
+         debug!("gather_move({:?}, {:?})", loc, lval);
+         let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx);
+         if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) {
+             debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty);
+             return
+         }
+         let path = match self.move_path_for(lval) {
+             Ok(path) | Err(MovePathError::UnionMove { path }) => path,
+             Err(MovePathError::IllegalMove) => {
+                 // Moving out of a bad path. Eventually, this should be a MIR
+                 // borrowck error instead of a bug.
+                 span_bug!(self.mir.span,
+                           "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}",
+                           lval, lv_ty, loc);
+             }
+         };
+         let move_out = self.data.moves.push(MoveOut { path: path, source: loc });
+         debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}",
+                loc, lval, move_out, path);
+         self.data.path_map[path].push(move_out);
+         self.data.loc_map[loc].push(move_out);
+     }
+ }
index cc61f3c11d799a19fb140f07ce27e68ffcf96560,38070a4b4858a7bd2392742f5fd5161665d2dfa8..d8564f858e5683481f49ef46d8bde68018134f79
@@@ -31,6 -31,7 +31,7 @@@ pub mod simplify
  pub mod erase_regions;
  pub mod no_landing_pads;
  pub mod type_check;
+ pub mod borrow_check;
  pub mod rustc_peek;
  pub mod elaborate_drops;
  pub mod add_call_guards;
@@@ -40,7 -41,6 +41,7 @@@ pub mod dump_mir
  pub mod deaggregator;
  pub mod instcombine;
  pub mod copy_prop;
 +pub mod generator;
  pub mod inline;
  pub mod nll;
  
index b03fd0196a369dc9fba5711e76139866f2dba91f,f0d837e1362d1eea7deb2e723d89d0c262ec8d8d..4b6da96824dcd9ac126247f25713b4e7fbb36205
@@@ -8,13 -8,13 +8,14 @@@
  // option. This file may not be copied, modified, or distributed
  // except according to those terms.
  
+ pub mod borrowck_errors;
  pub mod elaborate_drops;
  pub mod def_use;
  pub mod patch;
  
  mod graphviz;
  mod pretty;
 +pub mod liveness;
  
  pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty};
  pub use self::graphviz::{write_mir_graphviz};