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

Expand Down
60 changes: 50 additions & 10 deletions src/librustc/ty/context.rs
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
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
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
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
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