about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2018-09-10 22:34:38 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2018-09-24 23:33:13 +0100
commitb55bb2e918560509418a8b79f8ce5aa2c0d5aaff (patch)
tree7489d6f30c1ee5b5f9b9c7cce26daef3f35286dc
parentced5c2d08af52de40d104687c2b6066d9daedecf (diff)
downloadrust-b55bb2e918560509418a8b79f8ce5aa2c0d5aaff.tar.gz
rust-b55bb2e918560509418a8b79f8ce5aa2c0d5aaff.zip
Better messages for errors from Shallow borrows
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs49
-rw-r--r--src/librustc_mir/borrow_check/mod.rs13
-rw-r--r--src/librustc_mir/diagnostics.rs20
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs23
4 files changed, 96 insertions, 9 deletions
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index f0dd8a9feb8..b775fc81d4f 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -335,6 +335,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
 
             (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _)
             | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => {
+                let mut err = tcx.cannot_mutate_in_match_guard(
+                    span,
+                    issued_span,
+                    &desc_place,
+                    "mutably borrow",
+                    Origin::Mir,
+                );
+                borrow_spans.var_span_label(
+                    &mut err,
+                    format!(
+                        "borrow occurs due to use of `{}` in closure",
+                        desc_place
+                    ),
+                );
+                err.buffer(&mut self.errors_buffer);
+
                 return;
             }
 
@@ -373,7 +389,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     Origin::Mir,
                 ),
 
-            (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) => unreachable!(),
+            (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => {
+                // Shallow borrows are uses from the user's point of view.
+                self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow);
+                return
+            }
+            (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _)
+            | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _)
+            | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(),
         };
 
         if issued_spans == borrow_spans {
@@ -785,12 +810,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         let loan_span = loan_spans.args_or_use();
 
         let tcx = self.infcx.tcx;
-        let mut err = tcx.cannot_assign_to_borrowed(
-            span,
-            loan_span,
-            &self.describe_place(place).unwrap_or("_".to_owned()),
-            Origin::Mir,
-        );
+        let mut err = if loan.kind == BorrowKind::Shallow {
+            tcx.cannot_mutate_in_match_guard(
+                span,
+                loan_span,
+                &self.describe_place(place).unwrap_or("_".to_owned()),
+                "assign",
+                Origin::Mir,
+            )
+        } else {
+            tcx.cannot_assign_to_borrowed(
+                span,
+                loan_span,
+                &self.describe_place(place).unwrap_or("_".to_owned()),
+                Origin::Mir,
+            )
+        };
 
         loan_spans.var_span_label(&mut err, "borrow occurs due to use in closure");
 
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 34fe9408eaf..5d919e88cad 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -836,6 +836,7 @@ enum LocalMutationIsAllowed {
 enum InitializationRequiringAction {
     Update,
     Borrow,
+    MatchOn,
     Use,
     Assignment,
 }
@@ -850,6 +851,7 @@ impl InitializationRequiringAction {
         match self {
             InitializationRequiringAction::Update => "update",
             InitializationRequiringAction::Borrow => "borrow",
+            InitializationRequiringAction::MatchOn => "use", // no good noun
             InitializationRequiringAction::Use => "use",
             InitializationRequiringAction::Assignment => "assign",
         }
@@ -859,6 +861,7 @@ impl InitializationRequiringAction {
         match self {
             InitializationRequiringAction::Update => "updated",
             InitializationRequiringAction::Borrow => "borrowed",
+            InitializationRequiringAction::MatchOn => "matched on",
             InitializationRequiringAction::Use => "used",
             InitializationRequiringAction::Assignment => "assigned",
         }
@@ -991,7 +994,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     }
 
                     match kind {
-                        ReadKind::Copy => {
+                        ReadKind::Copy  => {
                             error_reported = true;
                             this.report_use_while_mutably_borrowed(context, place_span, borrow)
                         }
@@ -1137,9 +1140,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     flow_state,
                 );
 
+                let action = if bk == BorrowKind::Shallow {
+                    InitializationRequiringAction::MatchOn
+                } else {
+                    InitializationRequiringAction::Borrow
+                };
+
                 self.check_if_path_or_subpath_is_moved(
                     context,
-                    InitializationRequiringAction::Borrow,
+                    action,
                     (place, span),
                     flow_state,
                 );
diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs
index 24197c9e4b8..0c31e5c4da8 100644
--- a/src/librustc_mir/diagnostics.rs
+++ b/src/librustc_mir/diagnostics.rs
@@ -1991,6 +1991,26 @@ fn main() {
 ```
 "##,
 
+E0510: r##"
+Cannot mutate place in this match guard.
+
+When matching on a variable it cannot be mutated in the match guards, as this
+could cause the match to be non-exhaustive:
+
+```compile_fail,E0510
+#![feature(nll, bind_by_move_pattern_guards)]
+let mut x = Some(0);
+match x {
+    None => (),
+    Some(v) if { x = None; false } => (),
+    Some(_) => (), // No longer matches
+}
+```
+
+Here executing `x = None` would modify the value being matched and require us
+to go "back in time" to the `None` arm.
+"##,
+
 E0579: r##"
 When matching against an exclusive range, the compiler verifies that the range
 is non-empty. Exclusive range patterns include the start point but not the end
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index 82617ee1074..6d5d3ba88f2 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -555,6 +555,29 @@ pub trait BorrowckErrors<'cx>: Sized + Copy {
         self.cannot_borrow_path_as_mutable_because(span, path, "", o)
     }
 
+    fn cannot_mutate_in_match_guard(
+        self,
+        mutate_span: Span,
+        match_span: Span,
+        match_place: &str,
+        action: &str,
+        o: Origin,
+    ) -> DiagnosticBuilder<'cx> {
+        let mut err = struct_span_err!(
+            self,
+            mutate_span,
+            E0510,
+            "cannot {} `{}` in match guard{OGN}",
+            action,
+            match_place,
+            OGN = o
+        );
+        err.span_label(mutate_span, format!("cannot {}", action));
+        err.span_label(match_span, format!("value is immutable in match guard"));
+
+        self.cancel_if_wrong_origin(err, o)
+    }
+
     fn cannot_borrow_across_generator_yield(
         self,
         span: Span,