diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 313ef054829c5..ec54613d1dbac 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); @@ -272,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 98d9a0a7c6f5e..f856475c3376d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -451,11 +451,32 @@ 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, + /// 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, @@ -1672,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 /// @@ -1773,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), @@ -1790,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>, @@ -1805,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), @@ -2198,6 +2223,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..b775fc81d4f61 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -333,6 +333,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Origin::Mir, ), + (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; + } + (BorrowKind::Unique, _, _, _, _, _) => tcx.cannot_uniquely_borrow_by_one_closure( span, &desc_place, @@ -368,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 { @@ -780,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 769e1097bff05..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, ); } @@ -755,6 +764,7 @@ use self::AccessDepth::{Deep, Shallow}; enum ArtificialField { Discriminant, ArrayLength, + ShallowBorrow, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -835,6 +845,7 @@ enum LocalMutationIsAllowed { enum InitializationRequiringAction { Update, Borrow, + MatchOn, Use, Assignment, } @@ -849,6 +860,7 @@ impl InitializationRequiringAction { match self { InitializationRequiringAction::Update => "update", InitializationRequiringAction::Borrow => "borrow", + InitializationRequiringAction::MatchOn => "use", // no good noun InitializationRequiringAction::Use => "use", InitializationRequiringAction::Assignment => "assign", } @@ -858,6 +870,7 @@ impl InitializationRequiringAction { match self { InitializationRequiringAction::Update => "updated", InitializationRequiringAction::Borrow => "borrowed", + InitializationRequiringAction::MatchOn => "matched on", InitializationRequiringAction::Use => "used", InitializationRequiringAction::Assignment => "assigned", } @@ -972,7 +985,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 } @@ -984,7 +1003,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) } @@ -1108,6 +1127,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); @@ -1127,9 +1149,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, ); @@ -1315,11 +1343,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 +1402,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 +1702,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 +1732,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 +1778,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..9250c04969f98 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::borrow_conflicts_with_place( + 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..c0f059619a497 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -12,20 +12,21 @@ 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; -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>, + borrow_kind: BorrowKind, access_place: &Place<'tcx>, access: AccessDepth, ) -> bool { debug!( - "places_conflict({:?},{:?},{:?})", + "borrow_conflicts_with_place({:?},{:?},{:?})", borrow_place, access_place, access ); @@ -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 { @@ -95,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. // @@ -127,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 => { @@ -136,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; } } @@ -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, @@ -167,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; } @@ -175,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), _) => { @@ -185,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; } @@ -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!("borrow_conflicts_with_place: shallow borrow"); + return false; + } else { + debug!("borrow_conflicts_with_place: full borrow, CONFLICT"); + return true; + } } } } @@ -241,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>>, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index c30dcdafdb402..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(); @@ -1363,7 +1390,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, }, @@ -1502,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(), + ), + }); + } + } + } + } } 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/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/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, 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/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 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)]); 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/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/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`. 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`.