From ced5c2d08af52de40d104687c2b6066d9daedecf Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 10 Sep 2018 22:33:45 +0100 Subject: [PATCH 1/9] Add "Shallow" borrow kind This allows treating the "fake" match borrows differently from shared borrows. --- src/librustc/ich/impls_mir.rs | 1 + src/librustc/mir/mod.rs | 24 +++++++++++++- src/librustc/mir/tcx.rs | 4 +++ src/librustc/mir/visit.rs | 5 ++- src/librustc_mir/borrow_check/borrow_set.rs | 4 ++- .../borrow_check/error_reporting.rs | 5 +++ src/librustc_mir/borrow_check/mod.rs | 32 +++++++++++++++---- .../borrow_check/nll/invalidation.rs | 8 +++-- src/librustc_mir/borrow_check/path_utils.rs | 9 +++++- .../borrow_check/places_conflict.rs | 28 +++++++++++----- src/librustc_mir/build/matches/mod.rs | 4 ++- 11 files changed, 102 insertions(+), 22 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 313ef054829c5..e145e87a08907 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -46,6 +46,7 @@ for mir::BorrowKind { match *self { mir::BorrowKind::Shared | + mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {} mir::BorrowKind::Mut { allow_two_phase_borrow } => { allow_two_phase_borrow.hash_stable(hcx, hasher); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 98d9a0a7c6f5e..21c2299eac035 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -456,6 +456,27 @@ pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, + /// The immediately borrowed place must be immutable, but projections from + /// it don't need to be. For example, a shallow borrow of `a.b` doesn't + /// conflict with a mutable borrow of `a.b.c`. + /// + /// This is used when lowering matches: when matching on a place we want to + /// ensure that place have the same value from the start of the match until + /// an arm is selected. This prevents this code from compiling: + /// + /// let mut x = &Some(0); + /// match *x { + /// None => (), + /// Some(_) if { x = &None; false } => (), + /// Some(_) => (), + /// } + /// + /// This can't be a shared borrow because mutably borrowing (*x as Some).0 + /// should not prevent `if let None = x { ... }`, for example, becase the + /// mutating `(*x as Some).0` can't affect the discriminant of `x`. + /// We can also report errors with this kind of borrow differently. + Shallow, + /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in /// implicit closure bindings. It is needed when the closure is @@ -504,7 +525,7 @@ pub enum BorrowKind { impl BorrowKind { pub fn allows_two_phase_borrow(&self) -> bool { match *self { - BorrowKind::Shared | BorrowKind::Unique => false, + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, BorrowKind::Mut { allow_two_phase_borrow, } => allow_two_phase_borrow, @@ -2198,6 +2219,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { Ref(region, borrow_kind, ref place) => { let kind_str = match borrow_kind { BorrowKind::Shared => "", + BorrowKind::Shallow => "shallow ", BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", }; diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index c928be4f9df78..2a25e057a7149 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -287,6 +287,10 @@ impl BorrowKind { // use `&mut`. It gives all the capabilities of an `&uniq` // and hence is a safe "over approximation". BorrowKind::Unique => hir::MutMutable, + + // We have no type corresponding to a shallow borrow, so use + // `&` as an approximation. + BorrowKind::Shallow => hir::MutImmutable, } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 91c83ecb2e23c..6de7e2215bf41 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -963,6 +963,7 @@ impl<'tcx> PlaceContext<'tcx> { PlaceContext::Inspect | PlaceContext::Borrow { kind: BorrowKind::Shared, .. } | + PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } | PlaceContext::Borrow { kind: BorrowKind::Unique, .. } | PlaceContext::Projection(Mutability::Not) | PlaceContext::Copy | PlaceContext::Move | @@ -974,7 +975,9 @@ impl<'tcx> PlaceContext<'tcx> { /// Returns true if this place context represents a use that does not change the value. pub fn is_nonmutating_use(&self) -> bool { match *self { - PlaceContext::Inspect | PlaceContext::Borrow { kind: BorrowKind::Shared, .. } | + PlaceContext::Inspect | + PlaceContext::Borrow { kind: BorrowKind::Shared, .. } | + PlaceContext::Borrow { kind: BorrowKind::Shallow, .. } | PlaceContext::Borrow { kind: BorrowKind::Unique, .. } | PlaceContext::Projection(Mutability::Not) | PlaceContext::Copy | PlaceContext::Move => true, diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index bb70b4b76c277..bcf3772213014 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -87,6 +87,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { let kind = match self.kind { mir::BorrowKind::Shared => "", + mir::BorrowKind::Shallow => "shallow ", mir::BorrowKind::Unique => "uniq ", mir::BorrowKind::Mut { .. } => "mut ", }; @@ -287,7 +288,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { borrow_data.activation_location = match context { // The use of TMP in a shared borrow does not // count as an actual activation. - PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. } => { + PlaceContext::Borrow { kind: mir::BorrowKind::Shared, .. } + | PlaceContext::Borrow { kind: mir::BorrowKind::Shallow, .. } => { TwoPhaseActivation::NotActivated } _ => { diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 1d91fa365d547..f0dd8a9feb8e1 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -333,6 +333,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Origin::Mir, ), + (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => { + return; + } + (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure( span, &desc_place, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 769e1097bff05..34fe9408eafc3 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -755,6 +755,7 @@ use self::AccessDepth::{Deep, Shallow}; enum ArtificialField { Discriminant, ArrayLength, + ShallowBorrow, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -972,7 +973,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Control::Continue } - (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => { + (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) + | (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => { + Control::Continue + } + + (Write(WriteKind::Move), BorrowKind::Shallow) => { + // Handled by initialization checks. Control::Continue } @@ -1108,6 +1115,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match *rvalue { Rvalue::Ref(_ /*rgn*/, bk, ref place) => { let access_kind = match bk { + BorrowKind::Shallow => { + (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + }, BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); @@ -1315,11 +1325,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { return; } - // FIXME: replace this with a proper borrow_conflicts_with_place when - // that is merged. let sd = if might_be_alive { Deep } else { Shallow(None) }; - if places_conflict::places_conflict(self.infcx.tcx, self.mir, place, root_place, sd) { + if places_conflict::borrow_conflicts_with_place( + self.infcx.tcx, + self.mir, + place, + borrow.kind, + root_place, + sd + ) { debug!("check_for_invalidation_at_exit({:?}): INVALID", place); // FIXME: should be talking about the region lifetime instead // of just a span here. @@ -1369,7 +1384,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared => false, + BorrowKind::Shared | BorrowKind::Shallow => false, BorrowKind::Unique | BorrowKind::Mut { .. } => true, }); @@ -1669,7 +1684,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let is_local_mutation_allowed = match borrow_kind { BorrowKind::Unique => LocalMutationIsAllowed::Yes, BorrowKind::Mut { .. } => is_local_mutation_allowed, - BorrowKind::Shared => unreachable!(), + BorrowKind::Shared | BorrowKind::Shallow => unreachable!(), }; match self.is_mutable(place, is_local_mutation_allowed) { Ok(root_place) => { @@ -1699,8 +1714,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | Write(wk @ WriteKind::Move) | Reservation(wk @ WriteKind::StorageDeadOrDrop) | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) + | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) | Write(wk @ WriteKind::StorageDeadOrDrop) - | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) => { + | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) + | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => { if let Err(_place_err) = self.is_mutable(place, is_local_mutation_allowed) { if self.infcx.tcx.migrate_borrowck() { // rust-lang/rust#46908: In pure NLL mode this @@ -1743,6 +1760,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Read(ReadKind::Borrow(BorrowKind::Unique)) | Read(ReadKind::Borrow(BorrowKind::Mut { .. })) | Read(ReadKind::Borrow(BorrowKind::Shared)) + | Read(ReadKind::Borrow(BorrowKind::Shallow)) | Read(ReadKind::Copy) => { // Access authorized return false; diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 3d387963da9da..1246f7120c4fb 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -329,6 +329,9 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { match *rvalue { Rvalue::Ref(_ /*rgn*/, bk, ref place) => { let access_kind = match bk { + BorrowKind::Shallow => { + (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) + }, BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); @@ -439,8 +442,9 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // have already taken the reservation } - (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => { - // Reads/reservations don't invalidate shared borrows + (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) + | (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => { + // Reads/reservations don't invalidate shared or shallow borrows } (Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => { diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 67787d23db692..ccb7a4056267a 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -61,7 +61,14 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( for i in candidates { let borrowed = &borrow_set[i]; - if places_conflict::places_conflict(tcx, mir, &borrowed.borrowed_place, place, access) { + if places_conflict::places_conflict( + tcx, + mir, + &borrowed.borrowed_place, + borrowed.kind, + place, + access, + ) { debug!( "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}", i, borrowed, place, access diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index e371b34c4800c..13ac1d60c9543 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -12,7 +12,7 @@ use borrow_check::ArtificialField; use borrow_check::Overlap; use borrow_check::{Deep, Shallow, AccessDepth}; use rustc::hir; -use rustc::mir::{Mir, Place}; +use rustc::mir::{BorrowKind, Mir, Place}; use rustc::mir::{Projection, ProjectionElem}; use rustc::ty::{self, TyCtxt}; use std::cmp::max; @@ -21,6 +21,7 @@ pub(super) fn places_conflict<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, borrow_place: &Place<'tcx>, + borrow_kind: BorrowKind, access_place: &Place<'tcx>, access: AccessDepth, ) -> bool { @@ -39,7 +40,14 @@ pub(super) fn places_conflict<'gcx, 'tcx>( unroll_place(borrow_place, None, |borrow_components| { unroll_place(access_place, None, |access_components| { - place_components_conflict(tcx, mir, borrow_components, access_components, access) + place_components_conflict( + tcx, + mir, + borrow_components, + borrow_kind, + access_components, + access + ) }) }) } @@ -48,6 +56,7 @@ fn place_components_conflict<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, mut borrow_components: PlaceComponentsIter<'_, 'tcx>, + borrow_kind: BorrowKind, mut access_components: PlaceComponentsIter<'_, 'tcx>, access: AccessDepth, ) -> bool { @@ -157,7 +166,8 @@ fn place_components_conflict<'gcx, 'tcx>( match (elem, &base_ty.sty, access) { (_, _, Shallow(Some(ArtificialField::Discriminant))) - | (_, _, Shallow(Some(ArtificialField::ArrayLength))) => { + | (_, _, Shallow(Some(ArtificialField::ArrayLength))) + | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { // The discriminant and array length are like // additional fields on the type; they do not // overlap any existing data there. Furthermore, @@ -225,11 +235,13 @@ fn place_components_conflict<'gcx, 'tcx>( // If the second example, where we did, then we still know // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. - // - // FIXME: Differs from AST-borrowck; includes drive-by fix - // to #38899. Will probably need back-compat mode flag. - debug!("places_conflict: full borrow, CONFLICT"); - return true; + if borrow_kind == BorrowKind::Shallow && access_components.next().is_some() { + debug!("places_conflict: shallow borrow"); + return false; + } else { + debug!("places_conflict: full borrow, CONFLICT"); + return true; + } } } } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index c30dcdafdb402..235440e28417d 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -1363,7 +1363,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // borrow of the whole match input. See additional // discussion on rust-lang/rust#49870. let borrow_kind = match borrow_kind { - BorrowKind::Shared | BorrowKind::Unique => borrow_kind, + BorrowKind::Shared + | BorrowKind::Shallow + | BorrowKind::Unique => borrow_kind, BorrowKind::Mut { .. } => BorrowKind::Mut { allow_two_phase_borrow: true, }, From b55bb2e918560509418a8b79f8ce5aa2c0d5aaff Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Mon, 10 Sep 2018 22:34:38 +0100 Subject: [PATCH 2/9] 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 f0dd8a9feb8e1..b775fc81d4f61 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 34fe9408eafc3..5d919e88cad6f 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 24197c9e4b88f..0c31e5c4da8ac 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 82617ee107470..6d5d3ba88f2f6 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, From a6fad3f620ac14f57da080863dabcdc6b78005b1 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 21:35:24 +0100 Subject: [PATCH 3/9] Add more fake borrows to matches --- src/librustc/ich/impls_mir.rs | 2 +- src/librustc/mir/mod.rs | 16 +- src/librustc_mir/build/matches/mod.rs | 211 +++++++++++++++++++------- 3 files changed, 171 insertions(+), 58 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index e145e87a08907..ec54613d1dbac 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -273,7 +273,7 @@ for mir::StatementKind<'gcx> { } } -impl_stable_hash_for!(enum mir::FakeReadCause { ForMatch, ForLet }); +impl_stable_hash_for!(enum mir::FakeReadCause { ForMatchGuard, ForMatchedPlace, ForLet }); impl<'a, 'gcx, T> HashStable> for mir::ValidationOperand<'gcx, T> diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 21c2299eac035..f856475c3376d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -451,7 +451,7 @@ impl From for hir::Mutability { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. Shared, @@ -1693,7 +1693,11 @@ pub enum FakeReadCause { /// /// This should ensure that you cannot change the variant for an enum /// while you are in the midst of matching on it. - ForMatch, + ForMatchGuard, + + /// `let x: !; match x {}` doesn't generate any read of x so we need to + /// generate a read of x to check that it is initialized and safe. + ForMatchedPlace, /// Officially, the semantics of /// @@ -1794,7 +1798,7 @@ impl<'tcx> Debug for Statement<'tcx> { /// A path to a value; something that can be evaluated without /// changing or disturbing program state. -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum Place<'tcx> { /// local variable Local(Local), @@ -1811,7 +1815,7 @@ pub enum Place<'tcx> { /// The def-id of a static, along with its normalized type (which is /// stored to avoid requiring normalization when reading MIR). -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Static<'tcx> { pub def_id: DefId, pub ty: Ty<'tcx>, @@ -1826,13 +1830,13 @@ impl_stable_hash_for!(struct Static<'tcx> { /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Place`. See the aliases /// `PlaceProjection` etc below. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Projection<'tcx, B, V, T> { pub base: B, pub elem: ProjectionElem<'tcx, V, T>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum ProjectionElem<'tcx, V, T> { Deref, Field(Field, T), diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 235440e28417d..e40ed51f7d354 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -57,39 +57,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // See issue #47412 for this hole being discovered in the wild. // // HACK(eddyb) Work around the above issue by adding a dummy inspection - // of `discriminant_place`, specifically by applying `Rvalue::Discriminant` - // (which will work regardless of type) and storing the result in a temp. + // of `discriminant_place`, specifically by applying `ReadForMatch`. // - // NOTE: Under NLL, the above issue should no longer occur because it - // injects a borrow of the matched input, which should have the same effect - // as eddyb's hack. Once NLL is the default, we can remove the hack. - - let dummy_source_info = self.source_info(discriminant_span); - let dummy_access = Rvalue::Discriminant(discriminant_place.clone()); - let dummy_ty = dummy_access.ty(&self.local_decls, tcx); - let dummy_temp = self.temp(dummy_ty, dummy_source_info.span); - self.cfg - .push_assign(block, dummy_source_info, &dummy_temp, dummy_access); + // NOTE: ReadForMatch also checks that the discriminant is initialized. + // This is currently needed to not allow matching on an uninitialized, + // uninhabited value. If we get never patterns, those will check that + // the place is initialized, and so this read would only be used to + // check safety. let source_info = self.source_info(discriminant_span); - let borrowed_input_temp = if tcx.generate_borrow_of_any_match_input() { - // The region is unknown at this point; we rely on NLL - // inference to find an appropriate one. Therefore you can - // only use this when NLL is turned on. - assert!(tcx.use_mir_borrowck()); - let borrowed_input = Rvalue::Ref( - tcx.types.re_empty, - BorrowKind::Shared, + self.cfg.push(block, Statement { + source_info, + kind: StatementKind::FakeRead( + FakeReadCause::ForMatchedPlace, discriminant_place.clone(), - ); - let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx); - let borrowed_input_temp = self.temp(borrowed_input_ty, span); - self.cfg - .push_assign(block, source_info, &borrowed_input_temp, borrowed_input); - Some(borrowed_input_temp) - } else { - None - }; + ), + }); let mut arm_blocks = ArmBlocks { blocks: arms.iter().map(|_| self.cfg.start_new_block()).collect(), @@ -118,6 +101,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|_| self.cfg.start_new_block()) .collect(); + let mut has_guard = false; + // assemble a list of candidates: there is one candidate per // pattern, which means there may be more than one candidate // *per arm*. These candidates are kept sorted such that the @@ -140,24 +125,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map( |( (arm_index, pat_index, pattern, guard), - (pre_binding_block, next_candidate_pre_binding_block), + (pre_binding_block, next_candidate_pre_binding_block) )| { - if let (true, Some(borrow_temp)) = - (tcx.emit_read_for_match(), borrowed_input_temp.clone()) - { - // Inject a fake read, see comments on `FakeReadCause::ForMatch`. - let pattern_source_info = self.source_info(pattern.span); - self.cfg.push( - *pre_binding_block, - Statement { - source_info: pattern_source_info, - kind: StatementKind::FakeRead( - FakeReadCause::ForMatch, - borrow_temp.clone(), - ), - }, - ); - } + has_guard |= guard.is_some(); // One might ask: why not build up the match pair such that it // matches via `borrowed_input_temp.deref()` instead of @@ -202,9 +172,31 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TerminatorKind::Unreachable, ); + // Maps a place to the kind of Fake borrow that we want to perform on + // it: either Shallow or Shared, depending on whether the place is + // bound in the match, or just switched on. + // If there are no match guards then we don't need any fake borrows, + // so don't track them. + let mut fake_borrows = if has_guard && tcx.generate_borrow_of_any_match_input() { + Some(FxHashMap()) + } else { + None + }; + + let pre_binding_blocks: Vec<_> = candidates + .iter() + .map(|cand| (cand.pre_binding_block, cand.span)) + .collect(); + // this will generate code to test discriminant_place and // branch to the appropriate arm block - let otherwise = self.match_candidates(span, &mut arm_blocks, candidates, block); + let otherwise = self.match_candidates( + discriminant_span, + &mut arm_blocks, + candidates, + block, + &mut fake_borrows, + ); if !otherwise.is_empty() { // All matches are exhaustive. However, because some matches @@ -224,6 +216,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } + if let Some(fake_borrows) = fake_borrows { + self.add_fake_borrows(&pre_binding_blocks, fake_borrows, source_info, block); + } + // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); @@ -714,12 +710,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// up the list of candidates and recurse with a non-exhaustive /// list. This is important to keep the size of the generated code /// under control. See `test_candidates` for more details. + /// + /// If `add_fake_borrows` is true, then places which need fake borrows + /// will be added to it. fn match_candidates<'pat>( &mut self, span: Span, arm_blocks: &mut ArmBlocks, mut candidates: Vec>, mut block: BasicBlock, + fake_borrows: &mut Option, BorrowKind>>, ) -> Vec { debug!( "matched_candidate(span={:?}, block={:?}, candidates={:?})", @@ -747,6 +747,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ); let mut unmatched_candidates = candidates.split_off(fully_matched); + // Insert a *Shared* borrow of any places that are bound. + if let Some(fake_borrows) = fake_borrows { + for Binding { source, .. } + in candidates.iter().flat_map(|candidate| &candidate.bindings) + { + fake_borrows.insert(source.clone(), BorrowKind::Shared); + } + } + let fully_matched_with_guard = candidates.iter().take_while(|c| c.guard.is_some()).count(); let unreachable_candidates = if fully_matched_with_guard + 1 < candidates.len() { @@ -783,7 +792,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { return vec![]; } else { let target = self.cfg.start_new_block(); - return self.match_candidates(span, arm_blocks, unmatched_candidates, target); + return self.match_candidates( + span, + arm_blocks, + unmatched_candidates, + target, + &mut None, + ); } } } @@ -796,7 +811,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Test candidates where possible. let (otherwise, tested_candidates) = - self.test_candidates(span, arm_blocks, &unmatched_candidates, block); + self.test_candidates(span, arm_blocks, &unmatched_candidates, block, fake_borrows); // If the target candidates were exhaustive, then we are done. // But for borrowck continue build decision tree. @@ -810,7 +825,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Otherwise, let's process those remaining candidates. let join_block = self.join_otherwise_blocks(span, otherwise); - self.match_candidates(span, arm_blocks, untested_candidates, join_block) + self.match_candidates(span, arm_blocks, untested_candidates, join_block, &mut None) } fn join_otherwise_blocks(&mut self, span: Span, mut otherwise: Vec) -> BasicBlock { @@ -950,6 +965,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arm_blocks: &mut ArmBlocks, candidates: &[Candidate<'pat, 'tcx>], block: BasicBlock, + fake_borrows: &mut Option, BorrowKind>>, ) -> (Vec, usize) { // extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; @@ -990,6 +1006,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { _ => {} } + // Insert a Shallow borrow of any places that is switched on. + fake_borrows.as_mut().map(|fb| { + fb.entry(match_pair.place.clone()).or_insert(BorrowKind::Shallow) + }); + // perform the test, branching to one of N blocks. For each of // those N possible outcomes, create a (initially empty) // vector of candidates. Those are the candidates that still @@ -1026,7 +1047,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .into_iter() .zip(target_candidates) .flat_map(|(target_block, target_candidates)| { - self.match_candidates(span, arm_blocks, target_candidates, target_block) + self.match_candidates( + span, + arm_blocks, + target_candidates, + target_block, + fake_borrows, + ) }) .collect(); @@ -1504,4 +1531,86 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("declare_binding: vars={:?}", locals); self.var_indices.insert(var_id, locals); } + + // Determine the fake borrows that are needed to ensure that the place + // will evaluate to the same thing until an arm has been chosen. + fn add_fake_borrows<'pat>( + &mut self, + pre_binding_blocks: &[(BasicBlock, Span)], + fake_borrows: FxHashMap, BorrowKind>, + source_info: SourceInfo, + start_block: BasicBlock, + ) { + let tcx = self.hir.tcx(); + + debug!("add_fake_borrows pre_binding_blocks = {:?}, fake_borrows = {:?}", + pre_binding_blocks, fake_borrows); + + let mut all_fake_borrows = Vec::with_capacity(fake_borrows.len()); + + // Insert a Shallow borrow of the prefixes of any fake borrows. + for (place, borrow_kind) in fake_borrows + { + { + let mut prefix_cursor = &place; + while let Place::Projection(box Projection { base, elem }) = prefix_cursor { + if let ProjectionElem::Deref = elem { + // Insert a shallow borrow after a deref. For other + // projections the borrow of prefix_cursor will + // conflict with any mutation of base. + all_fake_borrows.push((base.clone(), BorrowKind::Shallow)); + } + prefix_cursor = base; + } + } + + all_fake_borrows.push((place, borrow_kind)); + } + + // Deduplicate and ensure a deterministic order. + all_fake_borrows.sort(); + all_fake_borrows.dedup(); + + debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); + + // Add fake borrows to the start of the match and reads of them before + // the start of each arm. + let mut borrowed_input_temps = Vec::with_capacity(all_fake_borrows.len()); + + for (matched_place, borrow_kind) in all_fake_borrows { + let borrowed_input = + Rvalue::Ref(tcx.types.re_empty, borrow_kind, matched_place.clone()); + let borrowed_input_ty = borrowed_input.ty(&self.local_decls, tcx); + let borrowed_input_temp = self.temp(borrowed_input_ty, source_info.span); + self.cfg.push_assign( + start_block, + source_info, + &borrowed_input_temp, + borrowed_input + ); + borrowed_input_temps.push(borrowed_input_temp); + } + + // FIXME: This could be a lot of reads (#fake borrows * #patterns). + // The false edges that we currently generate would allow us to only do + // this on the last Candidate, but it's possible that there might not be + // so many false edges in the future, so we read for all Candidates for + // now. + // Another option would be to make our own block and add our own false + // edges to it. + if tcx.emit_read_for_match() { + for &(pre_binding_block, span) in pre_binding_blocks { + let pattern_source_info = self.source_info(span); + for temp in &borrowed_input_temps { + self.cfg.push(pre_binding_block, Statement { + source_info: pattern_source_info, + kind: StatementKind::FakeRead( + FakeReadCause::ForMatchGuard, + temp.clone(), + ), + }); + } + } + } + } } From 46e247bcec13f3e1e850c3baffc23e64a8023ae4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 21:36:15 +0100 Subject: [PATCH 4/9] Don't check for conflicting borrows of `ReadForMatch`es --- src/librustc_mir/borrow_check/mod.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 5d919e88cad6f..06394ee44ccbe 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -499,11 +499,20 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ); } StatementKind::FakeRead(_, ref place) => { - self.access_place( + // Read for match doesn't access any memory and is used to + // assert that a place is safe and live. So we don't have to + // do any checks here. + // + // FIXME: Remove check that the place is initialized. This is + // needed for now because matches don't have never patterns yet. + // So this is the only place we prevent + // let x: !; + // match x {}; + // from compiling. + self.check_if_path_or_subpath_is_moved( ContextKind::FakeRead.new(location), + InitializationRequiringAction::Use, (place, span), - (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))), - LocalMutationIsAllowed::No, flow_state, ); } From c5047cb4944297566d236a663bbbba00f2f25cd0 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 22:04:00 +0100 Subject: [PATCH 5/9] Add tests for new match borrows --- ...sue-27282-mutate-before-diverging-arm-3.rs | 30 ++++ ...27282-mutate-before-diverging-arm-3.stderr | 14 ++ .../ui/nll/match-guards-partially-borrow.rs | 164 ++++++++++++++++++ .../nll/match-guards-partially-borrow.stderr | 132 ++++++++++++++ src/test/ui/nll/match-on-borrowed.rs | 95 ++++++++++ src/test/ui/nll/match-on-borrowed.stderr | 22 +++ 6 files changed, 457 insertions(+) create mode 100644 src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs create mode 100644 src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr create mode 100644 src/test/ui/nll/match-guards-partially-borrow.rs create mode 100644 src/test/ui/nll/match-guards-partially-borrow.stderr create mode 100644 src/test/ui/nll/match-on-borrowed.rs create mode 100644 src/test/ui/nll/match-on-borrowed.stderr diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs new file mode 100644 index 0000000000000..4cf5bcd6b4f68 --- /dev/null +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.rs @@ -0,0 +1,30 @@ +// This is testing an attempt to corrupt the discriminant of the match +// arm in a guard, followed by an attempt to continue matching on that +// corrupted discriminant in the remaining match arms. +// +// Basically this is testing that our new NLL feature of emitting a +// fake read on each match arm is catching cases like this. +// +// This case is interesting because a borrow of **x is untracked, because **x is +// immutable. However, for matches we care that **x refers to the same value +// until we have chosen a match arm. +#![feature(nll)] +struct ForceFnOnce; +fn main() { + let mut x = &mut &Some(&2); + let force_fn_once = ForceFnOnce; + match **x { + None => panic!("unreachable"), + Some(&_) if { + // ForceFnOnce needed to exploit #27282 + (|| { *x = &None; drop(force_fn_once); })(); + //~^ ERROR cannot mutably borrow `x` in match guard [E0510] + false + } => {} + Some(&a) if { // this binds to garbage if we've corrupted discriminant + println!("{}", a); + panic!() + } => {} + _ => panic!("unreachable"), + } +} diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr new file mode 100644 index 0000000000000..f46a42d750817 --- /dev/null +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-3.stderr @@ -0,0 +1,14 @@ +error[E0510]: cannot mutably borrow `x` in match guard + --> $DIR/issue-27282-mutate-before-diverging-arm-3.rs:20:14 + | +LL | match **x { + | --- value is immutable in match guard +... +LL | (|| { *x = &None; drop(force_fn_once); })(); + | ^^ - borrow occurs due to use of `x` in closure + | | + | cannot mutably borrow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0510`. diff --git a/src/test/ui/nll/match-guards-partially-borrow.rs b/src/test/ui/nll/match-guards-partially-borrow.rs new file mode 100644 index 0000000000000..49846f620f0c0 --- /dev/null +++ b/src/test/ui/nll/match-guards-partially-borrow.rs @@ -0,0 +1,164 @@ +// Test that a (partially) mutably borrowed place can be matched on, so long as +// we don't have to read any values that are mutably borrowed to determine +// which arm to take. +// +// Test that we don't allow mutating the value being matched on in a way that +// changes which patterns it matches, until we have chosen an arm. + +// compile-flags: -Zdisable-ast-check-for-mutation-in-guard + +#![feature(nll)] + +fn ok_mutation_in_guard(mut q: i32) { + match q { + // OK, mutation doesn't change which patterns g matches + _ if { q = 1; false } => (), + _ => (), + } +} + +fn ok_indirect_mutation_in_guard(mut p: &bool) { + match *p { + // OK, mutation doesn't change which patterns s matches + _ if { + p = &true; + false + } => (), + _ => (), + } +} + +fn mutation_invalidates_pattern_in_guard(mut q: bool) { + match q { + // s doesn't match the pattern with the guard by the end of the guard. + false if { + q = true; //~ ERROR + true + } => (), + _ => (), + } +} + +fn mutation_invalidates_previous_pattern_in_guard(mut r: bool) { + match r { + // s matches a previous pattern by the end of the guard. + true => (), + _ if { + r = true; //~ ERROR + true + } => (), + _ => (), + } +} + +fn match_on_borrowed_early_end(mut s: bool) { + let h = &mut s; + match s { //~ ERROR + // s changes value between the start of the match and when its value is checked. + _ if { + *h = !*h; + false + } => (), + true => (), + false => (), + } +} + +fn bad_mutation_in_guard(mut t: bool) { + match t { + true => (), + false if { + t = true; //~ ERROR + false + } => (), + false => (), + } +} + +fn bad_mutation_in_guard2(mut u: bool) { + match u { + // Guard changes the value bound in the last pattern. + _ => (), + _ if { + u = true; //~ ERROR + false + } => (), + x => (), + } +} + +pub fn bad_mutation_in_guard3(mut x: Option>) { + // Check that nested patterns are checked. + match x { + None => (), + Some(None) => (), + _ if { + match x { + Some(ref mut r) => *r = None, //~ ERROR + _ => return, + }; + false + } => (), + Some(Some(r)) => println!("{}", r), + } +} + + +fn bad_mutation_in_guard4(mut w: (&mut bool,)) { + match w { + // Guard changes the value bound in the last pattern. + _ => (), + _ if { + *w.0 = true; //~ ERROR + false + } => (), + x => (), + } +} + +fn bad_indirect_mutation_in_guard(mut y: &bool) { + match *y { + true => (), + false if { + y = &true; //~ ERROR + false + } => (), + false => (), + } +} + +fn bad_indirect_mutation_in_guard2(mut z: &bool) { + match z { + &true => (), + &false if { + z = &true; //~ ERROR + false + } => (), + &false => (), + } +} + +fn bad_indirect_mutation_in_guard3(mut a: &bool) { + // Same as bad_indirect_mutation_in_guard2, but using match ergonomics + match a { + true => (), + false if { + a = &true; //~ ERROR + false + } => (), + false => (), + } +} + +fn bad_indirect_mutation_in_guard4(mut b: &bool) { + match b { + &_ => (), + &_ if { + b = &true; //~ ERROR + false + } => (), + &b => (), + } +} + +fn main() {} diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr new file mode 100644 index 0000000000000..2cbfeb886b572 --- /dev/null +++ b/src/test/ui/nll/match-guards-partially-borrow.stderr @@ -0,0 +1,132 @@ +error[E0510]: cannot assign `q` in match guard + --> $DIR/match-guards-partially-borrow.rs:35:13 + | +LL | match q { + | - value is immutable in match guard +... +LL | q = true; //~ ERROR + | ^^^^^^^^ cannot assign +... +LL | _ => (), + | - borrow later used here + +error[E0510]: cannot assign `r` in match guard + --> $DIR/match-guards-partially-borrow.rs:47:13 + | +LL | match r { + | - value is immutable in match guard +... +LL | r = true; //~ ERROR + | ^^^^^^^^ cannot assign +... +LL | _ => (), + | - borrow later used here + +error[E0503]: cannot use `s` because it was mutably borrowed + --> $DIR/match-guards-partially-borrow.rs:56:11 + | +LL | let h = &mut s; + | ------ borrow of `s` occurs here +LL | match s { //~ ERROR + | ^ use of borrowed `s` +... +LL | *h = !*h; + | -- borrow later used here + +error[E0510]: cannot assign `t` in match guard + --> $DIR/match-guards-partially-borrow.rs:71:13 + | +LL | match t { + | - value is immutable in match guard +... +LL | t = true; //~ ERROR + | ^^^^^^^^ cannot assign +... +LL | false => (), + | ----- borrow later used here + +error[E0506]: cannot assign to `u` because it is borrowed + --> $DIR/match-guards-partially-borrow.rs:83:13 + | +LL | match u { + | - borrow of `u` occurs here +... +LL | u = true; //~ ERROR + | ^^^^^^^^ assignment to borrowed `u` occurs here +... +LL | x => (), + | - borrow later used here + +error[E0510]: cannot mutably borrow `x.0` in match guard + --> $DIR/match-guards-partially-borrow.rs:97:22 + | +LL | match x { + | - value is immutable in match guard +... +LL | Some(ref mut r) => *r = None, //~ ERROR + | ^^^^^^^^^ cannot mutably borrow + +error[E0506]: cannot assign to `*w.0` because it is borrowed + --> $DIR/match-guards-partially-borrow.rs:112:13 + | +LL | match w { + | - borrow of `*w.0` occurs here +... +LL | *w.0 = true; //~ ERROR + | ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here +... +LL | x => (), + | - borrow later used here + +error[E0510]: cannot assign `y` in match guard + --> $DIR/match-guards-partially-borrow.rs:123:13 + | +LL | match *y { + | -- value is immutable in match guard +... +LL | y = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | false => (), + | ----- borrow later used here + +error[E0510]: cannot assign `z` in match guard + --> $DIR/match-guards-partially-borrow.rs:134:13 + | +LL | match z { + | - value is immutable in match guard +... +LL | z = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | &false => (), + | ------ borrow later used here + +error[E0510]: cannot assign `a` in match guard + --> $DIR/match-guards-partially-borrow.rs:146:13 + | +LL | match a { + | - value is immutable in match guard +... +LL | a = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | false => (), + | ----- borrow later used here + +error[E0510]: cannot assign `b` in match guard + --> $DIR/match-guards-partially-borrow.rs:157:13 + | +LL | match b { + | - value is immutable in match guard +... +LL | b = &true; //~ ERROR + | ^^^^^^^^^ cannot assign +... +LL | &b => (), + | -- borrow later used here + +error: aborting due to 11 previous errors + +Some errors occurred: E0503, E0506, E0510. +For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/nll/match-on-borrowed.rs b/src/test/ui/nll/match-on-borrowed.rs new file mode 100644 index 0000000000000..6a8ce03e8fd25 --- /dev/null +++ b/src/test/ui/nll/match-on-borrowed.rs @@ -0,0 +1,95 @@ +// Test that a (partially) mutably borrowed place can be matched on, so long as +// we don't have to read any values that are mutably borrowed to determine +// which arm to take. +// +// Test that we don't allow mutating the value being matched on in a way that +// changes which patterns it matches, until we have chosen an arm. + +#![feature(nll)] + +struct A(i32, i32); + +fn struct_example(mut a: A) { + let x = &mut a.0; + match a { // OK, no access of borrowed data + _ if false => (), + A(_, r) => (), + } + x; +} + +fn indirect_struct_example(mut b: &mut A) { + let x = &mut b.0; + match *b { // OK, no access of borrowed data + _ if false => (), + A(_, r) => (), + } + x; +} + +fn underscore_example(mut c: i32) { + let r = &mut c; + match c { // OK, no access of borrowed data (or any data at all) + _ if false => (), + _ => (), + } + r; +} + +enum E { + V(i32, i32), + W, +} + +fn enum_example(mut e: E) { + let x = match e { + E::V(ref mut x, _) => x, + E::W => panic!(), + }; + match e { // OK, no access of borrowed data + _ if false => (), + E::V(_, r) => (), + E::W => (), + } + x; +} + +fn indirect_enum_example(mut f: &mut E) { + let x = match *f { + E::V(ref mut x, _) => x, + E::W => panic!(), + }; + match f { // OK, no access of borrowed data + _ if false => (), + E::V(_, r) => (), + E::W => (), + } + x; +} + +fn match_on_muatbly_borrowed_ref(mut p: &bool) { + let r = &mut p; + match *p { // OK, no access at all + _ if false => (), + _ => (), + } + r; +} + +fn match_on_borrowed(mut t: bool) { + let x = &mut t; + match t { + true => (), //~ ERROR + false => (), + } + x; +} + +enum Never {} + +fn never_init() { + let n: Never; + match n {} //~ ERROR +} + +fn main() {} diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr new file mode 100644 index 0000000000000..cdff29d44b85b --- /dev/null +++ b/src/test/ui/nll/match-on-borrowed.stderr @@ -0,0 +1,22 @@ +error[E0503]: cannot use `t` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:82:9 + | +LL | let x = &mut t; + | ------ borrow of `t` occurs here +LL | match t { +LL | true => (), //~ ERROR + | ^^^^ use of borrowed `t` +... +LL | x; + | - borrow later used here + +error[E0381]: use of possibly uninitialized variable: `n` + --> $DIR/match-on-borrowed.rs:92:11 + | +LL | match n {} //~ ERROR + | ^ use of possibly uninitialized `n` + +error: aborting due to 2 previous errors + +Some errors occurred: E0381, E0503. +For more information about an error, try `rustc --explain E0381`. From 1a6ed0271e7cc8864e6030d945b92aaa850e4afe Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Thu, 13 Sep 2018 22:04:09 +0100 Subject: [PATCH 6/9] Update ui tests --- .../borrowck-anon-fields-struct.nll.stderr | 29 +-- .../borrowck-anon-fields-tuple.nll.stderr | 29 +-- .../borrowck-anon-fields-variant.nll.stderr | 29 +-- .../borrowck-borrow-from-owned-ptr.nll.stderr | 13 +- ...owck-borrow-from-stack-variable.nll.stderr | 13 +- .../borrowck-describe-lvalue.ast.nll.stderr | 179 +----------------- .../borrowck-describe-lvalue.ast.stderr | 12 +- .../borrowck-describe-lvalue.mir.stderr | 179 +----------------- .../ui/borrowck/borrowck-describe-lvalue.rs | 28 +-- ...owck-match-already-borrowed.ast.nll.stderr | 28 +-- ...borrowck-match-already-borrowed.ast.stderr | 2 +- ...borrowck-match-already-borrowed.mir.stderr | 28 +-- .../borrowck-match-already-borrowed.rs | 4 +- .../conditional_array_execution.nll.stderr | 47 ----- .../consts/const-eval/issue-43197.nll.stderr | 70 ------- .../consts/const-eval/issue-44578.nll.stderr | 33 ---- ...issue-27282-move-match-input-into-guard.rs | 1 - ...e-27282-move-match-input-into-guard.stderr | 23 +-- ...sue-27282-mutate-before-diverging-arm-1.rs | 2 +- ...27282-mutate-before-diverging-arm-1.stderr | 13 +- ...sue-27282-mutate-before-diverging-arm-2.rs | 2 +- ...27282-mutate-before-diverging-arm-2.stderr | 13 +- src/test/ui/nll/borrowed-match-issue-45045.rs | 2 +- .../ui/nll/borrowed-match-issue-45045.stderr | 14 +- 24 files changed, 73 insertions(+), 720 deletions(-) delete mode 100644 src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr delete mode 100644 src/test/ui/consts/const-eval/issue-43197.nll.stderr delete mode 100644 src/test/ui/consts/const-eval/issue-44578.nll.stderr diff --git a/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr index 0fe9106249be9..963a89ed44da6 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-struct.nll.stderr @@ -1,27 +1,3 @@ -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-struct.rs:23:19 - | -LL | Y(ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-struct.rs:38:19 - | -LL | Y(ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - error[E0499]: cannot borrow `y.0` as mutable more than once at a time --> $DIR/borrowck-anon-fields-struct.rs:39:11 | @@ -34,7 +10,6 @@ LL | Y(ref mut b, _) => b //~ ERROR cannot borrow LL | *a += 1; | ------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr index 015174a9e4579..f06822f7bb6e4 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-tuple.nll.stderr @@ -1,27 +1,3 @@ -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-tuple.rs:21:19 - | -LL | (ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-tuple.rs:36:19 - | -LL | (ref mut a, _) => a - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - error[E0499]: cannot borrow `y.0` as mutable more than once at a time --> $DIR/borrowck-anon-fields-tuple.rs:37:10 | @@ -34,7 +10,6 @@ LL | (ref mut b, _) => b //~ ERROR cannot borrow LL | *a += 1; | ------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr index e4b9f2f2329c6..05197205e814c 100644 --- a/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr +++ b/src/test/ui/borrowck/borrowck-anon-fields-variant.nll.stderr @@ -1,27 +1,3 @@ -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-variant.rs:26:19 - | -LL | Foo::Y(ref mut a, _) => a, - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - -error[E0502]: cannot borrow `y` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-anon-fields-variant.rs:43:19 - | -LL | Foo::Y(ref mut a, _) => a, - | --------- mutable borrow occurs here -... -LL | let b = match y { - | ^ immutable borrow occurs here -... -LL | *a += 1; - | ------- borrow later used here - error[E0499]: cannot borrow `y.0` as mutable more than once at a time --> $DIR/borrowck-anon-fields-variant.rs:44:14 | @@ -34,7 +10,6 @@ LL | Foo::Y(ref mut b, _) => b, //~ ERROR cannot borrow LL | *a += 1; | ------- borrow later used here -error: aborting due to 3 previous errors +error: aborting due to previous error -Some errors occurred: E0499, E0502. -For more information about an error, try `rustc --explain E0499`. +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr index 08d66eb034459..603f4d63f7f4a 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.nll.stderr @@ -28,17 +28,6 @@ LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow LL | *bar1; | ----- borrow later used here -error[E0502]: cannot borrow `*foo` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-owned-ptr.rs:72:11 - | -LL | let bar1 = &mut foo.bar1; - | ------------- mutable borrow occurs here -LL | match *foo { - | ^^^^ immutable borrow occurs here -... -LL | *bar1; - | ----- borrow later used here - error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time --> $DIR/borrowck-borrow-from-owned-ptr.rs:73:21 | @@ -121,7 +110,7 @@ LL | let foo = make_foo(); LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow | ^^^^^^^^^^^^^ cannot borrow as mutable -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors Some errors occurred: E0499, E0502, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr index 8d1b9ca672ac9..3a215f2336aef 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-stack-variable.nll.stderr @@ -28,17 +28,6 @@ LL | let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow LL | *bar1; | ----- borrow later used here -error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-borrow-from-stack-variable.rs:70:11 - | -LL | let bar1 = &mut foo.bar1; - | ------------- mutable borrow occurs here -LL | match foo { - | ^^^ immutable borrow occurs here -... -LL | *bar1; - | ----- borrow later used here - error[E0499]: cannot borrow `foo.bar1` as mutable more than once at a time --> $DIR/borrowck-borrow-from-stack-variable.rs:71:21 | @@ -121,7 +110,7 @@ LL | let foo = make_foo(); LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow | ^^^^^^^^^^^^^ cannot borrow as mutable -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors Some errors occurred: E0499, E0502, E0596. For more information about an error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr index ae706ef64dd22..e417dadf6df16 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.nll.stderr @@ -72,23 +72,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:77:15 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:78:20 | LL | let x = e.x(); | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` ... @@ -139,23 +128,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `*e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:120:15 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed - | ^^ use of borrowed `*e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:121:20 | LL | let x = e.x(); | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed +LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` ... @@ -173,41 +151,18 @@ LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:139:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:140:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x, _, .., _, _] => println!("{}", x), | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:145:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:146:18 | @@ -220,18 +175,6 @@ LL | &[_, x, .., _, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:151:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:152:25 | @@ -244,18 +187,6 @@ LL | &[_, _, .., x, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:157:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:158:28 | @@ -268,41 +199,18 @@ LL | &[_, _, .., _, x] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:169:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:170:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x..] => println!("{:?}", x), | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:175:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:176:18 | @@ -315,18 +223,6 @@ LL | &[_, x..] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:181:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:182:15 | @@ -339,18 +235,6 @@ LL | &[x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:187:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:188:18 | @@ -363,23 +247,12 @@ LL | &[_, x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:201:15 - | -LL | let x = &mut e; - | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:202:13 | LL | let x = &mut e; | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^^^^^^^ use of borrowed `e` ... @@ -391,7 +264,7 @@ error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mu | LL | let x = &mut e; | ------ mutable borrow occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^ immutable borrow occurs here ... @@ -410,41 +283,18 @@ LL | E::B { x: ref bx } => LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:220:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - borrow later used here - error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable --> $DIR/borrowck-describe-lvalue.rs:221:22 | LL | let x = &mut s; | ------ mutable borrow occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed +LL | match s { LL | S { y: (ref y0, _), .. } => | ^^^^^^ immutable borrow occurs here ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:227:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -... -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - borrow later used here - error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable --> $DIR/borrowck-describe-lvalue.rs:228:28 | @@ -479,23 +329,12 @@ LL | v[0].y; LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:282:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable --> $DIR/borrowck-describe-lvalue.rs:283:24 | LL | let x = &mut v; | ------ mutable borrow occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), | ^^^^^^ immutable borrow occurs here ... @@ -534,7 +373,7 @@ LL | drop(x); //[ast]~ ERROR use of moved value: `x` | = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 46 previous errors +error: aborting due to 32 previous errors Some errors occurred: E0382, E0499, E0502, E0503. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr index ca9b2dda8bcf3..bc6385ffd920b 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.ast.stderr @@ -27,7 +27,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed | LL | let x = e.x(); | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` @@ -68,7 +68,7 @@ error[E0503]: cannot use `e.0` because it was mutably borrowed | LL | let x = e.x(); | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed +LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` @@ -85,7 +85,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed | LL | let x = &mut v; | - borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x, _, .., _, _] => println!("{}", x), | ^ use of borrowed `v` @@ -121,7 +121,7 @@ error[E0503]: cannot use `v[..]` because it was mutably borrowed | LL | let x = &mut v; | - borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x..] => println!("{:?}", x), | ^ use of borrowed `v` @@ -157,7 +157,7 @@ error[E0502]: cannot borrow `e.0` as immutable because `e` is also borrowed as m | LL | let x = &mut e; | - mutable borrow occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^ immutable borrow occurs here ... @@ -181,7 +181,7 @@ error[E0502]: cannot borrow `s.y.0` as immutable because `s` is also borrowed as | LL | let x = &mut s; | - mutable borrow occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed +LL | match s { LL | S { y: (ref y0, _), .. } => | ^^^^^^ immutable borrow occurs here ... diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr index ae706ef64dd22..e417dadf6df16 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.mir.stderr @@ -72,23 +72,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:77:15 - | -LL | let x = e.x(); - | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:78:20 | LL | let x = e.x(); | - borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `e` ... @@ -139,23 +128,12 @@ LL | //[mir]~^ ERROR cannot use `h.0` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `*e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:120:15 - | -LL | let x = e.x(); - | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed - | ^^ use of borrowed `*e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e.0` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:121:20 | LL | let x = e.x(); | - borrow of `*e` occurs here -LL | match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed +LL | match *e { LL | Baz::X(value) => value | ^^^^^ use of borrowed `*e` ... @@ -173,41 +151,18 @@ LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrow LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:139:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:140:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x, _, .., _, _] => println!("{}", x), | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:145:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:146:18 | @@ -220,18 +175,6 @@ LL | &[_, x, .., _, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:151:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:152:25 | @@ -244,18 +187,6 @@ LL | &[_, _, .., x, _] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:157:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:158:28 | @@ -268,41 +199,18 @@ LL | &[_, _, .., _, x] => println!("{}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:169:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:170:15 | LL | let x = &mut v; | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[x..] => println!("{:?}", x), | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:175:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:176:18 | @@ -315,18 +223,6 @@ LL | &[_, x..] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:181:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:182:15 | @@ -339,18 +235,6 @@ LL | &[x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:187:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -... -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `v[..]` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:188:18 | @@ -363,23 +247,12 @@ LL | &[_, x.., _] => println!("{:?}", x), LL | drop(x); | - borrow later used here -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:201:15 - | -LL | let x = &mut e; - | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed - | ^ use of borrowed `e` -... -LL | drop(x); - | - borrow later used here - error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:202:13 | LL | let x = &mut e; | ------ borrow of `e` occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^^^^^^^ use of borrowed `e` ... @@ -391,7 +264,7 @@ error[E0502]: cannot borrow `e.0` as immutable because it is also borrowed as mu | LL | let x = &mut e; | ------ mutable borrow occurs here -LL | match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed +LL | match e { LL | E::A(ref ax) => | ^^^^^^ immutable borrow occurs here ... @@ -410,41 +283,18 @@ LL | E::B { x: ref bx } => LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:220:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - borrow later used here - error[E0502]: cannot borrow `s.y.0` as immutable because it is also borrowed as mutable --> $DIR/borrowck-describe-lvalue.rs:221:22 | LL | let x = &mut s; | ------ mutable borrow occurs here -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed +LL | match s { LL | S { y: (ref y0, _), .. } => | ^^^^^^ immutable borrow occurs here ... LL | drop(x); | - borrow later used here -error[E0503]: cannot use `s` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:227:15 - | -LL | let x = &mut s; - | ------ borrow of `s` occurs here -... -LL | match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed - | ^ use of borrowed `s` -... -LL | drop(x); - | - borrow later used here - error[E0502]: cannot borrow `s.x.y` as immutable because it is also borrowed as mutable --> $DIR/borrowck-describe-lvalue.rs:228:28 | @@ -479,23 +329,12 @@ LL | v[0].y; LL | drop(x); | - borrow later used here -error[E0503]: cannot use `v` because it was mutably borrowed - --> $DIR/borrowck-describe-lvalue.rs:282:15 - | -LL | let x = &mut v; - | ------ borrow of `v` occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed - | ^ use of borrowed `v` -... -LL | drop(x); - | - borrow later used here - error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable --> $DIR/borrowck-describe-lvalue.rs:283:24 | LL | let x = &mut v; | ------ mutable borrow occurs here -LL | match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed +LL | match v { LL | &[_, F {x: ref xf, ..}] => println!("{}", xf), | ^^^^^^ immutable borrow occurs here ... @@ -534,7 +373,7 @@ LL | drop(x); //[ast]~ ERROR use of moved value: `x` | = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait -error: aborting due to 46 previous errors +error: aborting due to 32 previous errors Some errors occurred: E0382, E0499, E0502, E0503. For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.rs b/src/test/ui/borrowck/borrowck-describe-lvalue.rs index b821c7cfa34ff..2ef08e75cfda3 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.rs +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.rs @@ -74,7 +74,7 @@ fn main() { { let mut e = Baz::X(2); let x = e.x(); - match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed + match e { Baz::X(value) => value //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed @@ -117,7 +117,7 @@ fn main() { { let mut e = Box::new(Baz::X(3)); let x = e.x(); - match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed + match *e { Baz::X(value) => value //[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed //[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed @@ -136,25 +136,25 @@ fn main() { { let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let x = &mut v; - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[x, _, .., _, _] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, x, .., _, _] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, _, .., x, _] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, _, .., _, x] => println!("{}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed @@ -166,25 +166,25 @@ fn main() { { let mut v = &[1, 2, 3, 4, 5]; let x = &mut v; - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[x..] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, x..] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[x.., _] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed _ => panic!("other case"), } - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, x.., _] => println!("{:?}", x), //[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed //[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed @@ -198,7 +198,7 @@ fn main() { let mut e = E::A(3); let x = &mut e; - match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed + match e { E::A(ref ax) => //[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable //[mir]~^^ ERROR cannot borrow `e.0` as immutable because it is also borrowed as mutable @@ -217,14 +217,14 @@ fn main() { struct S { x: F, y: (u32, u32), }; let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) }; let x = &mut s; - match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed + match s { S { y: (ref y0, _), .. } => //[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable //[mir]~^^ ERROR cannot borrow `s.y.0` as immutable because it is also borrowed as mutable println!("y0: {:?}", y0), _ => panic!("other case"), } - match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed + match s { S { x: F { y: ref x0, .. }, .. } => //[ast]~^ ERROR cannot borrow `s.x.y` as immutable because `s` is also borrowed as mutable //[mir]~^^ ERROR cannot borrow `s.x.y` as immutable because it is also borrowed as mutable @@ -279,7 +279,7 @@ fn main() { struct F {x: u32, y: u32}; let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}]; let x = &mut v; - match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed + match v { &[_, F {x: ref xf, ..}] => println!("{}", xf), //[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable // No errors in AST diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr index 8dec40520c4e3..0853018bae942 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.nll.stderr @@ -1,20 +1,9 @@ -error[E0503]: cannot use `foo` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:22:19 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] - | ^^^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - error[E0503]: cannot use `foo` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:23:9 | LL | let p = &mut foo; | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] +LL | let _ = match foo { LL | Foo::B => 1, //[mir]~ ERROR [E0503] | ^^^^^^ use of borrowed `foo` ... @@ -33,23 +22,12 @@ LL | Foo::A(x) => x //[ast]~ ERROR [E0503] LL | drop(p); | - borrow later used here -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:35:19 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] - | ^ use of borrowed `x` -... -LL | drop(r); - | - borrow later used here - error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:36:9 | LL | let r = &mut x; | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] +LL | let _ = match x { LL | x => x + 1, //[ast]~ ERROR [E0503] | ^ use of borrowed `x` ... @@ -68,6 +46,6 @@ LL | y => y + 2, //[ast]~ ERROR [E0503] LL | drop(r); | - borrow later used here -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr index 2e49f90a16997..5ba2f26e2203a 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.ast.stderr @@ -12,7 +12,7 @@ error[E0503]: cannot use `x` because it was mutably borrowed | LL | let r = &mut x; | - borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] +LL | let _ = match x { LL | x => x + 1, //[ast]~ ERROR [E0503] | ^ use of borrowed `x` diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr b/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr index 8dec40520c4e3..0853018bae942 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.mir.stderr @@ -1,20 +1,9 @@ -error[E0503]: cannot use `foo` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:22:19 - | -LL | let p = &mut foo; - | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] - | ^^^ use of borrowed `foo` -... -LL | drop(p); - | - borrow later used here - error[E0503]: cannot use `foo` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:23:9 | LL | let p = &mut foo; | -------- borrow of `foo` occurs here -LL | let _ = match foo { //[mir]~ ERROR [E0503] +LL | let _ = match foo { LL | Foo::B => 1, //[mir]~ ERROR [E0503] | ^^^^^^ use of borrowed `foo` ... @@ -33,23 +22,12 @@ LL | Foo::A(x) => x //[ast]~ ERROR [E0503] LL | drop(p); | - borrow later used here -error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/borrowck-match-already-borrowed.rs:35:19 - | -LL | let r = &mut x; - | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] - | ^ use of borrowed `x` -... -LL | drop(r); - | - borrow later used here - error[E0503]: cannot use `x` because it was mutably borrowed --> $DIR/borrowck-match-already-borrowed.rs:36:9 | LL | let r = &mut x; | ------ borrow of `x` occurs here -LL | let _ = match x { //[mir]~ ERROR [E0503] +LL | let _ = match x { LL | x => x + 1, //[ast]~ ERROR [E0503] | ^ use of borrowed `x` ... @@ -68,6 +46,6 @@ LL | y => y + 2, //[ast]~ ERROR [E0503] LL | drop(r); | - borrow later used here -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0503`. diff --git a/src/test/ui/borrowck/borrowck-match-already-borrowed.rs b/src/test/ui/borrowck/borrowck-match-already-borrowed.rs index c2136e62a7b22..cabce08429e57 100644 --- a/src/test/ui/borrowck/borrowck-match-already-borrowed.rs +++ b/src/test/ui/borrowck/borrowck-match-already-borrowed.rs @@ -19,7 +19,7 @@ enum Foo { fn match_enum() { let mut foo = Foo::B; let p = &mut foo; - let _ = match foo { //[mir]~ ERROR [E0503] + let _ = match foo { Foo::B => 1, //[mir]~ ERROR [E0503] _ => 2, Foo::A(x) => x //[ast]~ ERROR [E0503] @@ -32,7 +32,7 @@ fn match_enum() { fn main() { let mut x = 1; let r = &mut x; - let _ = match x { //[mir]~ ERROR [E0503] + let _ = match x { x => x + 1, //[ast]~ ERROR [E0503] //[mir]~^ ERROR [E0503] y => y + 2, //[ast]~ ERROR [E0503] diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr deleted file mode 100644 index 86287e1299729..0000000000000 --- a/src/test/ui/consts/const-eval/conditional_array_execution.nll.stderr +++ /dev/null @@ -1,47 +0,0 @@ -warning: this constant cannot be used - --> $DIR/conditional_array_execution.rs:15:1 - | -LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ^^^^^^^^^^^^^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | attempt to subtract with overflow - | -note: lint level defined here - --> $DIR/conditional_array_execution.rs:11:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:19:14 - | -LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ----- attempt to subtract with overflow -... -LL | println!("{}", FOO); - | ^^^^ - -error[E0080]: erroneous constant used - --> $DIR/conditional_array_execution.rs:19:14 - | -LL | println!("{}", FOO); - | ^^^^ --- referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/conditional_array_execution.rs:19:20 - | -LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ----- attempt to subtract with overflow -... -LL | println!("{}", FOO); - | ^^^ - -error[E0080]: erroneous constant used - --> $DIR/conditional_array_execution.rs:19:20 - | -LL | println!("{}", FOO); - | ^^^ referenced constant has errors - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-43197.nll.stderr b/src/test/ui/consts/const-eval/issue-43197.nll.stderr deleted file mode 100644 index 732fe45983460..0000000000000 --- a/src/test/ui/consts/const-eval/issue-43197.nll.stderr +++ /dev/null @@ -1,70 +0,0 @@ -warning: this constant cannot be used - --> $DIR/issue-43197.rs:20:5 - | -LL | const X: u32 = 0-1; - | ^^^^^^^^^^^^^^^---^ - | | - | attempt to subtract with overflow - | -note: lint level defined here - --> $DIR/issue-43197.rs:11:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - -warning: this constant cannot be used - --> $DIR/issue-43197.rs:22:5 - | -LL | const Y: u32 = foo(0-1); - | ^^^^^^^^^^^^^^^^^^^---^^ - | | - | attempt to subtract with overflow - -error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:14 - | -LL | const X: u32 = 0-1; - | --- attempt to subtract with overflow -... -LL | println!("{} {}", X, Y); - | ^^^^^^^ - -error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:14 - | -LL | println!("{} {}", X, Y); - | ^^^^^^^ - referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:26 - | -LL | const Y: u32 = foo(0-1); - | --- attempt to subtract with overflow -LL | //~^ WARN this constant cannot be used -LL | println!("{} {}", X, Y); - | ^ - -error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:26 - | -LL | println!("{} {}", X, Y); - | ^ referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/issue-43197.rs:24:23 - | -LL | const X: u32 = 0-1; - | --- attempt to subtract with overflow -... -LL | println!("{} {}", X, Y); - | ^ - -error[E0080]: erroneous constant used - --> $DIR/issue-43197.rs:24:23 - | -LL | println!("{} {}", X, Y); - | ^ referenced constant has errors - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-44578.nll.stderr b/src/test/ui/consts/const-eval/issue-44578.nll.stderr deleted file mode 100644 index da040747991a4..0000000000000 --- a/src/test/ui/consts/const-eval/issue-44578.nll.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0080]: referenced constant has errors - --> $DIR/issue-44578.rs:35:14 - | -LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; - | ------------------------------------ index out of bounds: the len is 1 but the index is 1 -... -LL | println!("{}", as Foo>::AMT); - | ^^^^ - -error[E0080]: erroneous constant used - --> $DIR/issue-44578.rs:35:14 - | -LL | println!("{}", as Foo>::AMT); - | ^^^^ -------------------------- referenced constant has errors - -error[E0080]: referenced constant has errors - --> $DIR/issue-44578.rs:35:20 - | -LL | const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize]; - | ------------------------------------ index out of bounds: the len is 1 but the index is 1 -... -LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0080]: erroneous constant used - --> $DIR/issue-44578.rs:35:20 - | -LL | println!("{}", as Foo>::AMT); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs b/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs index b3be36e41e657..909c369354bc3 100644 --- a/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs +++ b/src/test/ui/issues/issue-27282-move-match-input-into-guard.rs @@ -24,7 +24,6 @@ fn main() { match b { &mut false => {}, _ if { (|| { let bar = b; *bar = false; })(); - //~^ ERROR cannot move out of `b` because it is borrowed [E0505] false } => { }, &mut true => { println!("You might think we should get here"); }, //~^ ERROR use of moved value: `*b` [E0382] diff --git a/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr b/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr index 91c51bcd05825..0b783e37615ee 100644 --- a/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr +++ b/src/test/ui/issues/issue-27282-move-match-input-into-guard.stderr @@ -1,29 +1,14 @@ -error[E0505]: cannot move out of `b` because it is borrowed - --> $DIR/issue-27282-move-match-input-into-guard.rs:26:17 - | -LL | match b { - | - borrow of `b` occurs here -LL | &mut false => {}, -LL | _ if { (|| { let bar = b; *bar = false; })(); - | ^^ - move occurs due to use in closure - | | - | move out of `b` occurs here -... -LL | &mut true => { println!("You might think we should get here"); }, - | --------- borrow later used here - error[E0382]: use of moved value: `*b` - --> $DIR/issue-27282-move-match-input-into-guard.rs:29:14 + --> $DIR/issue-27282-move-match-input-into-guard.rs:28:14 | LL | _ if { (|| { let bar = b; *bar = false; })(); | -- - variable moved due to use in closure | | | value moved into closure here -... +LL | false } => { }, LL | &mut true => { println!("You might think we should get here"); }, | ^^^^ value used here after move -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0382, E0505. -For more information about an error, try `rustc --explain E0382`. +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs index b575f4ebce6c0..2ebfb995d8ca9 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.rs @@ -31,7 +31,7 @@ fn main() { &mut Some(&_) if { // ForceFnOnce needed to exploit #27282 (|| { *x = None; drop(force_fn_once); })(); - //~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500] + //~^ ERROR cannot mutably borrow `x` in match guard [E0510] false } => {} &mut Some(&a) if { // this binds to garbage if we've corrupted discriminant diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr index a9d9651fb2a35..2ecbb25fd3e47 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-1.stderr @@ -1,17 +1,14 @@ -error[E0500]: closure requires unique access to `x` but it is already borrowed +error[E0510]: cannot mutably borrow `x` in match guard --> $DIR/issue-27282-mutate-before-diverging-arm-1.rs:33:14 | LL | match x { - | - borrow occurs here + | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ - borrow occurs due to use of `x` in closure | | - | closure construction occurs here -... -LL | &mut Some(&a) if { // this binds to garbage if we've corrupted discriminant - | ------------- borrow later used here + | cannot mutably borrow error: aborting due to previous error -For more information about this error, try `rustc --explain E0500`. +For more information about this error, try `rustc --explain E0510`. diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs index 866fed1368504..6b50973e04d06 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.rs @@ -36,7 +36,7 @@ fn main() { if { // ForceFnOnce needed to exploit #27282 (|| { *x = None; drop(force_fn_once); })(); - //~^ ERROR closure requires unique access to `x` but it is already borrowed [E0500] + //~^ ERROR cannot mutably borrow `x` in match guard [E0510] false } => {} diff --git a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr index 582d0fd678c07..6feef95300e05 100644 --- a/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr +++ b/src/test/ui/issues/issue-27282-mutate-before-diverging-arm-2.stderr @@ -1,17 +1,14 @@ -error[E0500]: closure requires unique access to `x` but it is already borrowed +error[E0510]: cannot mutably borrow `x` in match guard --> $DIR/issue-27282-mutate-before-diverging-arm-2.rs:38:18 | LL | match x { - | - borrow occurs here + | - value is immutable in match guard ... LL | (|| { *x = None; drop(force_fn_once); })(); - | ^^ - second borrow occurs due to use of `x` in closure + | ^^ - borrow occurs due to use of `x` in closure | | - | closure construction occurs here -... -LL | &mut Some(&2) - | ------------- borrow later used here + | cannot mutably borrow error: aborting due to previous error -For more information about this error, try `rustc --explain E0500`. +For more information about this error, try `rustc --explain E0510`. diff --git a/src/test/ui/nll/borrowed-match-issue-45045.rs b/src/test/ui/nll/borrowed-match-issue-45045.rs index 4b95bbd5a052b..8688bfa86dc6f 100644 --- a/src/test/ui/nll/borrowed-match-issue-45045.rs +++ b/src/test/ui/nll/borrowed-match-issue-45045.rs @@ -21,7 +21,7 @@ fn main() { let mut e = Xyz::A; let f = &mut e; let g = f; - match e { //~ cannot use `e` because it was mutably borrowed [E0503] + match e { Xyz::A => println!("a"), //~^ cannot use `e` because it was mutably borrowed [E0503] Xyz::B => println!("b"), diff --git a/src/test/ui/nll/borrowed-match-issue-45045.stderr b/src/test/ui/nll/borrowed-match-issue-45045.stderr index acbba9ee18754..ded773165c6fe 100644 --- a/src/test/ui/nll/borrowed-match-issue-45045.stderr +++ b/src/test/ui/nll/borrowed-match-issue-45045.stderr @@ -1,15 +1,3 @@ -error[E0503]: cannot use `e` because it was mutably borrowed - --> $DIR/borrowed-match-issue-45045.rs:24:11 - | -LL | let f = &mut e; - | ------ borrow of `e` occurs here -LL | let g = f; -LL | match e { //~ cannot use `e` because it was mutably borrowed [E0503] - | ^ use of borrowed `e` -... -LL | *g = Xyz::B; - | ----------- borrow later used here - error[E0503]: cannot use `e` because it was mutably borrowed --> $DIR/borrowed-match-issue-45045.rs:25:9 | @@ -22,6 +10,6 @@ LL | Xyz::A => println!("a"), LL | *g = Xyz::B; | ----------- borrow later used here -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0503`. From f71f733d482d892b5bff021b3955435e7b3eee25 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 23 Sep 2018 10:43:14 +0100 Subject: [PATCH 7/9] Add a MIR transform to remove fake reads As we are now creating borrows of places that may not be valid for borrow checking matches, these have to be removed to avoid generating broken code. --- src/librustc_mir/lib.rs | 2 +- .../transform/cleanup_post_borrowck.rs | 62 ++++++++- src/librustc_mir/transform/mod.rs | 5 +- src/test/mir-opt/remove_fake_borrows.rs | 122 ++++++++++++++++++ 4 files changed, 188 insertions(+), 3 deletions(-) create mode 100644 src/test/mir-opt/remove_fake_borrows.rs diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 4546e0bf253c3..a2d70bc05c1d4 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -14,7 +14,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! */ -#![cfg_attr(not(stage0), feature(nll))] +#![feature(nll)] #![feature(in_band_lifetimes)] #![feature(impl_header_lifetime_elision)] #![feature(slice_patterns)] diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/src/librustc_mir/transform/cleanup_post_borrowck.rs index 9edb1a1f76a6d..aaba7ab8418f5 100644 --- a/src/librustc_mir/transform/cleanup_post_borrowck.rs +++ b/src/librustc_mir/transform/cleanup_post_borrowck.rs @@ -33,7 +33,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc::middle::region; -use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind}; +use rustc::mir::{BasicBlock, FakeReadCause, Local, Location, Mir, Place}; +use rustc::mir::{Rvalue, Statement, StatementKind}; use rustc::mir::visit::{MutVisitor, Visitor, TyContext}; use rustc::ty::{Ty, RegionKind, TyCtxt}; use transform::{MirPass, MirSource}; @@ -135,3 +136,62 @@ impl<'tcx> MutVisitor<'tcx> for DeleteAscribeUserType { self.super_statement(block, statement, location); } } + +pub struct CleanFakeReadsAndBorrows; + +pub struct DeleteAndRecordFakeReads { + fake_borrow_temporaries: FxHashSet, +} + +pub struct DeleteFakeBorrows { + fake_borrow_temporaries: FxHashSet, +} + +// Removes any FakeReads from the MIR +impl MirPass for CleanFakeReadsAndBorrows { + fn run_pass<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source: MirSource, + mir: &mut Mir<'tcx>) { + let mut delete_reads = DeleteAndRecordFakeReads { + fake_borrow_temporaries: FxHashSet(), + }; + delete_reads.visit_mir(mir); + let mut delete_borrows = DeleteFakeBorrows { + fake_borrow_temporaries: delete_reads.fake_borrow_temporaries, + }; + delete_borrows.visit_mir(mir); + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteAndRecordFakeReads { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::FakeRead(cause, ref place) = statement.kind { + if let FakeReadCause::ForMatchGuard = cause { + match *place { + Place::Local(local) => self.fake_borrow_temporaries.insert(local), + _ => bug!("Fake match guard read of non-local: {:?}", place), + }; + } + statement.make_nop(); + } + self.super_statement(block, statement, location); + } +} + +impl<'tcx> MutVisitor<'tcx> for DeleteFakeBorrows { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + if let StatementKind::Assign(Place::Local(local), _) = statement.kind { + if self.fake_borrow_temporaries.contains(&local) { + statement.make_nop(); + } + } + self.super_statement(block, statement, location); + } +} diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 19fb35be9d4e0..d18836999dccf 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -237,9 +237,12 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx no_landing_pads::NoLandingPads, simplify_branches::SimplifyBranches::new("initial"), remove_noop_landing_pads::RemoveNoopLandingPads, - simplify::SimplifyCfg::new("early-opt"), // Remove all `AscribeUserType` statements. cleanup_post_borrowck::CleanAscribeUserType, + // Remove all `FakeRead` statements and the borrows that are only + // used for checking matches + cleanup_post_borrowck::CleanFakeReadsAndBorrows, + simplify::SimplifyCfg::new("early-opt"), // These next passes must be executed together add_call_guards::CriticalCallEdges, diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs new file mode 100644 index 0000000000000..8411fba02e977 --- /dev/null +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -0,0 +1,122 @@ +// Test that the fake borrows for matches are removed after borrow checking. + +// ignore-wasm32-bare + +#![feature(nll)] + +fn match_guard(x: Option<&&i32>) -> i32 { + match x { + Some(0) if true => 0, + _ => 1, + } +} + +fn main() { + match_guard(None); +} + +// END RUST SOURCE + +// START rustc.match_guard.CleanFakeReadsAndBorrows.before.mir +// bb0: { +// FakeRead(ForMatchedPlace, _1); +// _2 = discriminant(_1); +// _3 = &shallow _1; +// _4 = &shallow ((_1 as Some).0: &' &' i32); +// _5 = &shallow (*((_1 as Some).0: &' &' i32)); +// _6 = &shallow (*(*((_1 as Some).0: &' &' i32))); +// switchInt(move _2) -> [1isize: bb6, otherwise: bb4]; +// } +// bb1: { +// _0 = const 0i32; +// goto -> bb9; +// } +// bb2: { +// _0 = const 1i32; +// goto -> bb9; +// } +// bb3: { +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForMatchGuard, _5); +// FakeRead(ForMatchGuard, _6); +// goto -> bb7; +// } +// bb4: { +// FakeRead(ForMatchGuard, _3); +// FakeRead(ForMatchGuard, _4); +// FakeRead(ForMatchGuard, _5); +// FakeRead(ForMatchGuard, _6); +// goto -> bb2; +// } +// bb5: { +// unreachable; +// } +// bb6: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb4]; +// } +// bb7: { +// goto -> bb1; +// } +// bb8: { +// goto -> bb4; +// } +// bb9: { +// return; +// } +// bb10: { +// resume; +// } +// END rustc.match_guard.CleanFakeReadsAndBorrows.before.mir + +// START rustc.match_guard.CleanFakeReadsAndBorrows.after.mir +// bb0: { +// nop; +// _2 = discriminant(_1); +// nop; +// nop; +// nop; +// nop; +// switchInt(move _2) -> [1isize: bb6, otherwise: bb4]; +// } +// bb1: { +// _0 = const 0i32; +// goto -> bb9; +// } +// bb2: { +// _0 = const 1i32; +// goto -> bb9; +// } +// bb3: { +// nop; +// nop; +// nop; +// nop; +// goto -> bb7; +// } +// bb4: { +// nop; +// nop; +// nop; +// nop; +// goto -> bb2; +// } +// bb5: { +// unreachable; +// } +// bb6: { +// switchInt((*(*((_1 as Some).0: &' &' i32)))) -> [0i32: bb3, otherwise: bb4]; +// } +// bb7: { +// goto -> bb1; +// } +// bb8: { +// goto -> bb4; +// } +// bb9: { +// return; +// } +// bb10: { +// resume; +// } +// END rustc.match_guard.CleanFakeReadsAndBorrows.after.mir From 531e98a0d80af18da51a0bec6a39b0c9d7e33fb4 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sat, 15 Sep 2018 11:18:45 +0100 Subject: [PATCH 8/9] Update mir opt tests --- src/test/mir-opt/box_expr.rs | 1 - src/test/mir-opt/issue-49232.rs | 21 ++-- src/test/mir-opt/match_false_edges.rs | 143 ++++++++++++++------------ src/test/mir-opt/validate_1.rs | 1 - src/test/mir-opt/validate_2.rs | 1 - src/test/mir-opt/validate_3.rs | 2 - 6 files changed, 88 insertions(+), 81 deletions(-) diff --git a/src/test/mir-opt/box_expr.rs b/src/test/mir-opt/box_expr.rs index f6877d979e073..8390a0d19ae7b 100644 --- a/src/test/mir-opt/box_expr.rs +++ b/src/test/mir-opt/box_expr.rs @@ -63,7 +63,6 @@ impl Drop for S { // // bb4: { // StorageDead(_2); -// FakeRead(ForLet, _1); // StorageLive(_4); // _4 = move _1; // _3 = const std::mem::drop(move _4) -> [return: bb5, unwind: bb7]; diff --git a/src/test/mir-opt/issue-49232.rs b/src/test/mir-opt/issue-49232.rs index 3bc735bc6c5ed..f9024b6706334 100644 --- a/src/test/mir-opt/issue-49232.rs +++ b/src/test/mir-opt/issue-49232.rs @@ -34,10 +34,9 @@ fn main() { // } // let mut _1: (); // let mut _3: bool; -// let mut _4: u8; -// let mut _5: !; -// let mut _6: (); -// let mut _7: &i32; +// let mut _4: !; +// let mut _5: (); +// let mut _6: &i32; // bb0: { // goto -> bb1; // } @@ -51,7 +50,7 @@ fn main() { // StorageLive(_2); // StorageLive(_3); // _3 = const true; -// _4 = discriminant(_3); +// FakeRead(ForMatchedPlace, _3); // switchInt(_3) -> [false: bb11, otherwise: bb10]; // } // bb4: { @@ -89,9 +88,9 @@ fn main() { // bb14: { // FakeRead(ForLet, _2); // StorageDead(_3); -// StorageLive(_7); -// _7 = &_2; -// _6 = const std::mem::drop(move _7) -> [return: bb28, unwind: bb4]; +// StorageLive(_6); +// _6 = &_2; +// _5 = const std::mem::drop(move _6) -> [return: bb28, unwind: bb4]; // } // bb15: { // goto -> bb16; @@ -129,15 +128,15 @@ fn main() { // goto -> bb2; // } // bb26: { -// _5 = (); +// _4 = (); // unreachable; // } // bb27: { -// StorageDead(_5); +// StorageDead(_4); // goto -> bb14; // } // bb28: { -// StorageDead(_7); +// StorageDead(_6); // _1 = (); // StorageDead(_2); // goto -> bb1; diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index b9f4c23912737..9ccf037139945 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -53,10 +53,11 @@ fn main() { // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); -// _3 = discriminant(_2); -// _4 = &(promoted[1]: std::option::Option); -// _9 = discriminant(_2); -// switchInt(move _9) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; +// FakeRead(ForMatchedPlace, _2); +// _7 = discriminant(_2); +// _9 = &shallow (promoted[2]: std::option::Option); +// _10 = &(((promoted[1]: std::option::Option) as Some).0: i32); +// switchInt(move _7) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; // } // bb1: { // resume; @@ -66,15 +67,18 @@ fn main() { // goto -> bb13; // } // bb3: { // binding3(empty) and arm3 -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 // } // bb4: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding2 // } // bb5: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb2, imaginary: bb6]; //pre_binding3 // } // bb6: { @@ -84,31 +88,31 @@ fn main() { // unreachable; // } // bb8: { // binding1 and guard -// StorageLive(_7); -// _7 = &(((promoted[0]: std::option::Option) as Some).0: i32); -// StorageLive(_10); -// _10 = const guard() -> [return: bb9, unwind: bb1]; +// StorageLive(_5); +// _5 = &(((promoted[0]: std::option::Option) as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> [return: bb9, unwind: bb1]; // } // bb9: { -// switchInt(move _10) -> [false: bb10, otherwise: bb11]; +// switchInt(move _8) -> [false: bb10, otherwise: bb11]; // } // bb10: { // to pre_binding2 // falseEdges -> [real: bb4, imaginary: bb4]; // } // bb11: { // bindingNoLandingPads.before.mir2 and arm2 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); // StorageLive(_11); -// _11 = _5; +// _11 = _3; // _1 = (const 1i32, move _11); // StorageDead(_11); // goto -> bb13; // } // bb12: { -// StorageLive(_8); -// _8 = ((_2 as Some).0: i32); +// StorageLive(_6); +// _6 = ((_2 as Some).0: i32); // StorageLive(_12); -// _12 = _8; +// _12 = _6; // _1 = (const 2i32, move_12); // StorageDead(_12); // goto -> bb13; @@ -123,10 +127,11 @@ fn main() { // bb0: { // ... // _2 = std::option::Option::Some(const 42i32,); -// _3 = discriminant(_2); -// _4 = &_2; -// _9 = discriminant(_2); -// switchInt(move _9) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; +// FakeRead(ForMatchedPlace, _2); +// _7 = discriminant(_2); +// _9 = &shallow _2; +// _10 = &((_2 as Some).0: i32); +// switchInt(move _7) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; // } // bb1: { // resume; @@ -136,15 +141,18 @@ fn main() { // goto -> bb13; // } // bb3: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb8, imaginary: bb4]; //pre_binding1 // } // bb4: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb2, imaginary: bb5]; //pre_binding2 // } // bb5: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _9); +// FakeRead(ForMatchGuard, _10); // falseEdges -> [real: bb12, imaginary: bb6]; //pre_binding3 // } // bb6: { @@ -154,31 +162,31 @@ fn main() { // unreachable; // } // bb8: { // binding1 and guard -// StorageLive(_7); -// _7 = &((_2 as Some).0: i32); -// StorageLive(_10); -// _10 = const guard() -> [return: bb9, unwind: bb1]; +// StorageLive(_5); +// _5 = &((_2 as Some).0: i32); +// StorageLive(_8); +// _8 = const guard() -> [return: bb9, unwind: bb1]; // } // bb9: { // end of guard -// switchInt(move _10) -> [false: bb10, otherwise: bb11]; +// switchInt(move _8) -> [false: bb10, otherwise: bb11]; // } // bb10: { // to pre_binding3 (can skip 2 since this is `Some`) // falseEdges -> [real: bb5, imaginary: bb4]; // } // bb11: { // arm1 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); // StorageLive(_11); -// _11 = _5; +// _11 = _3; // _1 = (const 1i32, move _11); // StorageDead(_11); // goto -> bb13; // } // bb12: { // binding3 and arm3 -// StorageLive(_8); -// _8 = ((_2 as Some).0: i32); +// StorageLive(_6); +// _6 = ((_2 as Some).0: i32); // StorageLive(_12); -// _12 = _8; +// _12 = _6; // _1 = (const 2i32, move _12); // StorageDead(_12); // goto -> bb13; @@ -193,81 +201,86 @@ fn main() { // bb0: { // ... // _2 = std::option::Option::Some(const 1i32,); -// _3 = discriminant(_2); -// _4 = &_2; -// _13 = discriminant(_2); -// switchInt(move _13) -> [1isize: bb2, otherwise: bb3]; +// FakeRead(ForMatchedPlace, _2); +// _11 = discriminant(_2); +// _16 = &shallow _2; +// _17 = &((_2 as Some).0: i32); +// switchInt(move _11) -> [1isize: bb2, otherwise: bb3]; // } // bb1: { // resume; // } // bb2: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb7, imaginary: bb3]; //pre_binding1 // } // bb3: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb11, imaginary: bb4]; //pre_binding2 // } // bb4: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb12, imaginary: bb5]; //pre_binding3 // } // bb5: { -// FakeRead(ForMatch, _4); +// FakeRead(ForMatchGuard, _16); +// FakeRead(ForMatchGuard, _17); // falseEdges -> [real: bb16, imaginary: bb6]; //pre_binding4 // } // bb6: { // unreachable; // } // bb7: { // binding1: Some(w) if guard() -// StorageLive(_7); -// _7 = &((_2 as Some).0: i32); -// StorageLive(_14); -// _14 = const guard() -> [return: bb8, unwind: bb1]; +// StorageLive(_5); +// _5 = &((_2 as Some).0: i32); +// StorageLive(_12); +// _12 = const guard() -> [return: bb8, unwind: bb1]; // } // bb8: { //end of guard -// switchInt(move _14) -> [false: bb9, otherwise: bb10]; +// switchInt(move _12) -> [false: bb9, otherwise: bb10]; // } // bb9: { // to pre_binding2 // falseEdges -> [real: bb3, imaginary: bb3]; // } // bb10: { // set up bindings for arm1 -// StorageLive(_5); -// _5 = ((_2 as Some).0: i32); +// StorageLive(_3); +// _3 = ((_2 as Some).0: i32); // _1 = const 1i32; // goto -> bb17; // } // bb11: { // binding2 & arm2 -// StorageLive(_8); -// _8 = _2; +// StorageLive(_6); +// _6 = _2; // _1 = const 2i32; // goto -> bb17; // } // bb12: { // binding3: Some(y) if guard2(y) -// StorageLive(_11); -// _11 = &((_2 as Some).0: i32); -// StorageLive(_16); -// StorageLive(_17); -// _17 = (*_11); -// _16 = const guard2(move _17) -> [return: bb13, unwind: bb1]; +// StorageLive(_9); +// _9 = &((_2 as Some).0: i32); +// StorageLive(_14); +// StorageLive(_15); +// _15 = (*_9); +// _14 = const guard2(move _15) -> [return: bb13, unwind: bb1]; // } // bb13: { // end of guard2 -// StorageDead(_17); -// switchInt(move _16) -> [false: bb14, otherwise: bb15]; +// StorageDead(_15); +// switchInt(move _14) -> [false: bb14, otherwise: bb15]; // } // bb14: { // to pre_binding4 // falseEdges -> [real: bb5, imaginary: bb5]; // } // bb15: { // set up bindings for arm3 -// StorageLive(_9); -// _9 = ((_2 as Some).0: i32); +// StorageLive(_7); +// _7 = ((_2 as Some).0: i32); // _1 = const 3i32; // goto -> bb17; // } // bb16: { // binding4 & arm4 -// StorageLive(_12); -// _12 = _2; +// StorageLive(_10); +// _10 = _2; // _1 = const 4i32; // goto -> bb17; // } diff --git a/src/test/mir-opt/validate_1.rs b/src/test/mir-opt/validate_1.rs index 3ea8e99e953b4..882579c571086 100644 --- a/src/test/mir-opt/validate_1.rs +++ b/src/test/mir-opt/validate_1.rs @@ -67,7 +67,6 @@ fn main() { // Validate(Suspend(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })), [(*_2): i32]); // _3 = &ReErased (*_2); // Validate(Acquire, [(*_3): i32/ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 }) (imm)]); -// FakeRead(ForLet, _3); // _0 = (*_3); // EndRegion(ReScope(Remainder { block: ItemLocalId(25), first_statement_index: 0 })); // StorageDead(_3); diff --git a/src/test/mir-opt/validate_2.rs b/src/test/mir-opt/validate_2.rs index 0cb0b7debfaa3..3776a11b3ab82 100644 --- a/src/test/mir-opt/validate_2.rs +++ b/src/test/mir-opt/validate_2.rs @@ -28,7 +28,6 @@ fn main() { // Validate(Acquire, [_1: std::boxed::Box<[i32]>]); // StorageDead(_2); // StorageDead(_3); -// FakeRead(ForLet, _1); // _0 = (); // Validate(Release, [_1: std::boxed::Box<[i32]>]); // drop(_1) -> [return: bb2, unwind: bb3]; diff --git a/src/test/mir-opt/validate_3.rs b/src/test/mir-opt/validate_3.rs index 89b67bd34c83d..07f5b2aa84b7d 100644 --- a/src/test/mir-opt/validate_3.rs +++ b/src/test/mir-opt/validate_3.rs @@ -47,12 +47,10 @@ fn main() { // bb0: { // StorageLive(_1); // _1 = Test { x: const 0i32 }; -// FakeRead(ForLet, _1); // StorageLive(_2); // Validate(Suspend(ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 })), [_1: Test]); // _2 = &ReErased _1; // Validate(Acquire, [(*_2): Test/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]); -// FakeRead(ForLet, _2); // StorageLive(_4); // StorageLive(_5); // Validate(Suspend(ReScope(Node(ItemLocalId(18)))), [((*_2).0: i32): i32/ReScope(Remainder { block: ItemLocalId(20), first_statement_index: 3 }) (imm)]); From a830732090d49c799b3e97e70c1c4e5c011a784c Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 23 Sep 2018 11:33:52 +0100 Subject: [PATCH 9/9] Rename places_conflict to borrow_conflicts_with_place This name better reflects the asymmetry of this function. --- src/librustc_mir/borrow_check/path_utils.rs | 2 +- .../borrow_check/places_conflict.rs | 24 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index ccb7a4056267a..9250c04969f98 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -61,7 +61,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( for i in candidates { let borrowed = &borrow_set[i]; - if places_conflict::places_conflict( + if places_conflict::borrow_conflicts_with_place( tcx, mir, &borrowed.borrowed_place, diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 13ac1d60c9543..c0f059619a497 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -17,7 +17,7 @@ use rustc::mir::{Projection, ProjectionElem}; use rustc::ty::{self, TyCtxt}; use std::cmp::max; -pub(super) fn places_conflict<'gcx, 'tcx>( +pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>( tcx: TyCtxt<'_, 'gcx, 'tcx>, mir: &Mir<'tcx>, borrow_place: &Place<'tcx>, @@ -26,7 +26,7 @@ pub(super) fn places_conflict<'gcx, 'tcx>( access: AccessDepth, ) -> bool { debug!( - "places_conflict({:?},{:?},{:?})", + "borrow_conflicts_with_place({:?},{:?},{:?})", borrow_place, access_place, access ); @@ -104,10 +104,10 @@ fn place_components_conflict<'gcx, 'tcx>( loop { // loop invariant: borrow_c is always either equal to access_c or disjoint from it. if let Some(borrow_c) = borrow_components.next() { - debug!("places_conflict: borrow_c = {:?}", borrow_c); + debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); if let Some(access_c) = access_components.next() { - debug!("places_conflict: access_c = {:?}", access_c); + debug!("borrow_conflicts_with_place: access_c = {:?}", access_c); // Borrow and access path both have more components. // @@ -136,7 +136,7 @@ fn place_components_conflict<'gcx, 'tcx>( // idea, at least for now, so just give up and // report a conflict. This is unsafe code anyway so // the user could always use raw pointers. - debug!("places_conflict: arbitrary -> conflict"); + debug!("borrow_conflicts_with_place: arbitrary -> conflict"); return true; } Overlap::EqualOrDisjoint => { @@ -145,7 +145,7 @@ fn place_components_conflict<'gcx, 'tcx>( Overlap::Disjoint => { // We have proven the borrow disjoint - further // projections will remain disjoint. - debug!("places_conflict: disjoint"); + debug!("borrow_conflicts_with_place: disjoint"); return false; } } @@ -177,7 +177,7 @@ fn place_components_conflict<'gcx, 'tcx>( // // e.g. a (mutable) borrow of `a[5]` while we read the // array length of `a`. - debug!("places_conflict: implicit field"); + debug!("borrow_conflicts_with_place: implicit field"); return false; } @@ -185,7 +185,7 @@ fn place_components_conflict<'gcx, 'tcx>( // e.g. a borrow of `*x.y` while we shallowly access `x.y` or some // prefix thereof - the shallow access can't touch anything behind // the pointer. - debug!("places_conflict: shallow access behind ptr"); + debug!("borrow_conflicts_with_place: shallow access behind ptr"); return false; } (ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => { @@ -195,7 +195,7 @@ fn place_components_conflict<'gcx, 'tcx>( (ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => { // Values behind a mutatble reference are not access either by Dropping a // value, or by StorageDead - debug!("places_conflict: drop access behind ptr"); + debug!("borrow_conflicts_with_place: drop access behind ptr"); return false; } @@ -236,10 +236,10 @@ fn place_components_conflict<'gcx, 'tcx>( // that the borrow can access a *part* of our place that // our access cares about, so we still have a conflict. if borrow_kind == BorrowKind::Shallow && access_components.next().is_some() { - debug!("places_conflict: shallow borrow"); + debug!("borrow_conflicts_with_place: shallow borrow"); return false; } else { - debug!("places_conflict: full borrow, CONFLICT"); + debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); return true; } } @@ -253,7 +253,7 @@ fn place_components_conflict<'gcx, 'tcx>( /// /// NB: This particular impl strategy is not the most obvious. It was /// chosen because it makes a measurable difference to NLL -/// performance, as this code (`places_conflict`) is somewhat hot. +/// performance, as this code (`borrow_conflicts_with_place`) is somewhat hot. struct PlaceComponents<'p, 'tcx: 'p> { component: &'p Place<'tcx>, next: Option<&'p PlaceComponents<'p, 'tcx>>,