about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2018-07-20 17:29:29 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2018-07-26 13:17:55 +0200
commita23e8a726c167cf806840d35c787240d4008d3d0 (patch)
tree9ee441e69a5a2f575dfa48564fa024f80e5a1bbe
parent655894baf96e02b4a7270447b8c636a52b357bdf (diff)
downloadrust-a23e8a726c167cf806840d35c787240d4008d3d0.tar.gz
rust-a23e8a726c167cf806840d35c787240d4008d3d0.zip
Add `-Z borrowck=migrate` flag, use it to link NLL up to AST-borrowck.
-rw-r--r--src/librustc/session/config.rs15
-rw-r--r--src/librustc/ty/context.rs7
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_errors/diagnostic.rs19
-rw-r--r--src/librustc_errors/diagnostic_builder.rs19
-rw-r--r--src/librustc_mir/borrow_check/mod.rs27
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<BorrowCheckResult>
 {
-    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<S: Into<MultiSpan>>(
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 {