Enable migrate mode by default on the 2015 edition
This also fully stabilizes two-phase borrows on all editions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 16140d0..747f0a6 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -92,8 +92,8 @@
/// enabled.
pub fn when_nll_is_enabled(tcx: TyCtxt<'_, '_, '_>) -> Self {
match tcx.borrowck_mode() {
- // If we're on AST or Migrate mode, report AST region errors
- BorrowckMode::Ast | BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false },
+ // If we're on Migrate mode, report AST region errors
+ BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false },
// If we're on MIR or Compare mode, don't report AST region errors as they should
// be reported by NLL
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 97a1c83..cb30780 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -460,7 +460,6 @@
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum BorrowckMode {
- Ast,
Mir,
Compare,
Migrate,
@@ -471,7 +470,6 @@
/// on the AST borrow check if the MIR-based one errors.
pub fn migrate(self) -> bool {
match self {
- BorrowckMode::Ast => false,
BorrowckMode::Compare => false,
BorrowckMode::Mir => false,
BorrowckMode::Migrate => true,
@@ -481,21 +479,11 @@
/// Should we emit the AST-based borrow checker errors?
pub fn use_ast(self) -> bool {
match self {
- BorrowckMode::Ast => true,
BorrowckMode::Compare => true,
BorrowckMode::Mir => 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 {
@@ -627,7 +615,7 @@
incremental: None,
debugging_opts: basic_debugging_options(),
prints: Vec::new(),
- borrowck_mode: BorrowckMode::Ast,
+ borrowck_mode: BorrowckMode::Migrate,
cg: basic_codegen_options(),
error_format: ErrorOutputType::default(),
externs: Externs(BTreeMap::new()),
@@ -2326,10 +2314,9 @@
}));
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("compare") => BorrowckMode::Compare,
- Some("migrate") => BorrowckMode::Migrate,
Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
};
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 1ce9ffd..ed500d1 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -70,7 +70,6 @@
use syntax::ast;
use syntax::attr;
use syntax::source_map::MultiSpan;
-use syntax::edition::Edition;
use syntax::feature_gate;
use syntax::symbol::{Symbol, keywords, InternedString};
use syntax_pos::Span;
@@ -1496,21 +1495,13 @@
/// because that method has a narrower effect that can be toggled
/// off via a separate `-Z` flag, at least for the short term.
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
/// guard could perform bad mutations (or mutable-borrows).
pub fn check_for_mutation_in_guard_via_ast_walk(self) -> bool {
- // If someone requests the feature, then be a little more
- // 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;
+ !self.allow_bind_by_move_patterns_with_guards()
}
/// If true, we should use the AST-based borrowck (we may *also* use
@@ -1519,12 +1510,6 @@
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
/// fall back on the AST borrow check if the MIR-based one errors.
pub fn migrate_borrowck(self) -> bool {
@@ -1541,23 +1526,7 @@
/// statements (which simulate the maximal effect of executing the
/// patterns in a match arm).
pub fn emit_read_for_match(&self) -> bool {
- self.use_mir_borrowck() && !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
+ !self.sess.opts.debugging_opts.nll_dont_emit_read_for_match
}
/// What mode(s) of borrowck should we run? AST? MIR? both?
@@ -1565,14 +1534,10 @@
pub fn borrowck_mode(&self) -> BorrowckMode {
// 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.
- // (This is arguably a historical accident.)
//
- // 2. `BorrowckMode::Migrate` is the limited migration to
- // NLL that we are deploying with the 2018 edition.
- //
- // 3. We want to allow developers on the Nightly channel
+ // 2. We want to allow developers on the Nightly channel
// to opt back into the "hard error" mode for NLL,
// (which they can do via specifying `#![feature(nll)]`
// explicitly in their crate).
@@ -1585,24 +1550,13 @@
// a user's attempt to specify `-Z borrowck=compare`, which
// we arguably do not need anymore and should remove.)
//
- // * Otherwise, if no `-Z borrowck=...` flag was given (or
- // if `borrowck=ast` was specified), then use the default
- // as required by the edition.
+ // * Otherwise, if no `-Z borrowck=...` then use migrate mode
//
// * Otherwise, use the behavior requested via `-Z borrowck=...`
if self.features().nll { return BorrowckMode::Mir; }
- match 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,
- },
- }
+ self.sess.opts.borrowck_mode
}
#[inline]
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index a2f6d97..540f374 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -49,8 +49,6 @@
pub mod move_data;
-mod unused;
-
#[derive(Clone, Copy)]
pub struct LoanDataFlowOperator;
@@ -138,10 +136,6 @@
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 {
used_mut_nodes: bccx.used_mut_nodes.into_inner(),
signalled_any_error: bccx.signalled_any_error.into_inner(),
diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs
deleted file mode 100644
index 60a9c18..0000000
--- a/src/librustc_borrowck/borrowck/unused.rs
+++ /dev/null
@@ -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));
- }
-}
diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs
index c81da66..9181923 100644
--- a/src/librustc_mir/borrow_check/borrow_set.rs
+++ b/src/librustc_mir/borrow_check/borrow_set.rs
@@ -303,9 +303,8 @@
/// allowed to be split into separate Reservation and
/// Activation phases.
fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
- self.tcx.two_phase_borrows()
- && (kind.allows_two_phase_borrow()
- || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
+ kind.allows_two_phase_borrow()
+ || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref
}
/// If this is a two-phase borrow, then we will record it
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 43ed85d..4a3159d 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -74,37 +74,28 @@
let input_mir = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
- let mut return_early;
-
- // Return early if we are not supposed to use MIR borrow checker for this function.
- return_early = !tcx.has_attr(def_id, "rustc_mir") && !tcx.use_mir_borrowck();
-
+ // 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.
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 {
closure_requirements: None,
used_mut_upvars: SmallVec::new(),
@@ -1505,10 +1496,6 @@
span: Span,
flow_state: &Flows<'cx, 'gcx, 'tcx>,
) {
- if !self.infcx.tcx.two_phase_borrows() {
- return;
- }
-
// Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with
// another borrow.
diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs
index 36d3a03..a5230e6 100644
--- a/src/librustc_mir/borrow_check/nll/invalidation.rs
+++ b/src/librustc_mir/borrow_check/nll/invalidation.rs
@@ -474,10 +474,6 @@
&mut self,
location: Location,
) {
- if !self.tcx.two_phase_borrows() {
- return;
- }
-
// Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with
// another borrow.
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index ce8f185..0dee64d 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -2672,9 +2672,8 @@
let def_id = src.def_id();
debug!("run_pass: {:?}", def_id);
- // When NLL is enabled, the borrow checker runs the typeck
- // itself, so we don't need this MIR pass anymore.
- if tcx.use_mir_borrowck() {
+ // FIXME: We don't need this MIR pass anymore.
+ if true {
return;
}
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 42eb502..c68dee2 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -15,9 +15,8 @@
tcx: &TyCtxt<'a, 'gcx, 'tcx>,
kind: BorrowKind
) -> bool {
- tcx.two_phase_borrows()
- && (kind.allows_two_phase_borrow()
- || tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
+ kind.allows_two_phase_borrow()
+ || tcx.sess.opts.debugging_opts.two_phase_beyond_autoref
}
/// Control for the path borrow checking code
diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs
index b500060..713e3fe 100644
--- a/src/librustc_mir/build/expr/as_place.rs
+++ b/src/librustc_mir/build/expr/as_place.rs
@@ -112,11 +112,7 @@
}
ExprKind::SelfRef => block.and(Place::Base(PlaceBase::Local(Local::new(1)))),
ExprKind::VarRef { id } => {
- let place = if this.is_bound_var_in_guard(id) && this
- .hir
- .tcx()
- .all_pat_vars_are_implicit_refs_within_guards()
- {
+ let place = if this.is_bound_var_in_guard(id) {
let index = this.var_local_id(id, RefWithinGuard);
Place::Base(PlaceBase::Local(index)).deref()
} else {
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 566f179..b5b2d78 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -1425,26 +1425,22 @@
// the reference that we create for the arm.
// * So we eagerly create the reference for the arm and then take a
// 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 autoref {
- self.bind_matched_candidate_for_guard(
- block,
- &candidate.bindings,
- );
- let guard_frame = GuardFrame {
- locals: candidate
- .bindings
- .iter()
- .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode))
- .collect(),
- };
- debug!("Entering guard building context: {:?}", guard_frame);
- self.guard_context.push(guard_frame);
- } else {
- self.bind_matched_candidate_for_arm_body(block, &candidate.bindings);
- }
+ let tcx = self.hir.tcx();
+
+ self.bind_matched_candidate_for_guard(
+ block,
+ &candidate.bindings,
+ );
+ let guard_frame = GuardFrame {
+ locals: candidate
+ .bindings
+ .iter()
+ .map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode))
+ .collect(),
+ };
+ debug!("Entering guard building context: {:?}", guard_frame);
+ self.guard_context.push(guard_frame);
let re_erased = tcx.types.re_erased;
let scrutinee_source_info = self.source_info(scrutinee_span);
@@ -1470,13 +1466,11 @@
let source_info = self.source_info(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));
- if autoref {
- let guard_frame = self.guard_context.pop().unwrap();
- debug!(
- "Exiting guard building context with locals: {:?}",
- guard_frame
- );
- }
+ let guard_frame = self.guard_context.pop().unwrap();
+ debug!(
+ "Exiting guard building context with locals: {:?}",
+ guard_frame
+ );
for &(_, temp) in fake_borrows {
self.cfg.push(block, Statement {
@@ -1526,28 +1520,26 @@
),
);
- if autoref {
- let by_value_bindings = candidate.bindings.iter().filter(|binding| {
- if let BindingMode::ByValue = binding.binding_mode { true } else { false }
- });
- // Read all of the by reference bindings to ensure that the
- // place they refer to can't be modified by the guard.
- for binding in by_value_bindings.clone() {
- let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
+ let by_value_bindings = candidate.bindings.iter().filter(|binding| {
+ if let BindingMode::ByValue = binding.binding_mode { true } else { false }
+ });
+ // Read all of the by reference bindings to ensure that the
+ // place they refer to can't be modified by the guard.
+ for binding in by_value_bindings.clone() {
+ let local_id = self.var_local_id(binding.var_id, RefWithinGuard);
let place = Place::Base(PlaceBase::Local(local_id));
- self.cfg.push(
- block,
- Statement {
- source_info: guard_end,
- kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place),
- },
- );
- }
- self.bind_matched_candidate_for_arm_body(
- post_guard_block,
- by_value_bindings,
+ self.cfg.push(
+ block,
+ Statement {
+ source_info: guard_end,
+ kind: StatementKind::FakeRead(FakeReadCause::ForGuardBinding, place),
+ },
);
}
+ self.bind_matched_candidate_for_arm_body(
+ post_guard_block,
+ by_value_bindings,
+ );
self.cfg.terminate(
post_guard_block,
@@ -1604,8 +1596,6 @@
}
}
- // 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(
&mut self,
block: BasicBlock,
@@ -1739,7 +1729,7 @@
}))),
};
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> {
// This variable isn't mutated but has a name, so has to be
// immutable to avoid the unused mut lint.
diff --git a/src/librustc_mir/error_codes.rs b/src/librustc_mir/error_codes.rs
index c8836fe..74a4278 100644
--- a/src/librustc_mir/error_codes.rs
+++ b/src/librustc_mir/error_codes.rs
@@ -877,12 +877,14 @@
"##,
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
structure that is currently uninitialized.
For example, this can happen when a drop has taken place:
-```compile_fail,E0383
+```compile_fail
struct Foo {
a: u32,
}
@@ -966,10 +968,12 @@
"##,*/
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
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.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }
@@ -1026,13 +1030,15 @@
"##,
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
commonly occurs when attempting to assign to a non-mutable reference of a
mutable reference (`&(&mut T)`).
Example of erroneous code:
-```compile_fail,E0389
+```compile_fail
struct FancyNum {
num: u8,
}
@@ -1202,6 +1208,7 @@
let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;
+x;
// error: cannot borrow `i` as mutable more than once at a time
```
@@ -1220,35 +1227,33 @@
let a = &i; // ok!
let b = &i; // still ok!
let c = &i; // still ok!
+b;
+a;
```
"##,
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) {
- let nights_watch = || {
- *jon_snow = 2;
- };
+ let nights_watch = &jon_snow;
let starks = || {
*jon_snow = 3; // error: closure requires unique access to `jon_snow`
// 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,
-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) {
- {
- let nights_watch = || {
- *jon_snow = 2;
- };
- } // At this point, `jon_snow` is free.
+ let nights_watch = &jon_snow;
+ println!("{}", nights_watch);
let starks = || {
*jon_snow = 3;
};
@@ -1261,12 +1266,10 @@
```
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;
};
+ println!("{}", jon_copy);
}
```
"##,
@@ -1293,26 +1296,28 @@
}
fn foo(a: &mut i32) {
- let bar = || {
+ let mut bar = || {
inside_closure(a)
};
outside_closure(a); // error: cannot borrow `*a` as mutable because previous
// 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 outside_closure(x: &mut i32) {}
fn foo(a: &mut i32) {
- {
- let bar = || {
- inside_closure(a)
- };
- } // borrow on `a` ends.
+ let mut bar = || {
+ inside_closure(a)
+ };
+ bar();
+ // borrow on `a` ends.
outside_closure(a); // ok!
}
```
@@ -1324,7 +1329,7 @@
fn outside_closure(x: &mut i32) {}
fn foo(a: &mut i32) {
- let bar = |s: &mut i32| {
+ let mut bar = |s: &mut i32| {
inside_closure(s)
};
outside_closure(a);
@@ -1340,9 +1345,10 @@
fn foo(a: &mut i32) {
outside_closure(a);
- let bar = || {
+ let mut bar = || {
inside_closure(a)
};
+ bar();
}
```
"##,
@@ -1359,6 +1365,7 @@
let ref y = a; // a is borrowed as immutable.
bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
// as immutable
+ println!("{}", y);
}
```
@@ -1370,6 +1377,7 @@
fn foo(a: &mut i32) {
bar(a);
let ref y = a; // ok!
+ println!("{}", y);
}
```
@@ -1385,11 +1393,11 @@
```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;
+ // Create a mutable borrow of `value`.
+ let borrow = &mut value;
let _sum = value + 1; // error: cannot use `value` because
// it was mutably borrowed
+ println!("{}", borrow);
}
```
@@ -1397,16 +1405,14 @@
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:
+You can fix this error by finishing using the borrow before the next use of
+the value:
```
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.
- }
+ let borrow = &mut value;
+ println!("{}", borrow);
// The block has ended and with it the borrow.
// You can now use `value` again.
let _sum = value + 1;
@@ -1422,10 +1428,11 @@
let value_cloned = value.clone();
// The mutable borrow is a reference to `value` and
// not to `value_cloned`...
- let _borrow = &mut value;
+ let borrow = &mut value;
// ... which means we can still use `value_cloned`,
let _sum = value_cloned + 1;
// even though the borrow only ends here.
+ println!("{}", borrow);
}
```
@@ -1434,12 +1441,14 @@
"##,
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
closure.
Example of erroneous code:
-```compile_fail,E0504
+```compile_fail
struct FancyNum {
num: u8,
}
@@ -1577,9 +1586,10 @@
fn main() {
let x = Value{};
- let _ref_to_val: &Value = &x;
+
+ let ref_to_val: &Value = &x;
eat(&x); // pass by reference, if it's possible
- borrow(_ref_to_val);
+ borrow(ref_to_val);
}
```
@@ -1594,11 +1604,11 @@
fn main() {
let x = Value{};
- {
- let _ref_to_val: &Value = &x;
- borrow(_ref_to_val);
- }
- eat(x); // release borrow and then move it.
+
+ let ref_to_val: &Value = &x;
+ borrow(ref_to_val);
+ // ref_to_val is no longer used.
+ eat(x);
}
```
@@ -1614,9 +1624,9 @@
fn main() {
let x = Value{};
- let _ref_to_val: &Value = &x;
+ let ref_to_val: &Value = &x;
eat(x); // it will be copied here.
- borrow(_ref_to_val);
+ borrow(ref_to_val);
}
```
@@ -2053,11 +2063,13 @@
"##,
E0595: r##"
+#### Note: this error code is no longer emitted by the compiler.
+
Closures cannot mutate immutable captured variables.
Erroneous code example:
-```compile_fail,E0595
+```compile_fail,E0594
let x = 3; // error: closure cannot assign to immutable local variable `x`
let mut c = || { x += 1 };
```
@@ -2090,8 +2102,7 @@
"##,
E0597: r##"
-This error occurs because a borrow was made inside a variable which has a
-greater lifetime than the borrowed one.
+This error occurs because a value was dropped while it was still borrowed
Example of erroneous code:
@@ -2101,23 +2112,28 @@
}
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
-keep in mind that values in a scope are dropped in the opposite order they are
-created. So to fix the previous example, just make the `y` lifetime greater than
-the `x`'s one:
+In here, `y` is dropped at the end of the inner scope, but it is borrowed by
+`x` until the `println`. To fix the previous example, just remove the scope
+so that `y` isn't dropped until after the println
```
struct Foo<'a> {
x: Option<&'a u32>,
}
-let y = 0;
let mut x = Foo { x: None };
+
+let y = 0;
x.x = Some(&y);
+
+println!("{:?}", x.x);
```
"##,
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 7ded973..7bfb0a4 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -565,7 +565,7 @@
let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
"cannot bind by-move into a 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 \
crate attributes to enable");
}
@@ -649,9 +649,7 @@
let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301,
"cannot mutably borrow in a pattern guard");
err.span_label(span, "borrowed mutably in pattern guard");
- if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() &&
- self.cx.tcx.use_mir_borrowck()
- {
+ if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add #![feature(bind_by_move_pattern_guards)] to the \
crate attributes to enable");
}
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index fd694dd..e334e27 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -40,7 +40,7 @@
pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
match self {
Origin::Ast => mode.use_ast(),
- Origin::Mir => mode.use_mir(),
+ Origin::Mir => true,
}
}
}
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index bc87a88..ba567a1 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -445,9 +445,7 @@
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
// Allow mixing of bind-by-move in patterns and references to
- // those identifiers in guards, *if* we are using MIR-borrowck
- // (aka NLL). Essentially this means you need to be using the
- // 2018 edition or later.
+ // those identifiers in guards.
(active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
// Allows `impl Trait` in bindings (`let`, `const`, `static`).