Skip to content

Commit

Permalink
Auto merge of #52681 - pnkfelix:z-borrowck-migrate, r=nikomatsakis
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Jul 27, 2018
2 parents 7c2aeb9 + 9f05f29 commit b18b9ed
Show file tree
Hide file tree
Showing 20 changed files with 382 additions and 82 deletions.
8 changes: 8 additions & 0 deletions src/librustc/middle/borrowck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
}
}
17 changes: 16 additions & 1 deletion src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand All @@ -472,6 +485,7 @@ impl BorrowckMode {
BorrowckMode::Ast => false,
BorrowckMode::Compare => true,
BorrowckMode::Mir => true,
BorrowckMode::Migrate => true,
}
}
}
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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)),
};

Expand Down
60 changes: 50 additions & 10 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
match self.sess.opts.borrowck_mode {
mode @ BorrowckMode::Mir |
mode @ BorrowckMode::Compare => mode,
// 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=...`

mode @ BorrowckMode::Ast => {
if self.features().nll {
BorrowckMode::Mir
} else {
mode
}
}
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,

// 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,
},
}
}

Expand Down
13 changes: 11 additions & 2 deletions src/librustc_borrowck/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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();
}
}
}
Expand Down Expand Up @@ -745,6 +752,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
};

err.emit();
self.bccx.signal_error();
}
}
}
Expand Down Expand Up @@ -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();
}
}
1 change: 1 addition & 0 deletions src/librustc_borrowck/borrowck/gather_loans/move_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down
28 changes: 25 additions & 3 deletions src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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,
})
}
_ => { }
Expand All @@ -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
Expand Down Expand Up @@ -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(),
})
}

Expand Down Expand Up @@ -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);
Expand All @@ -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> {
Expand Down Expand Up @@ -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;
}
_ => {
Expand Down Expand Up @@ -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(
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -1047,6 +1066,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
"");

db.emit();
self.signal_error();
}
}
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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> {
Expand Down
19 changes: 19 additions & 0 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit b18b9ed

Please sign in to comment.