Enable migrate mode by default on the 2015 edition
This also fully stabilizes two-phase borrows on all editions
This commit is contained in:
parent
31a75a1728
commit
aa6fb6caf9
@ -92,8 +92,8 @@ impl SuppressRegionErrors {
|
||||
/// 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
|
||||
|
@ -460,7 +460,6 @@ pub enum PrintRequest {
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum BorrowckMode {
|
||||
Ast,
|
||||
Mir,
|
||||
Compare,
|
||||
Migrate,
|
||||
@ -471,7 +470,6 @@ impl BorrowckMode {
|
||||
/// 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 @@ impl BorrowckMode {
|
||||
/// 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 @@ impl Default for Options {
|
||||
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 @@ pub fn build_session_options_and_crate_config(
|
||||
}));
|
||||
|
||||
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)),
|
||||
};
|
||||
|
||||
|
@ -70,7 +70,6 @@ use rustc_macros::HashStable;
|
||||
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// 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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// 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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
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 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
// 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]
|
||||
|
@ -49,8 +49,6 @@ pub mod gather_loans;
|
||||
|
||||
pub mod move_data;
|
||||
|
||||
mod unused;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
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);
|
||||
}
|
||||
|
||||
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(),
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
@ -303,9 +303,8 @@ impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
|
||||
/// 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
|
||||
|
@ -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);
|
||||
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 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||
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.
|
||||
|
@ -474,10 +474,6 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> {
|
||||
&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.
|
||||
|
@ -2672,9 +2672,8 @@ impl MirPass for TypeckMir {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -15,9 +15,8 @@ pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>(
|
||||
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
|
||||
|
@ -112,11 +112,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
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 {
|
||||
|
@ -1425,26 +1425,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// 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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
),
|
||||
);
|
||||
|
||||
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 @@ 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(
|
||||
&mut self,
|
||||
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 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.
|
||||
|
@ -877,12 +877,14 @@ https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html
|
||||
"##,
|
||||
|
||||
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 @@ y.set(2);
|
||||
"##,*/
|
||||
|
||||
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 @@ E0388 was removed and is no longer issued.
|
||||
"##,
|
||||
|
||||
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 @@ A variable was borrowed as mutable more than once. Erroneous code example:
|
||||
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 mut i = 0;
|
||||
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 @@ 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;
|
||||
};
|
||||
println!("{}", jon_copy);
|
||||
}
|
||||
```
|
||||
"##,
|
||||
@ -1293,26 +1296,28 @@ fn outside_closure(x: &mut i32) {
|
||||
}
|
||||
|
||||
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 inside_closure(x: &mut i32) {}
|
||||
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 outside_closure(x: &mut i32) {}
|
||||
|
||||
fn foo(a: &mut i32) {
|
||||
outside_closure(a);
|
||||
let bar = || {
|
||||
let mut bar = || {
|
||||
inside_closure(a)
|
||||
};
|
||||
bar();
|
||||
}
|
||||
```
|
||||
"##,
|
||||
@ -1359,6 +1365,7 @@ 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
|
||||
println!("{}", y);
|
||||
}
|
||||
```
|
||||
|
||||
@ -1370,6 +1377,7 @@ fn bar(x: &mut i32) {}
|
||||
fn foo(a: &mut i32) {
|
||||
bar(a);
|
||||
let ref y = a; // ok!
|
||||
println!("{}", y);
|
||||
}
|
||||
```
|
||||
|
||||
@ -1385,11 +1393,11 @@ 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;
|
||||
// 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 @@ 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:
|
||||
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 @@ fn main() {
|
||||
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 @@ http://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
|
||||
"##,
|
||||
|
||||
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 eat(val: &Value) {}
|
||||
|
||||
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 eat(val: Value) {}
|
||||
|
||||
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 eat(val: Value) {}
|
||||
|
||||
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 @@ fn get_owned_iterator() -> IntoIter<i32> {
|
||||
"##,
|
||||
|
||||
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 @@ let y = &mut x; // ok!
|
||||
"##,
|
||||
|
||||
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 @@ struct Foo<'a> {
|
||||
}
|
||||
|
||||
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);
|
||||
```
|
||||
"##,
|
||||
|
||||
|
@ -565,7 +565,7 @@ fn check_legality_of_move_bindings(
|
||||
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 @@ impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> {
|
||||
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");
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ impl Origin {
|
||||
pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
|
||||
match self {
|
||||
Origin::Ast => mode.use_ast(),
|
||||
Origin::Mir => mode.use_mir(),
|
||||
Origin::Mir => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -445,9 +445,7 @@ declare_features! (
|
||||
(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`).
|
||||
|
Loading…
x
Reference in New Issue
Block a user