From a23e8a726c167cf806840d35c787240d4008d3d0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 20 Jul 2018 17:29:29 +0200 Subject: [PATCH] Add `-Z borrowck=migrate` flag, use it to link NLL up to AST-borrowck. --- src/librustc/session/config.rs | 15 +++++++++++++ src/librustc/ty/context.rs | 7 ++++++ src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_errors/diagnostic.rs | 19 ++++++++++++++++ src/librustc_errors/diagnostic_builder.rs | 19 ---------------- src/librustc_mir/borrow_check/mod.rs | 27 ++++++++++++++++++++--- 6 files changed, 66 insertions(+), 23 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 293b5c63cf0..1dadf07808f 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -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, } } } @@ -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)), }; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 41007508c50..d30f656098d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1366,6 +1366,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 { @@ -1399,6 +1405,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn borrowck_mode(&self) -> BorrowckMode { match self.sess.opts.borrowck_mode { mode @ BorrowckMode::Mir | + mode @ BorrowckMode::Migrate | mode @ BorrowckMode::Compare => mode, mode @ BorrowckMode::Ast => { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 86a7f301470..0cb4a766e80 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -90,7 +90,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> { fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) -> Lrc { - assert!(tcx.use_ast_borrowck()); + assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck()); debug!("borrowck(body_owner_def_id={:?})", owner_def_id); diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index b1578b697bb..825e31539c8 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -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) { diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 8f99ad87cb8..a0f3abda077 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -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>( diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index b3d7337cffe..ad663000f93 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -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,28 @@ 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; } + } + } + 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 {