Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -Z borrowck=migrate #52681

Merged
merged 10 commits into from
Jul 27, 2018
8 changes: 8 additions & 0 deletions src/librustc/middle/borrowck.rs
Original file line number Diff line number Diff line change
@@ -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);
}
}
17 changes: 16 additions & 1 deletion src/librustc/session/config.rs
Original file line number Diff line number Diff line change
@@ -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],
@@ -2166,6 +2180,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)),
};

60 changes: 50 additions & 10 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -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 {
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,
},
}
}

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

28 changes: 25 additions & 3 deletions src/librustc_borrowck/borrowck/mod.rs
Original file line number Diff line number Diff line change
@@ -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> {
19 changes: 19 additions & 0 deletions src/librustc_errors/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -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) {
Loading
Oops, something went wrong.