Auto merge of #52681 - pnkfelix:z-borrowck-migrate, r=nikomatsakis
Add `-Z borrowck=migrate` This adds `-Z borrowck=migrate`, which represents the way we want to migrate to NLL under Rust versions to come. It also hooks this new mode into `--edition 2018`, which means we're officially turning NLL on in the 2018 edition. The basic idea of `-Z borrowck=migrate` that there are cases where NLL is fixing old soundness bugs in the borrow-checker, but in order to avoid just breaking code by immediately rejecting the programs that hit those soundness bugs, we instead use the following strategy: If your code is accepted by NLL, then we accept it. If your code is rejected by both NLL and the old AST-borrowck, then we reject it. If your code is rejected by NLL but accepted by the old AST-borrowck, then we emit the new NLL errors as **warnings**. These warnings will be turned into hard errors in the future, and they say so in these diagnostics. Fix #46908
This commit is contained in:
commit
b18b9edf00
20 changed files with 380 additions and 80 deletions
|
@ -15,9 +15,15 @@ use util::nodemap::FxHashSet;
|
||||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
|
||||||
StableHasherResult};
|
StableHasherResult};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||||
|
pub enum SignalledError { SawSomeError, NoErrorsSeen }
|
||||||
|
|
||||||
|
impl_stable_hash_for!(enum self::SignalledError { SawSomeError, NoErrorsSeen });
|
||||||
|
|
||||||
#[derive(Debug, RustcEncodable, RustcDecodable)]
|
#[derive(Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct BorrowCheckResult {
|
pub struct BorrowCheckResult {
|
||||||
pub used_mut_nodes: FxHashSet<HirId>,
|
pub used_mut_nodes: FxHashSet<HirId>,
|
||||||
|
pub signalled_any_error: SignalledError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
|
impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
|
||||||
|
@ -26,7 +32,9 @@ impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
|
||||||
hasher: &mut StableHasher<W>) {
|
hasher: &mut StableHasher<W>) {
|
||||||
let BorrowCheckResult {
|
let BorrowCheckResult {
|
||||||
ref used_mut_nodes,
|
ref used_mut_nodes,
|
||||||
|
ref signalled_any_error,
|
||||||
} = *self;
|
} = *self;
|
||||||
used_mut_nodes.hash_stable(hcx, hasher);
|
used_mut_nodes.hash_stable(hcx, hasher);
|
||||||
|
signalled_any_error.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -455,15 +455,28 @@ pub enum BorrowckMode {
|
||||||
Ast,
|
Ast,
|
||||||
Mir,
|
Mir,
|
||||||
Compare,
|
Compare,
|
||||||
|
Migrate,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowckMode {
|
impl BorrowckMode {
|
||||||
|
/// Should we run the MIR-based borrow check, but also fall back
|
||||||
|
/// 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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::Ast => true,
|
||||||
BorrowckMode::Compare => true,
|
BorrowckMode::Compare => true,
|
||||||
BorrowckMode::Mir => false,
|
BorrowckMode::Mir => false,
|
||||||
|
BorrowckMode::Migrate => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Should we emit the MIR-based borrow checker errors?
|
/// Should we emit the MIR-based borrow checker errors?
|
||||||
|
@ -472,6 +485,7 @@ impl BorrowckMode {
|
||||||
BorrowckMode::Ast => false,
|
BorrowckMode::Ast => false,
|
||||||
BorrowckMode::Compare => true,
|
BorrowckMode::Compare => true,
|
||||||
BorrowckMode::Mir => true,
|
BorrowckMode::Mir => true,
|
||||||
|
BorrowckMode::Migrate => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1127,7 +1141,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||||
emit_end_regions: bool = (false, parse_bool, [UNTRACKED],
|
emit_end_regions: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"emit EndRegion as part of MIR; enable transforms that solely process EndRegion"),
|
"emit EndRegion as part of MIR; enable transforms that solely process EndRegion"),
|
||||||
borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
|
||||||
"select which borrowck is used (`ast`, `mir`, or `compare`)"),
|
"select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"),
|
||||||
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
|
two_phase_borrows: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
|
"use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
|
||||||
two_phase_beyond_autoref: bool = (false, parse_bool, [UNTRACKED],
|
two_phase_beyond_autoref: bool = (false, parse_bool, [UNTRACKED],
|
||||||
|
@ -2168,6 +2182,7 @@ pub fn build_session_options_and_crate_config(
|
||||||
None | Some("ast") => BorrowckMode::Ast,
|
None | Some("ast") => BorrowckMode::Ast,
|
||||||
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)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ use rustc_target::spec::abi;
|
||||||
use syntax::ast::{self, NodeId};
|
use syntax::ast::{self, NodeId};
|
||||||
use syntax::attr;
|
use syntax::attr;
|
||||||
use syntax::codemap::MultiSpan;
|
use syntax::codemap::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;
|
||||||
|
@ -1366,6 +1367,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.borrowck_mode().use_mir()
|
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 {
|
||||||
|
self.borrowck_mode().migrate()
|
||||||
|
}
|
||||||
|
|
||||||
/// If true, make MIR codegen for `match` emit a temp that holds a
|
/// If true, make MIR codegen for `match` emit a temp that holds a
|
||||||
/// borrow of the input to the match expression.
|
/// borrow of the input to the match expression.
|
||||||
pub fn generate_borrow_of_any_match_input(&self) -> bool {
|
pub fn generate_borrow_of_any_match_input(&self) -> bool {
|
||||||
|
@ -1397,18 +1404,51 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// What mode(s) of borrowck should we run? AST? MIR? both?
|
/// What mode(s) of borrowck should we run? AST? MIR? both?
|
||||||
/// (Also considers the `#![feature(nll)]` setting.)
|
/// (Also considers the `#![feature(nll)]` setting.)
|
||||||
pub fn borrowck_mode(&self) -> BorrowckMode {
|
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
|
||||||
|
// 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
|
||||||
|
// to opt back into the "hard error" mode for NLL,
|
||||||
|
// (which they can do via specifying `#![feature(nll)]`
|
||||||
|
// explicitly in their crate).
|
||||||
|
//
|
||||||
|
// So, this precedence list is how pnkfelix chose to work with
|
||||||
|
// the above constraints:
|
||||||
|
//
|
||||||
|
// * `#![feature(nll)]` *always* means use NLL with hard
|
||||||
|
// errors. (To simplify the code here, it now even overrides
|
||||||
|
// 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, use the behavior requested via `-Z borrowck=...`
|
||||||
|
|
||||||
|
if self.features().nll { return BorrowckMode::Mir; }
|
||||||
|
|
||||||
match self.sess.opts.borrowck_mode {
|
match self.sess.opts.borrowck_mode {
|
||||||
mode @ BorrowckMode::Mir |
|
mode @ BorrowckMode::Mir |
|
||||||
mode @ BorrowckMode::Compare => mode,
|
mode @ BorrowckMode::Compare |
|
||||||
|
mode @ BorrowckMode::Migrate => mode,
|
||||||
|
|
||||||
mode @ BorrowckMode::Ast => {
|
BorrowckMode::Ast => match self.sess.edition() {
|
||||||
if self.features().nll {
|
Edition::Edition2015 => BorrowckMode::Ast,
|
||||||
BorrowckMode::Mir
|
Edition::Edition2018 => BorrowckMode::Migrate,
|
||||||
} else {
|
|
||||||
mode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// For now, future editions mean Migrate. (But it
|
||||||
|
// would make a lot of sense for it to be changed to
|
||||||
|
// `BorrowckMode::Mir`, depending on how we plan to
|
||||||
|
// time the forcing of full migration to NLL.)
|
||||||
|
_ => BorrowckMode::Migrate,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -447,10 +447,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
.region_scope_tree
|
.region_scope_tree
|
||||||
.yield_in_scope_for_expr(scope,
|
.yield_in_scope_for_expr(scope,
|
||||||
cmt.hir_id,
|
cmt.hir_id,
|
||||||
self.bccx.body) {
|
self.bccx.body)
|
||||||
|
{
|
||||||
self.bccx.cannot_borrow_across_generator_yield(borrow_span,
|
self.bccx.cannot_borrow_across_generator_yield(borrow_span,
|
||||||
yield_span,
|
yield_span,
|
||||||
Origin::Ast).emit();
|
Origin::Ast).emit();
|
||||||
|
self.bccx.signal_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,9 +509,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
new_loan, old_loan, old_loan, new_loan).err();
|
new_loan, old_loan, old_loan, new_loan).err();
|
||||||
|
|
||||||
match (err_old_new, err_new_old) {
|
match (err_old_new, err_new_old) {
|
||||||
(Some(mut err), None) | (None, Some(mut err)) => err.emit(),
|
(Some(mut err), None) | (None, Some(mut err)) => {
|
||||||
|
err.emit();
|
||||||
|
self.bccx.signal_error();
|
||||||
|
}
|
||||||
(Some(mut err_old), Some(mut err_new)) => {
|
(Some(mut err_old), Some(mut err_new)) => {
|
||||||
err_old.emit();
|
err_old.emit();
|
||||||
|
self.bccx.signal_error();
|
||||||
err_new.cancel();
|
err_new.cancel();
|
||||||
}
|
}
|
||||||
(None, None) => return true,
|
(None, None) => return true,
|
||||||
|
@ -695,6 +701,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
loan_span, &self.bccx.loan_path_to_string(&loan_path),
|
loan_span, &self.bccx.loan_path_to_string(&loan_path),
|
||||||
Origin::Ast)
|
Origin::Ast)
|
||||||
.emit();
|
.emit();
|
||||||
|
self.bccx.signal_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -745,6 +752,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
|
self.bccx.signal_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -914,5 +922,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||||
self.bccx.cannot_assign_to_borrowed(
|
self.bccx.cannot_assign_to_borrowed(
|
||||||
span, loan.span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast)
|
span, loan.span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast)
|
||||||
.emit();
|
.emit();
|
||||||
|
self.bccx.signal_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec<Move
|
||||||
"captured outer variable");
|
"captured outer variable");
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
|
bccx.signal_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ use rustc::middle::dataflow::DataFlowContext;
|
||||||
use rustc::middle::dataflow::BitwiseOperator;
|
use rustc::middle::dataflow::BitwiseOperator;
|
||||||
use rustc::middle::dataflow::DataFlowOperator;
|
use rustc::middle::dataflow::DataFlowOperator;
|
||||||
use rustc::middle::dataflow::KillFrom;
|
use rustc::middle::dataflow::KillFrom;
|
||||||
use rustc::middle::borrowck::BorrowCheckResult;
|
use rustc::middle::borrowck::{BorrowCheckResult, SignalledError};
|
||||||
use rustc::hir::def_id::{DefId, LocalDefId};
|
use rustc::hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc::middle::expr_use_visitor as euv;
|
use rustc::middle::expr_use_visitor as euv;
|
||||||
use rustc::middle::mem_categorization as mc;
|
use rustc::middle::mem_categorization as mc;
|
||||||
|
@ -42,7 +42,7 @@ use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
|
||||||
use rustc_mir::util::suggest_ref_mut;
|
use rustc_mir::util::suggest_ref_mut;
|
||||||
use rustc::util::nodemap::FxHashSet;
|
use rustc::util::nodemap::FxHashSet;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::{Cell, RefCell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
|
@ -90,7 +90,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> {
|
||||||
fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
|
fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
|
||||||
-> Lrc<BorrowCheckResult>
|
-> Lrc<BorrowCheckResult>
|
||||||
{
|
{
|
||||||
assert!(tcx.use_ast_borrowck());
|
assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck());
|
||||||
|
|
||||||
debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
|
debug!("borrowck(body_owner_def_id={:?})", owner_def_id);
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
|
||||||
// and do not need borrowchecking.
|
// and do not need borrowchecking.
|
||||||
return Lrc::new(BorrowCheckResult {
|
return Lrc::new(BorrowCheckResult {
|
||||||
used_mut_nodes: FxHashSet(),
|
used_mut_nodes: FxHashSet(),
|
||||||
|
signalled_any_error: SignalledError::NoErrorsSeen,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => { }
|
_ => { }
|
||||||
|
@ -121,6 +122,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
|
||||||
owner_def_id,
|
owner_def_id,
|
||||||
body,
|
body,
|
||||||
used_mut_nodes: RefCell::new(FxHashSet()),
|
used_mut_nodes: RefCell::new(FxHashSet()),
|
||||||
|
signalled_any_error: Cell::new(SignalledError::NoErrorsSeen),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Eventually, borrowck will always read the MIR, but at the
|
// Eventually, borrowck will always read the MIR, but at the
|
||||||
|
@ -154,6 +156,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId)
|
||||||
|
|
||||||
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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,6 +237,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>(
|
||||||
owner_def_id,
|
owner_def_id,
|
||||||
body,
|
body,
|
||||||
used_mut_nodes: RefCell::new(FxHashSet()),
|
used_mut_nodes: RefCell::new(FxHashSet()),
|
||||||
|
signalled_any_error: Cell::new(SignalledError::NoErrorsSeen),
|
||||||
};
|
};
|
||||||
|
|
||||||
let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
|
let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg);
|
||||||
|
@ -257,6 +261,15 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
|
||||||
body: &'tcx hir::Body,
|
body: &'tcx hir::Body,
|
||||||
|
|
||||||
used_mut_nodes: RefCell<FxHashSet<HirId>>,
|
used_mut_nodes: RefCell<FxHashSet<HirId>>,
|
||||||
|
|
||||||
|
signalled_any_error: Cell<SignalledError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<'a, 'tcx: 'a> BorrowckCtxt<'a, 'tcx> {
|
||||||
|
fn signal_error(&self) {
|
||||||
|
self.signalled_any_error.set(SignalledError::SawSomeError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'tcx: 'b> BorrowckErrors<'a> for &'a BorrowckCtxt<'b, 'tcx> {
|
impl<'a, 'b, 'tcx: 'b> BorrowckErrors<'a> for &'a BorrowckCtxt<'b, 'tcx> {
|
||||||
|
@ -645,6 +658,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
.span_label(use_span, format!("use of possibly uninitialized `{}`",
|
.span_label(use_span, format!("use of possibly uninitialized `{}`",
|
||||||
self.loan_path_to_string(lp)))
|
self.loan_path_to_string(lp)))
|
||||||
.emit();
|
.emit();
|
||||||
|
self.signal_error();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -760,6 +774,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
// not considered particularly helpful.
|
// not considered particularly helpful.
|
||||||
|
|
||||||
err.emit();
|
err.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_partial_reinitialization_of_uninitialized_structure(
|
pub fn report_partial_reinitialization_of_uninitialized_structure(
|
||||||
|
@ -770,6 +785,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
&self.loan_path_to_string(lp),
|
&self.loan_path_to_string(lp),
|
||||||
Origin::Ast)
|
Origin::Ast)
|
||||||
.emit();
|
.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report_reassigned_immutable_variable(&self,
|
pub fn report_reassigned_immutable_variable(&self,
|
||||||
|
@ -787,6 +803,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
self.loan_path_to_string(lp)));
|
self.loan_path_to_string(lp)));
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self,
|
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(&self,
|
||||||
|
@ -908,6 +925,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
self.tcx.hir.hir_to_node_id(err.cmt.hir_id)
|
self.tcx.hir.hir_to_node_id(err.cmt.hir_id)
|
||||||
);
|
);
|
||||||
db.emit();
|
db.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
err_out_of_scope(super_scope, sub_scope, cause) => {
|
err_out_of_scope(super_scope, sub_scope, cause) => {
|
||||||
let msg = match opt_loan_path(&err.cmt) {
|
let msg = match opt_loan_path(&err.cmt) {
|
||||||
|
@ -1022,6 +1040,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
db.emit();
|
db.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
|
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
|
||||||
let descr = self.cmt_to_path_or_string(err.cmt);
|
let descr = self.cmt_to_path_or_string(err.cmt);
|
||||||
|
@ -1047,6 +1066,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
"");
|
"");
|
||||||
|
|
||||||
db.emit();
|
db.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1125,6 +1145,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
err.help("closures behind references must be called via `&mut`");
|
err.help("closures behind references must be called via `&mut`");
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a type, if it is an immutable reference, return a suggestion to make it mutable
|
/// Given a type, if it is an immutable reference, return a suggestion to make it mutable
|
||||||
|
@ -1307,6 +1328,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||||
cmt_path_or_string),
|
cmt_path_or_string),
|
||||||
suggestion)
|
suggestion)
|
||||||
.emit();
|
.emit();
|
||||||
|
self.signal_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
|
fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {
|
||||||
|
|
|
@ -99,6 +99,25 @@ impl Diagnostic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_error(&self) -> bool {
|
||||||
|
match self.level {
|
||||||
|
Level::Bug |
|
||||||
|
Level::Fatal |
|
||||||
|
Level::PhaseFatal |
|
||||||
|
Level::Error |
|
||||||
|
Level::FailureNote => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
Level::Warning |
|
||||||
|
Level::Note |
|
||||||
|
Level::Help |
|
||||||
|
Level::Cancelled => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Cancel the diagnostic (a structured diagnostic must either be emitted or
|
/// Cancel the diagnostic (a structured diagnostic must either be emitted or
|
||||||
/// canceled or it will panic when dropped).
|
/// canceled or it will panic when dropped).
|
||||||
pub fn cancel(&mut self) {
|
pub fn cancel(&mut self) {
|
||||||
|
|
|
@ -100,25 +100,6 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||||
buffered_diagnostics.push(diagnostic);
|
buffered_diagnostics.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_error(&self) -> bool {
|
|
||||||
match self.level {
|
|
||||||
Level::Bug |
|
|
||||||
Level::Fatal |
|
|
||||||
Level::PhaseFatal |
|
|
||||||
Level::Error |
|
|
||||||
Level::FailureNote => {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
Level::Warning |
|
|
||||||
Level::Note |
|
|
||||||
Level::Help |
|
|
||||||
Level::Cancelled => {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convenience function for internal use, clients should use one of the
|
/// Convenience function for internal use, clients should use one of the
|
||||||
/// span_* methods instead.
|
/// span_* methods instead.
|
||||||
pub fn sub<S: Into<MultiSpan>>(
|
pub fn sub<S: Into<MultiSpan>>(
|
||||||
|
|
|
@ -16,6 +16,7 @@ use rustc::hir::def_id::DefId;
|
||||||
use rustc::hir::map::definitions::DefPathData;
|
use rustc::hir::map::definitions::DefPathData;
|
||||||
use rustc::infer::InferCtxt;
|
use rustc::infer::InferCtxt;
|
||||||
use rustc::lint::builtin::UNUSED_MUT;
|
use rustc::lint::builtin::UNUSED_MUT;
|
||||||
|
use rustc::middle::borrowck::SignalledError;
|
||||||
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||||
use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place};
|
use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place};
|
||||||
use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
|
use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
|
||||||
|
@ -23,7 +24,7 @@ use rustc::mir::{Terminator, TerminatorKind};
|
||||||
use rustc::ty::query::Providers;
|
use rustc::ty::query::Providers;
|
||||||
use rustc::ty::{self, ParamEnv, TyCtxt};
|
use rustc::ty::{self, ParamEnv, TyCtxt};
|
||||||
|
|
||||||
use rustc_errors::{Diagnostic, DiagnosticBuilder};
|
use rustc_errors::{Diagnostic, DiagnosticBuilder, Level};
|
||||||
use rustc_data_structures::graph::dominators::Dominators;
|
use rustc_data_structures::graph::dominators::Dominators;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||||
|
@ -329,8 +330,34 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for diag in mbcx.errors_buffer.drain(..) {
|
if mbcx.errors_buffer.len() > 0 {
|
||||||
DiagnosticBuilder::new_diagnostic(mbcx.tcx.sess.diagnostic(), diag).emit();
|
if tcx.migrate_borrowck() {
|
||||||
|
match tcx.borrowck(def_id).signalled_any_error {
|
||||||
|
SignalledError::NoErrorsSeen => {
|
||||||
|
// if AST-borrowck signalled no errors, then
|
||||||
|
// downgrade all the buffered MIR-borrowck errors
|
||||||
|
// to warnings.
|
||||||
|
for err in &mut mbcx.errors_buffer {
|
||||||
|
if err.is_error() {
|
||||||
|
err.level = Level::Warning;
|
||||||
|
err.warn("This error has been downgraded to a warning \
|
||||||
|
for backwards compatibility with previous releases.\n\
|
||||||
|
It represents potential unsoundness in your code.\n\
|
||||||
|
This warning will become a hard error in the future.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SignalledError::SawSomeError => {
|
||||||
|
// if AST-borrowck signalled a (cancelled) error,
|
||||||
|
// then we will just emit the buffered
|
||||||
|
// MIR-borrowck errors as normal.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for diag in mbcx.errors_buffer.drain(..) {
|
||||||
|
DiagnosticBuilder::new_diagnostic(mbcx.tcx.sess.diagnostic(), diag).emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = BorrowCheckResult {
|
let result = BorrowCheckResult {
|
||||||
|
@ -1747,20 +1774,44 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Reservation(WriteKind::Move)
|
Reservation(wk @ WriteKind::Move)
|
||||||
| Write(WriteKind::Move)
|
| Write(wk @ WriteKind::Move)
|
||||||
| Reservation(WriteKind::StorageDeadOrDrop)
|
| Reservation(wk @ WriteKind::StorageDeadOrDrop)
|
||||||
| Reservation(WriteKind::MutableBorrow(BorrowKind::Shared))
|
| Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
|
||||||
| Write(WriteKind::StorageDeadOrDrop)
|
| Write(wk @ WriteKind::StorageDeadOrDrop)
|
||||||
| Write(WriteKind::MutableBorrow(BorrowKind::Shared)) => {
|
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => {
|
||||||
if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
|
if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
|
||||||
self.tcx.sess.delay_span_bug(
|
if self.tcx.migrate_borrowck() {
|
||||||
span,
|
// rust-lang/rust#46908: In pure NLL mode this
|
||||||
&format!(
|
// code path should be unreachable (and thus
|
||||||
"Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
|
// we signal an ICE in the else branch
|
||||||
place, kind
|
// here). But we can legitimately get here
|
||||||
),
|
// under borrowck=migrate mode, so instead of
|
||||||
);
|
// ICE'ing we instead report a legitimate
|
||||||
|
// error (which will then be downgraded to a
|
||||||
|
// warning by the migrate machinery).
|
||||||
|
error_access = match wk {
|
||||||
|
WriteKind::MutableBorrow(_) => AccessKind::MutableBorrow,
|
||||||
|
WriteKind::Move => AccessKind::Move,
|
||||||
|
WriteKind::StorageDeadOrDrop |
|
||||||
|
WriteKind::Mutate => AccessKind::Mutate,
|
||||||
|
};
|
||||||
|
self.report_mutability_error(
|
||||||
|
place,
|
||||||
|
span,
|
||||||
|
_place_err,
|
||||||
|
error_access,
|
||||||
|
location,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.tcx.sess.delay_span_bug(
|
||||||
|
span,
|
||||||
|
&format!(
|
||||||
|
"Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
|
||||||
|
place, kind
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ use util::suggest_ref_mut;
|
||||||
pub(super) enum AccessKind {
|
pub(super) enum AccessKind {
|
||||||
MutableBorrow,
|
MutableBorrow,
|
||||||
Mutate,
|
Mutate,
|
||||||
|
Move,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
@ -110,6 +111,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||||
if let Some(desc) = access_place_desc {
|
if let Some(desc) = access_place_desc {
|
||||||
item_msg = format!("`{}`", desc);
|
item_msg = format!("`{}`", desc);
|
||||||
reason = match error_access {
|
reason = match error_access {
|
||||||
|
AccessKind::Move |
|
||||||
AccessKind::Mutate => format!(" which is behind a {}", pointer_type),
|
AccessKind::Mutate => format!(" which is behind a {}", pointer_type),
|
||||||
AccessKind::MutableBorrow => {
|
AccessKind::MutableBorrow => {
|
||||||
format!(", as it is behind a {}", pointer_type)
|
format!(", as it is behind a {}", pointer_type)
|
||||||
|
@ -160,6 +162,13 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
|
|
||||||
let span = match error_access {
|
let span = match error_access {
|
||||||
|
AccessKind::Move => {
|
||||||
|
err = self.tcx
|
||||||
|
.cannot_move_out_of(span, &(item_msg + &reason), Origin::Mir);
|
||||||
|
act = "move";
|
||||||
|
acted_on = "moved";
|
||||||
|
span
|
||||||
|
}
|
||||||
AccessKind::Mutate => {
|
AccessKind::Mutate => {
|
||||||
err = self.tcx
|
err = self.tcx
|
||||||
.cannot_assign(span, &(item_msg + &reason), Origin::Mir);
|
.cannot_assign(span, &(item_msg + &reason), Origin::Mir);
|
||||||
|
|
|
@ -41,7 +41,20 @@ impl MirPass for ElaborateDrops {
|
||||||
|
|
||||||
let id = tcx.hir.as_local_node_id(src.def_id).unwrap();
|
let id = tcx.hir.as_local_node_id(src.def_id).unwrap();
|
||||||
let param_env = tcx.param_env(src.def_id).with_reveal_all();
|
let param_env = tcx.param_env(src.def_id).with_reveal_all();
|
||||||
let move_data = MoveData::gather_moves(mir, tcx).unwrap();
|
let move_data = match MoveData::gather_moves(mir, tcx) {
|
||||||
|
Ok(move_data) => move_data,
|
||||||
|
Err((move_data, _move_errors)) => {
|
||||||
|
// The only way we should be allowing any move_errors
|
||||||
|
// in here is if we are in the migration path for the
|
||||||
|
// NLL-based MIR-borrowck.
|
||||||
|
//
|
||||||
|
// If we are in the migration path, we have already
|
||||||
|
// reported these errors as warnings to the user. So
|
||||||
|
// we will just ignore them here.
|
||||||
|
assert!(tcx.migrate_borrowck());
|
||||||
|
move_data
|
||||||
|
}
|
||||||
|
};
|
||||||
let elaborate_patch = {
|
let elaborate_patch = {
|
||||||
let mir = &*mir;
|
let mir = &*mir;
|
||||||
let env = MoveDataParamEnv {
|
let env = MoveDataParamEnv {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0507]: cannot move out of borrowed content
|
||||||
|
--> $DIR/borrowck-feature-nll-overrides-migrate.rs:32:17
|
||||||
|
|
|
||||||
|
LL | (|| { let bar = foo; bar.take() })();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0507`.
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// This is a test that the `#![feature(nll)]` opt-in overrides the
|
||||||
|
// migration mode. The intention here is to emulate the goal behavior
|
||||||
|
// that `--edition 2018` effects on borrowck (modeled here by `-Z
|
||||||
|
// borrowck=migrate`) are themselves overridden by the
|
||||||
|
// `#![feature(nll)]` opt-in.
|
||||||
|
//
|
||||||
|
// Therefore, for developer convenience, under `#[feature(nll)]` the
|
||||||
|
// NLL checks will be emitted as errors *even* in the presence of `-Z
|
||||||
|
// borrowck=migrate`.
|
||||||
|
|
||||||
|
// revisions: zflag edition
|
||||||
|
// [zflag]compile-flags: -Z borrowck=migrate
|
||||||
|
// [edition]compile-flags: --edition 2018
|
||||||
|
|
||||||
|
#![feature(nll)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match Some(&4) {
|
||||||
|
None => {},
|
||||||
|
ref mut foo
|
||||||
|
if {
|
||||||
|
(|| { let bar = foo; bar.take() })();
|
||||||
|
//[zflag]~^ ERROR cannot move out of borrowed content [E0507]
|
||||||
|
//[edition]~^^ ERROR cannot move out of borrowed content [E0507]
|
||||||
|
false
|
||||||
|
} => {},
|
||||||
|
Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
|
||||||
|
_ => println!("Here is some supposedly unreachable code."),
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
error[E0507]: cannot move out of borrowed content
|
||||||
|
--> $DIR/borrowck-feature-nll-overrides-migrate.rs:32:17
|
||||||
|
|
|
||||||
|
LL | (|| { let bar = foo; bar.take() })();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0507`.
|
24
src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr
Normal file
24
src/test/ui/borrowck/borrowck-migrate-to-nll.edition.stderr
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
warning[E0507]: cannot move out of borrowed content
|
||||||
|
--> $DIR/borrowck-migrate-to-nll.rs:35:17
|
||||||
|
|
|
||||||
|
LL | (|| { let bar = foo; bar.take() })();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
|
||||||
|
|
|
||||||
|
= warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
|
||||||
|
It represents potential unsoundness in your code.
|
||||||
|
This warning will become a hard error in the future.
|
||||||
|
|
||||||
|
warning[E0507]: cannot move out of `foo`, as it is immutable for the pattern guard
|
||||||
|
--> $DIR/borrowck-migrate-to-nll.rs:35:17
|
||||||
|
|
|
||||||
|
LL | (|| { let bar = foo; bar.take() })();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| cannot move out of `foo`, as it is immutable for the pattern guard
|
||||||
|
| cannot move
|
||||||
|
|
|
||||||
|
= note: variables bound in patterns are immutable until the end of the pattern guard
|
||||||
|
= warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
|
||||||
|
It represents potential unsoundness in your code.
|
||||||
|
This warning will become a hard error in the future.
|
||||||
|
|
41
src/test/ui/borrowck/borrowck-migrate-to-nll.rs
Normal file
41
src/test/ui/borrowck/borrowck-migrate-to-nll.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// This is a test of the borrowck migrate mode. It leverages #27282, a
|
||||||
|
// bug that is fixed by NLL: this code is (unsoundly) accepted by
|
||||||
|
// AST-borrowck, but is correctly rejected by the NLL borrowck.
|
||||||
|
//
|
||||||
|
// Therefore, for backwards-compatiblity, under borrowck=migrate the
|
||||||
|
// NLL checks will be emitted as *warnings*.
|
||||||
|
|
||||||
|
// NLL mode makes this compile-fail; we cannot currently encode a
|
||||||
|
// test that is run-pass or compile-fail based on compare-mode. So
|
||||||
|
// just ignore it instead:
|
||||||
|
|
||||||
|
// ignore-compare-mode-nll
|
||||||
|
|
||||||
|
// revisions: zflag edition
|
||||||
|
//[zflag]compile-flags: -Z borrowck=migrate
|
||||||
|
//[edition]compile-flags: --edition 2018
|
||||||
|
//[zflag] run-pass
|
||||||
|
//[edition] run-pass
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match Some(&4) {
|
||||||
|
None => {},
|
||||||
|
ref mut foo
|
||||||
|
if {
|
||||||
|
(|| { let bar = foo; bar.take() })();
|
||||||
|
false
|
||||||
|
} => {},
|
||||||
|
Some(ref _s) => println!("Note this arm is bogus; the `Some` became `None` in the guard."),
|
||||||
|
_ => println!("Here is some supposedly unreachable code."),
|
||||||
|
}
|
||||||
|
}
|
24
src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr
Normal file
24
src/test/ui/borrowck/borrowck-migrate-to-nll.zflag.stderr
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
warning[E0507]: cannot move out of borrowed content
|
||||||
|
--> $DIR/borrowck-migrate-to-nll.rs:35:17
|
||||||
|
|
|
||||||
|
LL | (|| { let bar = foo; bar.take() })();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
|
||||||
|
|
|
||||||
|
= warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
|
||||||
|
It represents potential unsoundness in your code.
|
||||||
|
This warning will become a hard error in the future.
|
||||||
|
|
||||||
|
warning[E0507]: cannot move out of `foo`, as it is immutable for the pattern guard
|
||||||
|
--> $DIR/borrowck-migrate-to-nll.rs:35:17
|
||||||
|
|
|
||||||
|
LL | (|| { let bar = foo; bar.take() })();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| cannot move out of `foo`, as it is immutable for the pattern guard
|
||||||
|
| cannot move
|
||||||
|
|
|
||||||
|
= note: variables bound in patterns are immutable until the end of the pattern guard
|
||||||
|
= warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
|
||||||
|
It represents potential unsoundness in your code.
|
||||||
|
This warning will become a hard error in the future.
|
||||||
|
|
|
@ -8,17 +8,15 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z borrowck=compare
|
|
||||||
|
|
||||||
#![feature(generators)]
|
#![feature(generators)]
|
||||||
#![feature(nll)]
|
#![feature(nll)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|| {
|
|| {
|
||||||
// The reference in `_a` is a Legal with NLL since it ends before the yield
|
// The reference in `_a` is a Legal with NLL since it ends before the yield
|
||||||
let _a = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
|
let _a = &mut true;
|
||||||
let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
|
let b = &mut true;
|
||||||
//~^ borrow may still be in use when generator yields (Mir)
|
//~^ borrow may still be in use when generator yields
|
||||||
yield ();
|
yield ();
|
||||||
println!("{}", b);
|
println!("{}", b);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,30 +1,12 @@
|
||||||
error[E0626]: borrow may still be in use when generator yields (Ast)
|
error[E0626]: borrow may still be in use when generator yields
|
||||||
--> $DIR/generator-with-nll.rs:19:23
|
--> $DIR/generator-with-nll.rs:18:17
|
||||||
|
|
|
|
||||||
LL | let _a = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
|
LL | let b = &mut true;
|
||||||
| ^^^^
|
|
||||||
...
|
|
||||||
LL | yield ();
|
|
||||||
| -------- possible yield occurs here
|
|
||||||
|
|
||||||
error[E0626]: borrow may still be in use when generator yields (Ast)
|
|
||||||
--> $DIR/generator-with-nll.rs:20:22
|
|
||||||
|
|
|
||||||
LL | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
|
|
||||||
| ^^^^
|
|
||||||
LL | //~^ borrow may still be in use when generator yields (Mir)
|
|
||||||
LL | yield ();
|
|
||||||
| -------- possible yield occurs here
|
|
||||||
|
|
||||||
error[E0626]: borrow may still be in use when generator yields (Mir)
|
|
||||||
--> $DIR/generator-with-nll.rs:20:17
|
|
||||||
|
|
|
||||||
LL | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
|
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
LL | //~^ borrow may still be in use when generator yields (Mir)
|
LL | //~^ borrow may still be in use when generator yields
|
||||||
LL | yield ();
|
LL | yield ();
|
||||||
| -------- possible yield occurs here
|
| -------- possible yield occurs here
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to previous error
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0626`.
|
For more information about this error, try `rustc --explain E0626`.
|
||||||
|
|
|
@ -14,7 +14,7 @@ use std::io::prelude::*;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use common::{self, Config, Mode};
|
use common::{self, CompareMode, Config, Mode};
|
||||||
use util;
|
use util;
|
||||||
|
|
||||||
use extract_gdb_version;
|
use extract_gdb_version;
|
||||||
|
@ -608,7 +608,12 @@ impl Config {
|
||||||
common::DebugInfoLldb => name == "lldb",
|
common::DebugInfoLldb => name == "lldb",
|
||||||
common::Pretty => name == "pretty",
|
common::Pretty => name == "pretty",
|
||||||
_ => false,
|
_ => false,
|
||||||
} || (self.target != self.host && name == "cross-compile")
|
} || (self.target != self.host && name == "cross-compile") ||
|
||||||
|
match self.compare_mode {
|
||||||
|
Some(CompareMode::Nll) => name == "compare-mode-nll",
|
||||||
|
Some(CompareMode::Polonius) => name == "compare-mode-polonius",
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue