From b55bb2e918560509418a8b79f8ce5aa2c0d5aaff Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 10 Sep 2018 22:34:38 +0100 Subject: [PATCH] Better messages for errors from Shallow borrows --- .../borrow_check/error_reporting.rs | 49 ++++++++++++++++--- src/librustc_mir/borrow_check/mod.rs | 13 ++++- src/librustc_mir/diagnostics.rs | 20 ++++++++ src/librustc_mir/util/borrowck_errors.rs | 23 +++++++++ 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 @@ pub(super) fn report_conflicting_borrow( (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 @@ pub(super) fn report_conflicting_borrow( 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 @@ pub(super) fn report_illegal_mutation_of_borrowed( 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 @@ fn as_noun(self) -> &'static str { match self { InitializationRequiringAction::Update => "update", InitializationRequiringAction::Borrow => "borrow", + InitializationRequiringAction::MatchOn => "use", // no good noun InitializationRequiringAction::Use => "use", InitializationRequiringAction::Assignment => "assign", } @@ -859,6 +861,7 @@ fn as_verb_in_past_tense(self) -> &'static str { match self { InitializationRequiringAction::Update => "updated", InitializationRequiringAction::Borrow => "borrowed", + InitializationRequiringAction::MatchOn => "matched on", InitializationRequiringAction::Use => "used", InitializationRequiringAction::Assignment => "assigned", } @@ -991,7 +994,7 @@ fn check_access_for_conflict( } match kind { - ReadKind::Copy => { + ReadKind::Copy => { error_reported = true; this.report_use_while_mutably_borrowed(context, place_span, borrow) } @@ -1137,9 +1140,15 @@ fn consume_rvalue( 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 @@ fn cannot_borrow_path_as_mutable( 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, -- 2.44.0