]> git.lizzy.rs Git - rust.git/commitdiff
Add `-Z borrowck=migrate` flag, use it to link NLL up to AST-borrowck.
authorFelix S. Klock II <pnkfelix@pnkfx.org>
Fri, 20 Jul 2018 15:29:29 +0000 (17:29 +0200)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Thu, 26 Jul 2018 11:17:55 +0000 (13:17 +0200)
src/librustc/session/config.rs
src/librustc/ty/context.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_errors/diagnostic.rs
src/librustc_errors/diagnostic_builder.rs
src/librustc_mir/borrow_check/mod.rs

index 293b5c63cf06aa69ec5a1aab4e5b8f1f4fe3cf6d..1dadf07808f83e9b09af5ce90517ff9889901dfb 100644 (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 @@ pub fn use_mir(self) -> bool {
             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)),
     };
 
index 41007508c506010c2e73c1e012300073ab758c0f..d30f656098dc11b27c9db1083c4db426b5ac8359 100644 (file)
@@ -1366,6 +1366,12 @@ pub fn use_mir_borrowck(self) -> bool {
         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 @@ pub fn two_phase_borrows(self) -> bool {
     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 => {
index 86a7f30147024956ac1752e3068349a44b342327..0cb4a766e807997d79b5cabfcd981c98fa29d874 100644 (file)
@@ -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);
 
index b1578b697bb8c3e1f389d68fe16f911d72269fdf..825e31539c8bedfe511056858a3182fc10836e3c 100644 (file)
@@ -99,6 +99,25 @@ pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) ->
         }
     }
 
+    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) {
index 8f99ad87cb8e023699640a6d49f5d056d93f167c..a0f3abda077f94720015a1053c7b57a582788a1f 100644 (file)
@@ -100,25 +100,6 @@ pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
         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>>(
index b3d7337cffe115b43ef5db31d68bcbf0a76b8dae..ad663000f938b99793c006a41f060441111a21b3 100644 (file)
@@ -16,6 +16,7 @@
 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::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 {