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:
bors 2018-07-27 09:10:07 +00:00
commit b18b9edf00
20 changed files with 380 additions and 80 deletions

View File

@ -15,9 +15,15 @@ use util::nodemap::FxHashSet;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
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)]
pub struct BorrowCheckResult {
pub used_mut_nodes: FxHashSet<HirId>,
pub signalled_any_error: SignalledError,
}
impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
@ -26,7 +32,9 @@ impl<'a> HashStable<StableHashingContext<'a>> for BorrowCheckResult {
hasher: &mut StableHasher<W>) {
let BorrowCheckResult {
ref used_mut_nodes,
ref signalled_any_error,
} = *self;
used_mut_nodes.hash_stable(hcx, hasher);
signalled_any_error.hash_stable(hcx, hasher);
}
}

View File

@ -455,15 +455,28 @@ pub enum BorrowckMode {
Ast,
Mir,
Compare,
Migrate,
}
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?
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?
@ -472,6 +485,7 @@ impl BorrowckMode {
BorrowckMode::Ast => false,
BorrowckMode::Compare => 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 EndRegion as part of MIR; enable transforms that solely process EndRegion"),
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],
"use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"),
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,
Some("mir") => BorrowckMode::Mir,
Some("compare") => BorrowckMode::Compare,
Some("migrate") => BorrowckMode::Migrate,
Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
};

View File

@ -74,6 +74,7 @@ use rustc_target::spec::abi;
use syntax::ast::{self, NodeId};
use syntax::attr;
use syntax::codemap::MultiSpan;
use syntax::edition::Edition;
use syntax::feature_gate;
use syntax::symbol::{Symbol, keywords, InternedString};
use syntax_pos::Span;
@ -1366,6 +1367,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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
/// borrow of the input to the match expression.
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?
/// (Also considers the `#![feature(nll)]` setting.)
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 {
mode @ BorrowckMode::Mir |
mode @ BorrowckMode::Compare => mode,
mode @ BorrowckMode::Compare |
mode @ BorrowckMode::Migrate => mode,
mode @ BorrowckMode::Ast => {
if self.features().nll {
BorrowckMode::Mir
} else {
mode
}
}
BorrowckMode::Ast => match self.sess.edition() {
Edition::Edition2015 => BorrowckMode::Ast,
Edition::Edition2018 => BorrowckMode::Migrate,
// 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,
},
}
}

View File

@ -447,10 +447,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
.region_scope_tree
.yield_in_scope_for_expr(scope,
cmt.hir_id,
self.bccx.body) {
self.bccx.body)
{
self.bccx.cannot_borrow_across_generator_yield(borrow_span,
yield_span,
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();
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)) => {
err_old.emit();
self.bccx.signal_error();
err_new.cancel();
}
(None, None) => return true,
@ -695,6 +701,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
loan_span, &self.bccx.loan_path_to_string(&loan_path),
Origin::Ast)
.emit();
self.bccx.signal_error();
}
}
}
@ -745,6 +752,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
};
err.emit();
self.bccx.signal_error();
}
}
}
@ -914,5 +922,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
self.bccx.cannot_assign_to_borrowed(
span, loan.span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast)
.emit();
self.bccx.signal_error();
}
}

View File

@ -99,6 +99,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec<Move
"captured outer variable");
}
err.emit();
bccx.signal_error();
}
}

View File

