1
Fork 0

Enable migrate mode by default on the 2015 edition

This also fully stabilizes two-phase borrows on all editions
This commit is contained in:
Matthew Jasper 2019-01-26 17:25:37 +00:00
parent 31a75a1728
commit aa6fb6caf9
16 changed files with 154 additions and 357 deletions

View file

@ -92,8 +92,8 @@ impl SuppressRegionErrors {
/// enabled. /// enabled.
pub fn when_nll_is_enabled(tcx: TyCtxt<'_, '_, '_>) -> Self { pub fn when_nll_is_enabled(tcx: TyCtxt<'_, '_, '_>) -> Self {
match tcx.borrowck_mode() { match tcx.borrowck_mode() {
// If we're on AST or Migrate mode, report AST region errors // If we're on Migrate mode, report AST region errors
BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false }, BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false },
// If we're on MIR or Compare mode, don't report AST region errors as they should // If we're on MIR or Compare mode, don't report AST region errors as they should
// be reported by NLL // be reported by NLL

View file

@ -460,7 +460,6 @@ pub enum PrintRequest {
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BorrowckMode { pub enum BorrowckMode {
Ast,
Mir, Mir,
Compare, Compare,
Migrate, Migrate,
@ -471,7 +470,6 @@ impl BorrowckMode {
/// on the AST borrow check if the MIR-based one errors. /// on the AST borrow check if the MIR-based one errors.
pub fn migrate(self) -> bool { pub fn migrate(self) -> bool {
match self { match self {
BorrowckMode::Ast => false,
BorrowckMode::Compare => false, BorrowckMode::Compare => false,
BorrowckMode::Mir => false, BorrowckMode::Mir => false,
BorrowckMode::Migrate => true, BorrowckMode::Migrate => true,
@ -481,21 +479,11 @@ impl BorrowckMode {
/// Should we emit the AST-based borrow checker errors? /// Should we emit the AST-based borrow checker errors?
pub fn use_ast(self) -> bool { pub fn use_ast(self) -> bool {
match self { match self {
BorrowckMode::Ast => true,
BorrowckMode::Compare => true, BorrowckMode::Compare => true,
BorrowckMode::Mir => false, BorrowckMode::Mir => false,
BorrowckMode::Migrate => false, BorrowckMode::Migrate => false,
} }
} }
/// Should we emit the MIR-based borrow checker errors?
pub fn use_mir(self) -> bool {
match self {
BorrowckMode::Ast => false,
BorrowckMode::Compare => true,
BorrowckMode::Mir => true,
BorrowckMode::Migrate => true,
}
}
} }
pub enum Input { pub enum Input {
@ -627,7 +615,7 @@ impl Default for Options {
incremental: None, incremental: None,
debugging_opts: basic_debugging_options(), debugging_opts: basic_debugging_options(),
prints: Vec::new(), prints: Vec::new(),
borrowck_mode: BorrowckMode::Ast, borrowck_mode: BorrowckMode::Migrate,
cg: basic_codegen_options(), cg: basic_codegen_options(),
error_format: ErrorOutputType::default(), error_format: ErrorOutputType::default(),
externs: Externs(BTreeMap::new()), externs: Externs(BTreeMap::new()),
@ -2326,10 +2314,9 @@ pub fn build_session_options_and_crate_config(
})); }));
let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) { let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
None | Some("ast") => BorrowckMode::Ast, None | Some("migrate") => BorrowckMode::Migrate,
Some("mir") => BorrowckMode::Mir, Some("mir") => BorrowckMode::Mir,
Some("compare") => BorrowckMode::Compare, Some("compare") => BorrowckMode::Compare,
Some("migrate") => BorrowckMode::Migrate,
Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)), Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
}; };

View file

@ -70,7 +70,6 @@ use rustc_macros::HashStable;
use syntax::ast; use syntax::ast;
use syntax::attr; use syntax::attr;
use syntax::source_map::MultiSpan; use syntax::source_map::MultiSpan;
use syntax::edition::Edition;
use syntax::feature_gate; use syntax::feature_gate;
use syntax::symbol::{Symbol, keywords, InternedString}; use syntax::symbol::{Symbol, keywords, InternedString};
use syntax_pos::Span; use syntax_pos::Span;
@ -1496,21 +1495,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// because that method has a narrower effect that can be toggled /// because that method has a narrower effect that can be toggled
/// off via a separate `-Z` flag, at least for the short term. /// off via a separate `-Z` flag, at least for the short term.
pub fn allow_bind_by_move_patterns_with_guards(self) -> bool { pub fn allow_bind_by_move_patterns_with_guards(self) -> bool {
self.features().bind_by_move_pattern_guards && self.use_mir_borrowck() self.features().bind_by_move_pattern_guards
} }
/// If true, we should use a naive AST walk to determine if match /// If true, we should use a naive AST walk to determine if match
/// guard could perform bad mutations (or mutable-borrows). /// guard could perform bad mutations (or mutable-borrows).
pub fn check_for_mutation_in_guard_via_ast_walk(self) -> bool { pub fn check_for_mutation_in_guard_via_ast_walk(self) -> bool {
// If someone requests the feature, then be a little more !self.allow_bind_by_move_patterns_with_guards()
// careful and ensure that MIR-borrowck is enabled (which can
// happen via edition selection, via `feature(nll)`, or via an
// appropriate `-Z` flag) before disabling the mutation check.
if self.allow_bind_by_move_patterns_with_guards() {
return false;
}
return true;
} }
/// If true, we should use the AST-based borrowck (we may *also* use /// If true, we should use the AST-based borrowck (we may *also* use
@ -1519,12 +1510,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.borrowck_mode().use_ast() self.borrowck_mode().use_ast()
} }
/// If true, we should use the MIR-based borrowck (we may *also* use
/// the AST-based borrowck).
pub fn use_mir_borrowck(self) -> bool {
self.borrowck_mode().use_mir()
}
/// If true, we should use the MIR-based borrow check, but also /// If true, we should use the MIR-based borrow check, but also
/// fall back on the AST borrow check if the MIR-based one errors. /// fall back on the AST borrow check if the MIR-based one errors.
pub fn migrate_borrowck(self) -> bool { pub fn migrate_borrowck(self) -> bool {
@ -1541,23 +1526,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// statements (which simulate the maximal effect of executing the /// statements (which simulate the maximal effect of executing the
/// patterns in a match arm). /// patterns in a match arm).
pub fn emit_read_for_match(&self) -> bool { pub fn emit_read_for_match(&self) -> bool {
self.use_mir_borrowck() && !self.sess.opts.debugging_opts.nll_dont_emit_read_for_match !self.sess.opts.debugging_opts.nll_dont_emit_read_for_match
}
/// If true, pattern variables for use in guards on match arms
/// will be bound as references to the data, and occurrences of
/// those variables in the guard expression will implicitly
/// dereference those bindings. (See rust-lang/rust#27282.)
pub fn all_pat_vars_are_implicit_refs_within_guards(self) -> bool {
self.borrowck_mode().use_mir()
}
/// If true, we should enable two-phase borrows checks. This is
/// done with either: `-Ztwo-phase-borrows`, `#![feature(nll)]`,
/// or by opting into an edition after 2015.
pub fn two_phase_borrows(self) -> bool {
self.sess.rust_2018() || self.features().nll ||
self.sess.opts.debugging_opts.two_phase_borrows
} }
/// What mode(s) of borrowck should we run? AST? MIR? both? /// What mode(s) of borrowck should we run? AST? MIR? both?
@ -1565,14 +1534,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn borrowck_mode(&self) -> BorrowckMode { pub fn borrowck_mode(&self) -> BorrowckMode {
// Here are the main constraints we need to deal with: // Here are the main constraints we need to deal with:
// //
// 1. An opts.borrowck_mode of `BorrowckMode::Ast` is // 1. An opts.borrowck_mode of `BorrowckMode::Migrate` is
// synonymous with no `-Z borrowck=...` flag at all. // synonymous with no `-Z borrowck=...` flag at all.
// (This is arguably a historical accident.)
// //
// 2. `BorrowckMode::Migrate` is the limited migration to // 2. We want to allow developers on the Nightly channel
// NLL that we are deploying with the 2018 edition.
//
// 3. We want to allow developers on the Nightly channel
// to opt back into the "hard error" mode for NLL, // to opt back into the "hard error" mode for NLL,
// (which they can do via specifying `#![feature(nll)]` // (which they can do via specifying `#![feature(nll)]`
// explicitly in their crate). // explicitly in their crate).
@ -1585,24 +1550,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// a user's attempt to specify `-Z borrowck=compare`, which // a user's attempt to specify `-Z borrowck=compare`, which
// we arguably do not need anymore and should remove.) // we arguably do not need anymore and should remove.)
// //
// * Otherwise, if no `-Z borrowck=...` flag was given (or // * Otherwise, if no `-Z borrowck=...` then use migrate mode
// if `borrowck=ast` was specified), then use the default
// as required by the edition.
// //
// * Otherwise, use the behavior requested via `-Z borrowck=...` // * Otherwise, use the behavior requested via `-Z borrowck=...`
if self.features().nll { return BorrowckMode::Mir; } if self.features().nll { return BorrowckMode::Mir; }
match self.sess.opts.borrowck_mode { self.sess.opts.borrowck_mode
mode @ BorrowckMode::Mir |
mode @ BorrowckMode::Compare |
mode @ BorrowckMode::Migrate => mode,
BorrowckMode::Ast => match self.sess.edition() {
Edition::Edition2015 => BorrowckMode::Ast,
Edition::Edition2018 => BorrowckMode::Migrate,
},
}
} }
#[inline] #[inline]

View file

@ -49,8 +49,6 @@ pub mod gather_loans;
pub mod move_data; pub mod move_data;
mod unused;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct LoanDataFlowOperator; pub struct LoanDataFlowOperator;
@ -138,10 +136,6 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body); check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body);
} }
if !tcx.use_mir_borrowck() {
unused::check(&mut bccx, body);
}
Lrc::new(BorrowCheckResult { Lrc::new(BorrowCheckResult {
used_mut_nodes: bccx.used_mut_nodes.into_inner(), used_mut_nodes: bccx.used_mut_nodes.into_inner(),
signalled_any_error: bccx.signalled_any_error.into_inner(), signalled_any_error: bccx.signalled_any_error.into_inner(),

View file

@ -1,116 +0,0 @@
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
use rustc::hir::{self, HirId};
use rustc::lint::builtin::UNUSED_MUT;
use rustc::ty;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use errors::Applicability;
use std::slice;
use syntax::ptr::P;
use crate::borrowck::BorrowckCtxt;
pub fn check<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: &'tcx hir::Body) {
let mut used_mut = bccx.used_mut_nodes.borrow().clone();
UsedMutFinder {
bccx,
set: &mut used_mut,
}.visit_expr(&body.value);
let mut cx = UnusedMutCx { bccx, used_mut };
for arg in body.arguments.iter() {
cx.check_unused_mut_pat(slice::from_ref(&arg.pat));
}
cx.visit_expr(&body.value);
}
struct UsedMutFinder<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
set: &'a mut FxHashSet<HirId>,
}
struct UnusedMutCx<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
used_mut: FxHashSet<HirId>,
}
impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> {
fn check_unused_mut_pat(&self, pats: &[P<hir::Pat>]) {
let tcx = self.bccx.tcx;
let mut mutables: FxHashMap<_, Vec<_>> = Default::default();
for p in pats {
p.each_binding(|_, hir_id, span, ident| {
// Skip anything that looks like `_foo`
if ident.as_str().starts_with("_") {
return;
}
// Skip anything that looks like `&foo` or `&mut foo`, only look
// for by-value bindings
if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) {
match bm {
ty::BindByValue(hir::MutMutable) => {}
_ => return,
}
mutables.entry(ident.name).or_default().push((hir_id, span));
} else {
tcx.sess.delay_span_bug(span, "missing binding mode");
}
});
}
for (_name, ids) in mutables {
// If any id for this name was used mutably then consider them all
// ok, so move on to the next
if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) {
continue;
}
let (hir_id, span) = ids[0];
if span.compiler_desugaring_kind().is_some() {
// If the `mut` arises as part of a desugaring, we should ignore it.
continue;
}
// Ok, every name wasn't used mutably, so issue a warning that this
// didn't need to be mutable.
let mut_span = tcx.sess.source_map().span_until_non_whitespace(span);
tcx.struct_span_lint_hir(UNUSED_MUT,
hir_id,
span,
"variable does not need to be mutable")
.span_suggestion_short(
mut_span,
"remove this `mut`",
String::new(),
Applicability::MachineApplicable,
)
.emit();
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for UnusedMutCx<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir())
}
fn visit_arm(&mut self, arm: &hir::Arm) {
self.check_unused_mut_pat(&arm.pats)
}
fn visit_local(&mut self, local: &hir::Local) {
self.check_unused_mut_pat(slice::from_ref(&local.pat));
}
}
impl<'a, 'tcx> Visitor<'tcx> for UsedMutFinder<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::OnlyBodies(&self.bccx.tcx.hir())
}
fn visit_nested_body(&mut self, id: hir::BodyId) {
let def_id = self.bccx.tcx.hir().body_owner_def_id(id);
self.set.extend(self.bccx.tcx.borrowck(def_id).used_mut_nodes.iter().cloned());
self.visit_body(self.bccx.tcx.hir().body(id));
}
}

View file

@ -303,9 +303,8 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
/// allowed to be split into separate Reservation and /// allowed to be split into separate Reservation and
/// Activation phases. /// Activation phases.
fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool { fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
self.tcx.two_phase_borrows() kind.allows_two_phase_borrow()
&& (kind.allows_two_phase_borrow() || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref
|| self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
} }
/// If this is a two-phase borrow, then we will record it /// If this is a two-phase borrow, then we will record it

View file

@ -74,37 +74,28 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC
let input_mir = tcx.mir_validated(def_id); let input_mir = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id)); debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
let mut return_early; // We are not borrow checking the automatically generated struct/variant constructors
// because we want to accept structs such as this (taken from the `linked-hash-map`
// Return early if we are not supposed to use MIR borrow checker for this function. // crate):
return_early = !tcx.has_attr(def_id, "rustc_mir") && !tcx.use_mir_borrowck(); // ```rust
// struct Qey<Q: ?Sized>(Q);
// ```
// MIR of this struct constructor looks something like this:
// ```rust
// fn Qey(_1: Q) -> Qey<Q>{
// let mut _0: Qey<Q>; // return place
//
// bb0: {
// (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
// return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
// }
// }
// ```
// The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
// of statically known size, which is not known to be true because of the
// `Q: ?Sized` constraint. However, it is true because the constructor can be
// called only when `Q` is of statically known size.
if tcx.is_constructor(def_id) { if tcx.is_constructor(def_id) {
// We are not borrow checking the automatically generated struct/variant constructors
// because we want to accept structs such as this (taken from the `linked-hash-map`
// crate):
// ```rust
// struct Qey<Q: ?Sized>(Q);
// ```
// MIR of this struct constructor looks something like this:
// ```rust
// fn Qey(_1: Q) -> Qey<Q>{
// let mut _0: Qey<Q>; // return place
//
// bb0: {
// (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
// return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
// }
// }
// ```
// The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
// of statically known size, which is not known to be true because of the
// `Q: ?Sized` constraint. However, it is true because the constructor can be
// called only when `Q` is of statically known size.
return_early = true;
}
if return_early {
return BorrowCheckResult { return BorrowCheckResult {
closure_requirements: None, closure_requirements: None,
used_mut_upvars: SmallVec::new(), used_mut_upvars: SmallVec::new(),
@ -1505,10 +1496,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
span: Span, span: Span,
flow_state: &Flows<'cx, 'gcx, 'tcx>, flow_state: &Flows<'cx, 'gcx, 'tcx>,
) { ) {
if !self.infcx.tcx.two_phase_borrows() {
return;
}
// Two-phase borrow support: For each activation that is newly // Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with // generated at this statement, check if it interferes with
// another borrow. // another borrow.

View file

@ -474,10 +474,6 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
&mut self, &mut self,
location: Location, location: Location,
) { ) {
if !self.tcx.two_phase_borrows() {
return;
}
// Two-phase borrow support: For each activation that is newly // Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with // generated at this statement, check if it interferes with
// another borrow. // another borrow.

View file

@ -2672,9 +2672,8 @@ impl MirPass for TypeckMir {
let def_id = src.def_id(); let def_id = src.def_id();
debug!("run_pass: {:?}", def_id); debug!("run_pass: {:?}", def_id);
// When NLL is enabled, the borrow checker runs the typeck // FIXME: We don't need this MIR pass anymore.
// itself, so we don't need this MIR pass anymore. if true {
if tcx.use_mir_borrowck() {
return; return;
} }

View file

@ -15,9 +15,8 @@ pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>(
tcx: &TyCtxt<'a, 'gcx, 'tcx>, tcx: &TyCtxt<'a, 'gcx, 'tcx>,
kind: BorrowKind kind: BorrowKind
) -> bool { ) -> bool {
tcx.two_phase_borrows() kind.allows_two_phase_borrow()
&& (kind.allows_two_phase_borrow() || tcx.sess.opts.debugging_opts.two_phase_beyond_autoref
|| tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
} }
/// Control for the path borrow checking code /// Control for the path borrow checking code

View file

@ -112,11 +112,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} }
ExprKind::SelfRef => block.and(Place::Base(PlaceBase::Local(Local::new(1)))), ExprKind::SelfRef => block.and(Place::Base(PlaceBase::Local(Local::new(1)))),
ExprKind::VarRef { id } => { ExprKind::VarRef { id } => {
let place = if this.is_bound_var_in_guard(id) && this let place = if this.is_bound_var_in_guard(id) {
.hir
.tcx()
.all_pat_vars_are_implicit_refs_within_guards()
{
let index = this.var_local_id(id, RefWithinGuard); let index = this.var_local_id(id, RefWithinGuard);
Place::Base(PlaceBase::Local(index)).deref() Place::Base(PlaceBase::Local(index)).deref()
} else { } else {

View file

@ -1425,26 +1425,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// the reference that we create for the arm. // the reference that we create for the arm.
// * So we eagerly create the reference for the arm and then take a // * So we eagerly create the reference for the arm and then take a
// reference to that. // reference to that.
let tcx = self.hir.tcx();
let autoref = tcx.all_pat_vars_are_implicit_refs_within_guards();
if let Some(guard) = guard { if let Some(guard) = guard {
if autoref { let tcx = self.hir.tcx();
self.bind_matched_candidate_for_guard(
block, self.bind_matched_candidate_for_guard(
&candidate.bindings, block,
); &candidate.bindings,
let guard_frame = GuardFrame { );
locals: candidate let guard_frame = GuardFrame {
.bindings locals: candidate
.iter() .bindings
.map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)) .iter()
.collect(), .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode))
}; .collect(),
debug!("Entering guard building context: {:?}", guard_frame); };
self.guard_context.push(guard_frame); debug!("Entering guard building context: {:?}", guard_frame);
} else { self.guard_context.push(guard_frame);
self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
}
let re_erased = tcx.types.re_erased; let re_erased = tcx.types.re_erased;
let scrutinee_source_info = self.source_info(scrutinee_span); let scrutinee_source_info = self.source_info(scrutinee_span);
@ -1470,13 +1466,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let source_info = self.source_info(guard.span); let source_info = self.source_info(guard.span);
let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span)); let guard_end = self.source_info(tcx.sess.source_map().end_point(guard.span));
let cond = unpack!(block = self.as_local_operand(block, guard)); let cond = unpack!(block = self.as_local_operand(block, guard));
if autoref { let guard_frame = self.guard_context.pop().unwrap();
let guard_frame = self.guard_context.pop().unwrap(); debug!(
debug!( "Exiting guard building context with locals: {:?}",
"Exiting guard building context with locals: {:?}", guard_frame
guard_frame );
);
}
for &(_, temp) in fake_borrows { for &(_, temp) in fake_borrows {
self.cfg.push(block, Statement { self.cfg.push(block, Statement {
@ -1526,28 +1520,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
), ),
); );
if autoref { let by_value_bindings = candidate.bindings.iter().filter(|binding| {
let by_value_bindings = candidate.bindings.iter().filter(|binding| { if let BindingMode::ByValue = binding.binding_mode { true } else { false }
if let BindingMode::ByValue = binding.binding_mode { true } else { false } });
}); // Read all of the by reference bindings to ensure that the
// Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard.
// place they refer to can't be modified by the guard. for binding in by_value_bindings.clone() {
for binding in by_value_bindings.clone() { let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
let place = Place::Base(PlaceBase::Local(local_id)); let place = Place::Base(PlaceBase::Local(local_id));
self.cfg.push( self.cfg.push(
block, block,
Statement { Statement {
source_info: guard_end, source_info: guard_end,
kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place), kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place),
}, },
);
}
self.bind_matched_candidate_for_arm_body(
post_guard_block,
by_value_bindings,
); );
} }
self.bind_matched_candidate_for_arm_body(
post_guard_block,
by_value_bindings,
);
self.cfg.terminate( self.cfg.terminate(
post_guard_block, post_guard_block,
@ -1604,8 +1596,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
} }
} }
// Only called when all_pat_vars_are_implicit_refs_within_guards,
// and thus all code/comments assume we are in that context.
fn bind_matched_candidate_for_guard( fn bind_matched_candidate_for_guard(
&mut self, &mut self,
block: BasicBlock, block: BasicBlock,
@ -1739,7 +1729,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}))), }))),
}; };
let for_arm_body = self.local_decls.push(local.clone()); let for_arm_body = self.local_decls.push(local.clone());
let locals = if has_guard.0 && tcx.all_pat_vars_are_implicit_refs_within_guards() { let locals = if has_guard.0 {
let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> { let ref_for_guard = self.local_decls.push(LocalDecl::<'tcx> {
// This variable isn't mutated but has a name, so has to be // This variable isn't mutated but has a name, so has to be
// immutable to avoid the unused mut lint. // immutable to avoid the unused mut lint.

View file

@ -877,12 +877,14 @@ https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
"##, "##,
E0383: r##" E0383: r##"
#### Note: this error code is no longer emitted by the compiler.
This error occurs when an attempt is made to partially reinitialize a This error occurs when an attempt is made to partially reinitialize a
structure that is currently uninitialized. structure that is currently uninitialized.
For example, this can happen when a drop has taken place: For example, this can happen when a drop has taken place:
```compile_fail,E0383 ```compile_fail
struct Foo { struct Foo {
a: u32, a: u32,
} }
@ -966,10 +968,12 @@ y.set(2);
"##,*/ "##,*/
E0387: r##" E0387: r##"
#### Note: this error code is no longer emitted by the compiler.
This error occurs when an attempt is made to mutate or mutably reference data This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below: that a closure has captured immutably. Examples of this error are shown below:
```compile_fail,E0387 ```compile_fail
// Accepts a function or a closure that captures its environment immutably. // Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state. // Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { } fn foo<F: Fn()>(f: F) { }
@ -1026,13 +1030,15 @@ E0388 was removed and is no longer issued.
"##, "##,
E0389: r##" E0389: r##"
#### Note: this error code is no longer emitted by the compiler.
An attempt was made to mutate data using a non-mutable reference. This An attempt was made to mutate data using a non-mutable reference. This
commonly occurs when attempting to assign to a non-mutable reference of a commonly occurs when attempting to assign to a non-mutable reference of a
mutable reference (`&(&mut T)`). mutable reference (`&(&mut T)`).
Example of erroneous code: Example of erroneous code:
```compile_fail,E0389 ```compile_fail
struct FancyNum { struct FancyNum {
num: u8, num: u8,
} }
@ -1202,6 +1208,7 @@ A variable was borrowed as mutable more than once. Erroneous code example:
let mut i = 0; let mut i = 0;
let mut x = &mut i; let mut x = &mut i;
let mut a = &mut i; let mut a = &mut i;
x;
// error: cannot borrow `i` as mutable more than once at a time // error: cannot borrow `i` as mutable more than once at a time
``` ```
@ -1220,35 +1227,33 @@ let mut i = 0;
let a = &i; // ok! let a = &i; // ok!
let b = &i; // still ok! let b = &i; // still ok!
let c = &i; // still ok! let c = &i; // still ok!
b;
a;
``` ```
"##, "##,
E0500: r##" E0500: r##"
A borrowed variable was used in another closure. Example of erroneous code: A borrowed variable was used by a closure. Example of erroneous code:
```compile_fail ```compile_fail,E0500
fn you_know_nothing(jon_snow: &mut i32) { fn you_know_nothing(jon_snow: &mut i32) {
let nights_watch = || { let nights_watch = &jon_snow;
*jon_snow = 2;
};
let starks = || { let starks = || {
*jon_snow = 3; // error: closure requires unique access to `jon_snow` *jon_snow = 3; // error: closure requires unique access to `jon_snow`
// but it is already borrowed // but it is already borrowed
}; };
println!("{}", nights_watch);
} }
``` ```
In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it In here, `jon_snow` is already borrowed by the `nights_watch` reference, so it
cannot be borrowed by the `starks` closure at the same time. To fix this issue, cannot be borrowed by the `starks` closure at the same time. To fix this issue,
you can put the closure in its own scope: you can create the closure after the borrow has ended:
``` ```
fn you_know_nothing(jon_snow: &mut i32) { fn you_know_nothing(jon_snow: &mut i32) {
{ let nights_watch = &jon_snow;
let nights_watch = || { println!("{}", nights_watch);
*jon_snow = 2;
};
} // At this point, `jon_snow` is free.
let starks = || { let starks = || {
*jon_snow = 3; *jon_snow = 3;
}; };
@ -1261,12 +1266,10 @@ closures:
``` ```
fn you_know_nothing(jon_snow: &mut i32) { fn you_know_nothing(jon_snow: &mut i32) {
let mut jon_copy = jon_snow.clone(); let mut jon_copy = jon_snow.clone();
let nights_watch = || {
jon_copy = 2;
};
let starks = || { let starks = || {
*jon_snow = 3; *jon_snow = 3;
}; };
println!("{}", jon_copy);
} }
``` ```
"##, "##,
@ -1293,26 +1296,28 @@ fn outside_closure(x: &mut i32) {
} }
fn foo(a: &mut i32) { fn foo(a: &mut i32) {
let bar = || { let mut bar = || {
inside_closure(a) inside_closure(a)
}; };
outside_closure(a); // error: cannot borrow `*a` as mutable because previous outside_closure(a); // error: cannot borrow `*a` as mutable because previous
// closure requires unique access. // closure requires unique access.
bar();
} }
``` ```
To fix this error, you can place the closure in its own scope: To fix this error, you can finish using the closure before using the captured
variable:
``` ```
fn inside_closure(x: &mut i32) {} fn inside_closure(x: &mut i32) {}
fn outside_closure(x: &mut i32) {} fn outside_closure(x: &mut i32) {}
fn foo(a: &mut i32) { fn foo(a: &mut i32) {
{ let mut bar = || {
let bar = || { inside_closure(a)
inside_closure(a) };
}; bar();
} // borrow on `a` ends. // borrow on `a` ends.
outside_closure(a); // ok! outside_closure(a); // ok!
} }
``` ```
@ -1324,7 +1329,7 @@ fn inside_closure(x: &mut i32) {}
fn outside_closure(x: &mut i32) {} fn outside_closure(x: &mut i32) {}
fn foo(a: &mut i32) { fn foo(a: &mut i32) {
let bar = |s: &mut i32| { let mut bar = |s: &mut i32| {
inside_closure(s) inside_closure(s)
}; };
outside_closure(a); outside_closure(a);
@ -1340,9 +1345,10 @@ fn outside_closure(x: &mut i32) {}
fn foo(a: &mut i32) { fn foo(a: &mut i32) {
outside_closure(a); outside_closure(a);
let bar = || { let mut bar = || {
inside_closure(a) inside_closure(a)
}; };
bar();
} }
``` ```
"##, "##,
@ -1359,6 +1365,7 @@ fn foo(a: &mut i32) {
let ref y = a; // a is borrowed as immutable. let ref y = a; // a is borrowed as immutable.
bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
// as immutable // as immutable
println!("{}", y);
} }
``` ```
@ -1370,6 +1377,7 @@ fn bar(x: &mut i32) {}
fn foo(a: &mut i32) { fn foo(a: &mut i32) {
bar(a); bar(a);
let ref y = a; // ok! let ref y = a; // ok!
println!("{}", y);
} }
``` ```
@ -1385,11 +1393,11 @@ Example of erroneous code:
```compile_fail,E0503 ```compile_fail,E0503
fn main() { fn main() {
let mut value = 3; let mut value = 3;
// Create a mutable borrow of `value`. This borrow // Create a mutable borrow of `value`.
// lives until the end of this function. let borrow = &mut value;
let _borrow = &mut value;
let _sum = value + 1; // error: cannot use `value` because let _sum = value + 1; // error: cannot use `value` because
// it was mutably borrowed // it was mutably borrowed
println!("{}", borrow);
} }
``` ```
@ -1397,16 +1405,14 @@ In this example, `value` is mutably borrowed by `borrow` and cannot be
used to calculate `sum`. This is not possible because this would violate used to calculate `sum`. This is not possible because this would violate
Rust's mutability rules. Rust's mutability rules.
You can fix this error by limiting the scope of the borrow: You can fix this error by finishing using the borrow before the next use of
the value:
``` ```
fn main() { fn main() {
let mut value = 3; let mut value = 3;
// By creating a new block, you can limit the scope let borrow = &mut value;
// of the reference. println!("{}", borrow);
{
let _borrow = &mut value; // Use `_borrow` inside this block.
}
// The block has ended and with it the borrow. // The block has ended and with it the borrow.
// You can now use `value` again. // You can now use `value` again.
let _sum = value + 1; let _sum = value + 1;
@ -1422,10 +1428,11 @@ fn main() {
let value_cloned = value.clone(); let value_cloned = value.clone();
// The mutable borrow is a reference to `value` and // The mutable borrow is a reference to `value` and
// not to `value_cloned`... // not to `value_cloned`...
let _borrow = &mut value; let borrow = &mut value;
// ... which means we can still use `value_cloned`, // ... which means we can still use `value_cloned`,
let _sum = value_cloned + 1; let _sum = value_cloned + 1;
// even though the borrow only ends here. // even though the borrow only ends here.
println!("{}", borrow);
} }
``` ```
@ -1434,12 +1441,14 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
"##, "##,
E0504: r##" E0504: r##"
#### Note: this error code is no longer emitted by the compiler.
This error occurs when an attempt is made to move a borrowed variable into a This error occurs when an attempt is made to move a borrowed variable into a
closure. closure.
Example of erroneous code: Example of erroneous code:
```compile_fail,E0504 ```compile_fail
struct FancyNum { struct FancyNum {
num: u8, num: u8,
} }
@ -1577,9 +1586,10 @@ fn eat(val: &Value) {}
fn main() { fn main() {
let x = Value{}; let x = Value{};
let _ref_to_val: &Value = &x;
let ref_to_val: &Value = &x;
eat(&x); // pass by reference, if it's possible eat(&x); // pass by reference, if it's possible
borrow(_ref_to_val); borrow(ref_to_val);
} }
``` ```
@ -1594,11 +1604,11 @@ fn eat(val: Value) {}
fn main() { fn main() {
let x = Value{}; let x = Value{};
{
let _ref_to_val: &Value = &x; let ref_to_val: &Value = &x;
borrow(_ref_to_val); borrow(ref_to_val);
} // ref_to_val is no longer used.
eat(x); // release borrow and then move it. eat(x);
} }
``` ```
@ -1614,9 +1624,9 @@ fn eat(val: Value) {}
fn main() { fn main() {
let x = Value{}; let x = Value{};
let _ref_to_val: &Value = &x; let ref_to_val: &Value = &x;
eat(x); // it will be copied here. eat(x); // it will be copied here.
borrow(_ref_to_val); borrow(ref_to_val);
} }
``` ```
@ -2053,11 +2063,13 @@ fn get_owned_iterator() -> IntoIter<i32> {
"##, "##,
E0595: r##" E0595: r##"
#### Note: this error code is no longer emitted by the compiler.
Closures cannot mutate immutable captured variables. Closures cannot mutate immutable captured variables.
Erroneous code example: Erroneous code example:
```compile_fail,E0595 ```compile_fail,E0594
let x = 3; // error: closure cannot assign to immutable local variable `x` let x = 3; // error: closure cannot assign to immutable local variable `x`
let mut c = || { x += 1 }; let mut c = || { x += 1 };
``` ```
@ -2090,8 +2102,7 @@ let y = &mut x; // ok!
"##, "##,
E0597: r##" E0597: r##"
This error occurs because a borrow was made inside a variable which has a This error occurs because a value was dropped while it was still borrowed
greater lifetime than the borrowed one.
Example of erroneous code: Example of erroneous code:
@ -2101,23 +2112,28 @@ struct Foo<'a> {
} }
let mut x = Foo { x: None }; let mut x = Foo { x: None };
let y = 0; {
x.x = Some(&y); // error: `y` does not live long enough let y = 0;
x.x = Some(&y); // error: `y` does not live long enough
}
println!("{:?}", x.x);
``` ```
In here, `x` is created before `y` and therefore has a greater lifetime. Always In here, `y` is dropped at the end of the inner scope, but it is borrowed by
keep in mind that values in a scope are dropped in the opposite order they are `x` until the `println`. To fix the previous example, just remove the scope
created. So to fix the previous example, just make the `y` lifetime greater than so that `y` isn't dropped until after the println
the `x`'s one:
``` ```
struct Foo<'a> { struct Foo<'a> {
x: Option<&'a u32>, x: Option<&'a u32>,
} }
let y = 0;
let mut x = Foo { x: None }; let mut x = Foo { x: None };
let y = 0;
x.x = Some(&y); x.x = Some(&y);
println!("{:?}", x.x);
``` ```
"##, "##,

View file

@ -565,7 +565,7 @@ fn check_legality_of_move_bindings(
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008, let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
"cannot bind by-move into a pattern guard"); "cannot bind by-move into a pattern guard");
err.span_label(p.span, "moves value into pattern guard"); err.span_label(p.span, "moves value into pattern guard");
if cx.tcx.sess.opts.unstable_features.is_nightly_build() && cx.tcx.use_mir_borrowck() { if cx.tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add #![feature(bind_by_move_pattern_guards)] to the \ err.help("add #![feature(bind_by_move_pattern_guards)] to the \
crate attributes to enable"); crate attributes to enable");
} }
@ -649,9 +649,7 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301, let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301,
"cannot mutably borrow in a pattern guard"); "cannot mutably borrow in a pattern guard");
err.span_label(span, "borrowed mutably in pattern guard"); err.span_label(span, "borrowed mutably in pattern guard");
if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() && if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() {
self.cx.tcx.use_mir_borrowck()
{
err.help("add #![feature(bind_by_move_pattern_guards)] to the \ err.help("add #![feature(bind_by_move_pattern_guards)] to the \
crate attributes to enable"); crate attributes to enable");
} }

View file

@ -40,7 +40,7 @@ impl Origin {
pub fn should_emit_errors(self, mode: BorrowckMode) -> bool { pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
match self { match self {
Origin::Ast => mode.use_ast(), Origin::Ast => mode.use_ast(),
Origin::Mir => mode.use_mir(), Origin::Mir => true,
} }
} }
} }

View file

@ -445,9 +445,7 @@ declare_features! (
(active, custom_inner_attributes, "1.30.0", Some(54726), None), (active, custom_inner_attributes, "1.30.0", Some(54726), None),
// Allow mixing of bind-by-move in patterns and references to // Allow mixing of bind-by-move in patterns and references to
// those identifiers in guards, *if* we are using MIR-borrowck // those identifiers in guards.
// (aka NLL). Essentially this means you need to be using the
// 2018 edition or later.
(active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
// Allows `impl Trait` in bindings (`let`, `const`, `static`). // Allows `impl Trait` in bindings (`let`, `const`, `static`).