@ -28,7 +28,7 @@ use rustc::middle::dataflow::DataFlowContext;
use rustc::middle::dataflow::BitwiseOperator;
use rustc::middle::dataflow::DataFlowOperator;
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::middle::expr_use_visitor as euv;
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::util::nodemap::FxHashSet;
use std::cell::RefCell;
use std::cell::{Cell, RefCell};
use std::fmt;
use std::rc::Rc;
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)
-> Lrc<BorrowCheckResult>
{
assert!(tcx.use_ast_borrowck());
assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck());
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.
return Lrc::new(BorrowCheckResult {
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,
body,
used_mut_nodes: RefCell::new(FxHashSet()),
signalled_any_error: Cell::new(SignalledError::NoErrorsSeen),
};
// 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 {
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,
body,
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);
@ -257,6 +261,15 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> {
body: &'tcx hir::Body,
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> {
@ -645,6 +658,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
.span_label(use_span, format!("use of possibly uninitialized `{}`",
self.loan_path_to_string(lp)))
.emit();
self.signal_error();
return;
}
_ => {
@ -760,6 +774,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
// not considered particularly helpful.
err.emit();
self.signal_error();
}
pub fn report_partial_reinitialization_of_uninitialized_structure(
@ -770,6 +785,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
&self.loan_path_to_string(lp),
Origin::Ast)
.emit();
self.signal_error();
}
pub fn report_reassigned_immutable_variable(&self,
@ -787,6 +803,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
self.loan_path_to_string(lp)));
}
err.emit();
self.signal_error();
}
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)
);
db.emit();
self.signal_error();
}
err_out_of_scope(super_scope, sub_scope, cause) => {
let msg = match opt_loan_path(&err.cmt) {
@ -1022,6 +1040,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
}
db.emit();
self.signal_error();
}
err_borrowed_pointer_too_short(loan_scope, ptr_scope) => {
let descr = self.cmt_to_path_or_string(err.cmt);
@ -1047,6 +1066,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
"");
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.emit();
self.signal_error();
}
/// 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),
suggestion)
.emit();
self.signal_error();
}
fn region_end_span(&self, region: ty::Region<'tcx>) -> Option<Span> {

View File

@ -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
/// canceled or it will panic when dropped).
pub fn cancel(&mut self) {

View File

@ -100,25 +100,6 @@ impl<'a> DiagnosticBuilder<'a> {
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
/// span_* methods instead.
pub fn sub<S: Into<MultiSpan>>(

View File

@ -16,6 +16,7 @@ use rustc::hir::def_id::DefId;
use rustc::hir::map::definitions::DefPathData;
use rustc::infer::InferCtxt;
use rustc::lint::builtin::UNUSED_MUT;
use rustc::middle::borrowck::SignalledError;
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Place};
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::{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::fx::FxHashSet;
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(..) {
DiagnosticBuilder::new_diagnostic(mbcx.tcx.sess.diagnostic(), diag).emit();
if mbcx.errors_buffer.len() > 0 {
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 {
@ -1747,20 +1774,44 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
}
}
Reservation(WriteKind::Move)
| Write(WriteKind::Move)
| Reservation(WriteKind::StorageDeadOrDrop)
| Reservation(WriteKind::MutableBorrow(BorrowKind::Shared))
| Write(WriteKind::StorageDeadOrDrop)
| Write(WriteKind::MutableBorrow(BorrowKind::Shared)) => {
Reservation(wk @ WriteKind::Move)
| Write(wk @ WriteKind::Move)
| Reservation(wk @ WriteKind::StorageDeadOrDrop)
| Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared))
| Write(wk @ WriteKind::StorageDeadOrDrop)
| Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => {
if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) {
self.tcx.sess.delay_span_bug(
span,
&format!(
"Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
place, kind
),
);
if self.tcx.migrate_borrowck() {
// rust-lang/rust#46908: In pure NLL mode this
// code path should be unreachable (and thus
// we signal an ICE in the else branch
// 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;
}

View File

@ -24,6 +24,7 @@ use util::suggest_ref_mut;
pub(super) enum AccessKind {
MutableBorrow,
Mutate,
Move,
}
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 {
item_msg = format!("`{}`", desc);
reason = match error_access {
AccessKind::Move |
AccessKind::Mutate => format!(" which is behind a {}", pointer_type),
AccessKind::MutableBorrow => {
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 {
AccessKind::Move => {
err = self.tcx
.cannot_move_out_of(span, &(item_msg + &reason), Origin::Mir);
act = "move";
acted_on = "moved";
span
}
AccessKind::Mutate => {
err = self.tcx
.cannot_assign(span, &(item_msg + &reason), Origin::Mir);

View File

@ -41,7 +41,20 @@ impl MirPass for ElaborateDrops {
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 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 mir = &*mir;
let env = MoveDataParamEnv {

View File

@ -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`.

View File

@ -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."),
}
}

View File

@ -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`.

View 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.

View 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."),
}
}

View 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.

View File

@ -8,17 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Z borrowck=compare
#![feature(generators)]
#![feature(nll)]
fn main() {
|| {
// 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 b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
//~^ borrow may still be in use when generator yields (Mir)
let _a = &mut true;
let b = &mut true;
//~^ borrow may still be in use when generator yields
yield ();
println!("{}", b);
};

View File

@ -1,30 +1,12 @@
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/generator-with-nll.rs:19:23
error[E0626]: borrow may still be in use when generator yields
--> $DIR/generator-with-nll.rs:18:17
|
LL | let _a = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
| ^^^^
...
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 | let b = &mut true;
| ^^^^^^^^^
LL | //~^ borrow may still be in use when generator yields (Mir)
LL | //~^ borrow may still be in use when generator yields
LL | yield ();
| -------- 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`.

View File

@ -14,7 +14,7 @@ use std::io::prelude::*;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use common::{self, Config, Mode};
use common::{self, CompareMode, Config, Mode};
use util;
use extract_gdb_version;
@ -608,7 +608,12 @@ impl Config {
common::DebugInfoLldb => name == "lldb",
common::Pretty => name == "pretty",
_ => 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 {
false
}