From a40646c3ca9d1ba7a9314dfe9b4ae562357fbe4f Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Tue, 27 Nov 2018 23:30:25 +0000 Subject: [PATCH] Make 2PB reservations conflict with shared borrows Creating a mutable reference asserts uniqueness in certain potential memory models for Rust. Make this an error for now. --- src/librustc/ich/impls_mir.rs | 1 + src/librustc/mir/mod.rs | 45 ++++++++-- src/librustc/mir/tcx.rs | 6 +- src/librustc/mir/visit.rs | 6 ++ src/librustc_codegen_ssa/mir/analyze.rs | 1 + src/librustc_mir/borrow_check/borrow_set.rs | 4 +- .../borrow_check/error_reporting.rs | 51 ++++++----- src/librustc_mir/borrow_check/mod.rs | 46 +++++++--- .../borrow_check/nll/invalidation.rs | 12 ++- src/librustc_mir/build/matches/mod.rs | 23 ++--- src/librustc_mir/transform/qualify_consts.rs | 2 + src/librustc_mir/util/liveness.rs | 1 + src/test/mir-opt/match_false_edges.rs | 12 +-- src/test/mir-opt/remove_fake_borrows.rs | 4 +- .../borrowck-for-loop-head-linkage.nll.stderr | 2 +- .../borrowck-object-lifetime.nll.stderr | 2 +- ...wo-phase-cannot-nest-mut-self-calls.stderr | 2 +- ...ervation-sharing-interference-2.nll.stderr | 14 ++++ ...hase-reservation-sharing-interference-2.rs | 19 ++--- ...-reservation-sharing-interference-2.stderr | 21 ++--- src/test/ui/error-codes/E0502.nll.stderr | 4 +- .../ui/hashmap-iter-value-lifetime.nll.stderr | 2 +- src/test/ui/hashmap-lifetimes.nll.stderr | 2 +- src/test/ui/nll/get_default.nll.stderr | 84 ------------------- .../nll/match-guards-partially-borrow.stderr | 14 ++-- src/test/ui/nll/match-on-borrowed.rs | 7 +- src/test/ui/nll/match-on-borrowed.stderr | 30 ++++++- .../region-ends-after-if-condition.nll.stderr | 39 --------- .../borrowck-issue-49631.nll.stderr | 2 +- 29 files changed, 223 insertions(+), 235 deletions(-) create mode 100644 src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll.stderr delete mode 100644 src/test/ui/nll/get_default.nll.stderr delete mode 100644 src/test/ui/nll/region-ends-after-if-condition.nll.stderr diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index d98bb82aabad1..e3976c7b382d9 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -40,6 +40,7 @@ impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_block impl_stable_hash_for!(enum mir::BorrowKind { Shared, Shallow, + Guard, Unique, Mut { allow_two_phase_borrow }, }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index af1255c438a95..0b51cb848b774 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -497,25 +497,50 @@ pub enum BorrowKind { /// 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`. + /// conflict with a mutable borrow of `*(a.b)`. /// /// 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: + /// an arm is selected. We create a shallow borrow of `x` for the following + /// match: /// /// let mut x = &Some(0); /// match *x { /// None => (), - /// Some(_) if { x = &None; false } => (), + /// Some(_) if { x = &None; /* error */ 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, because the - /// mutating `(*x as Some).0` can't affect the discriminant of `x`. - /// We can also report errors with this kind of borrow differently. + /// This can't be a shared borrow because mutably borrowing (*x).0 + /// should not prevent `match (*x).1 { ... }`, for example, because the + /// mutating `(*x).0` can't affect `(*x).1`. Shallow, + /// Same as `Shared`, but only exists to prevent mutation that could make + /// matches non-exhaustive. Removed after borrow checking. + /// + /// 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. We create a shallow borrow of `x` for the following + /// match: + /// + /// let mut x = &Some(0); + /// match *x { + /// None => (), + /// Some(_) if { x = &None; false } => (), + /// Some(_) => (), + /// } + /// + /// This can't be a `Shared` borrow because it doesn't conflict with the + /// two-phase borrow reservation in + /// + /// match x { // Guard borrow here + /// Some(ref mut r) // reservation from borrow of x + /// if true => (), + /// _ => (), + /// } + Guard, + /// 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 @@ -564,7 +589,10 @@ pub enum BorrowKind { impl BorrowKind { pub fn allows_two_phase_borrow(&self) -> bool { match *self { - BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => false, + BorrowKind::Shared + | BorrowKind::Shallow + | BorrowKind::Guard + | BorrowKind::Unique => false, BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, } } @@ -2314,6 +2342,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let kind_str = match borrow_kind { BorrowKind::Shared => "", BorrowKind::Shallow => "shallow ", + BorrowKind::Guard => "guard ", BorrowKind::Mut { .. } | BorrowKind::Unique => "mut ", }; diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index baa88dba45915..a855e3eda2905 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -346,9 +346,9 @@ impl BorrowKind { // 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, + // We have no type corresponding to a shallow or guard borrows, so + // use `&` as an approximation. + BorrowKind::Guard | BorrowKind::Shallow => hir::MutImmutable, } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 0c9b06a8d8c7d..e4b8189876d2d 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -599,6 +599,9 @@ macro_rules! make_mir_visitor { BorrowKind::Shallow => PlaceContext::NonMutatingUse( NonMutatingUseContext::ShallowBorrow(*r) ), + BorrowKind::Guard => PlaceContext::NonMutatingUse( + NonMutatingUseContext::GuardBorrow(*r) + ), BorrowKind::Unique => PlaceContext::NonMutatingUse( NonMutatingUseContext::UniqueBorrow(*r) ), @@ -992,6 +995,8 @@ pub enum NonMutatingUseContext<'tcx> { SharedBorrow(Region<'tcx>), /// Shallow borrow. ShallowBorrow(Region<'tcx>), + /// Guard borrow. + GuardBorrow(Region<'tcx>), /// Unique borrow. UniqueBorrow(Region<'tcx>), /// Used as base for another place, e.g. `x` in `x.y`. Will not mutate the place. @@ -1059,6 +1064,7 @@ impl<'tcx> PlaceContext<'tcx> { match *self { PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::GuardBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) | PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) => true, _ => false, diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index c7e2c76c3e503..6756388e449b3 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -250,6 +250,7 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::GuardBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => { self.not_ssa(local); } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index fd7dc7fc4bd3a..b9721dd8da6b8 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -90,6 +90,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { let kind = match self.kind { mir::BorrowKind::Shared => "", mir::BorrowKind::Shallow => "shallow ", + mir::BorrowKind::Guard => "guard ", mir::BorrowKind::Unique => "uniq ", mir::BorrowKind::Mut { .. } => "mut ", }; @@ -280,7 +281,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> { // The use of TMP in a shared borrow does not // count as an actual activation. PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) => + PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::GuardBorrow(..)) => TwoPhaseActivation::NotActivated, _ => { // Double check: This borrow is indeed a two-phase borrow (that is, diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 4ccd26bee8b88..7529441952425 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -409,7 +409,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } (BorrowKind::Mut { .. }, _, _, BorrowKind::Shallow, _, _) - | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) => { + | (BorrowKind::Unique, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Mut { .. }, _, _, BorrowKind::Guard, _, _) + | (BorrowKind::Unique, _, _, BorrowKind::Guard, _, _) => { let mut err = tcx.cannot_mutate_in_match_guard( span, issued_span, @@ -472,17 +474,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Origin::Mir, ) } - (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _) - | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => { - // Shallow borrows are uses from the user's point of view. + | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) + | (BorrowKind::Guard, _, _, BorrowKind::Unique, _, _) + | (BorrowKind::Guard, _, _, BorrowKind::Mut { .. }, _, _) => { + // Shallow and guard 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::Shared, _, _, BorrowKind::Guard, _, _) | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _) - | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(), + | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Guard, _, _) + | (BorrowKind::Guard, _, _, BorrowKind::Shared, _, _) + | (BorrowKind::Guard, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Guard, _, _, BorrowKind::Guard, _, _) => unreachable!(), }; if issued_spans == borrow_spans { @@ -1208,21 +1216,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let loan_span = loan_spans.args_or_use(); let tcx = self.infcx.tcx; - let mut err = if loan.kind == BorrowKind::Shallow { - tcx.cannot_mutate_in_match_guard( - span, - loan_span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), - "assign", - Origin::Mir, - ) - } else { - tcx.cannot_assign_to_borrowed( - span, - loan_span, - &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), - Origin::Mir, - ) + let mut err = match loan.kind { + BorrowKind::Shallow | BorrowKind::Guard => { + tcx.cannot_mutate_in_match_guard( + span, + loan_span, + &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + "assign", + Origin::Mir, + ) + } + BorrowKind::Shared | BorrowKind::Unique | BorrowKind::Mut { .. } => { + tcx.cannot_assign_to_borrowed( + span, + loan_span, + &self.describe_place(place).unwrap_or_else(|| "_".to_owned()), + Origin::Mir, + ) + } }; loan_spans.var_span_label( diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 76ba6ae5de6ee..57c0c454a6230 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -1008,12 +1008,27 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Control::Continue } - (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) - | (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => { + (Read(_), BorrowKind::Shared) + | (Read(_), BorrowKind::Shallow) + | (Read(_), BorrowKind::Guard) => { Control::Continue } - (Write(WriteKind::Move), BorrowKind::Shallow) => { + (Reservation(..), BorrowKind::Shallow) + | (Reservation(..), BorrowKind::Guard) => { + // `Shallow` and `Guard` borrows only exist to prevent + // mutation, which a `Reservation` is not, even though it + // creates a mutable reference. + // + // We don't allow `Shared` borrows here, since it is + // undecided whether the mutable reference that is + // created by the `Reservation` should be unique when it's + // created. + Control::Continue + } + + (Write(WriteKind::Move), BorrowKind::Shallow) + | (Write(WriteKind::Move), BorrowKind::Guard) => { // Handled by initialization checks. Control::Continue } @@ -1037,7 +1052,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Control::Break } - (Reservation(kind), BorrowKind::Unique) + (Reservation(kind), BorrowKind::Shared) + | (Reservation(kind), BorrowKind::Unique) | (Reservation(kind), BorrowKind::Mut { .. }) | (Activation(kind, _), _) | (Write(kind), _) => { @@ -1149,7 +1165,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { BorrowKind::Shallow => { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) }, - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), + BorrowKind::Shared | BorrowKind::Guard => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(&self.infcx.tcx, bk) { @@ -1168,10 +1184,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { flow_state, ); - let action = if bk == BorrowKind::Shallow { - InitializationRequiringAction::MatchOn - } else { - InitializationRequiringAction::Borrow + let action = match bk { + BorrowKind::Shallow | BorrowKind::Guard => { + InitializationRequiringAction::MatchOn + } + BorrowKind::Shared | BorrowKind::Unique | BorrowKind::Mut { .. } => { + InitializationRequiringAction::Borrow + } }; self.check_if_path_or_subpath_is_moved( @@ -1421,7 +1440,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Shallow => false, + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Guard => false, BorrowKind::Unique | BorrowKind::Mut { .. } => true, }); @@ -1832,7 +1851,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 | BorrowKind::Shallow => unreachable!(), + BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Guard => unreachable!(), }; match self.is_mutable(place, is_local_mutation_allowed) { Ok(root_place) => { @@ -1863,9 +1882,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | Reservation(wk @ WriteKind::StorageDeadOrDrop) | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) + | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Guard)) | Write(wk @ WriteKind::StorageDeadOrDrop) | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) - | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) => { + | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Shallow)) + | Write(wk @ WriteKind::MutableBorrow(BorrowKind::Guard)) => { if let (Err(_place_err), true) = ( self.is_mutable(place, is_local_mutation_allowed), self.errors_buffer.is_empty() @@ -1911,6 +1932,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { | Read(ReadKind::Borrow(BorrowKind::Mut { .. })) | Read(ReadKind::Borrow(BorrowKind::Shared)) | Read(ReadKind::Borrow(BorrowKind::Shallow)) + | Read(ReadKind::Borrow(BorrowKind::Guard)) | 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 8af23a8813a9e..9cfda2288bb96 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -332,7 +332,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { BorrowKind::Shallow => { (Shallow(Some(ArtificialField::ShallowBorrow)), Read(ReadKind::Borrow(bk))) }, - BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), + BorrowKind::Guard | BorrowKind::Shared => (Deep, Read(ReadKind::Borrow(bk))), BorrowKind::Unique | BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if allow_two_phase_borrow(&self.tcx, bk) { @@ -442,8 +442,11 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // have already taken the reservation } - (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) - | (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => { + (Read(_), BorrowKind::Shallow) + | (Read(_), BorrowKind::Guard) + | (Read(_), BorrowKind::Shared) + | (Reservation(..), BorrowKind::Shallow) + | (Reservation(..), BorrowKind::Guard) => { // Reads/reservations don't invalidate shared or shallow borrows } @@ -460,7 +463,8 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { this.generate_invalidates(borrow_index, context.loc); } - (Reservation(_), BorrowKind::Unique) + (Reservation(..), BorrowKind::Shared) + | (Reservation(_), BorrowKind::Unique) | (Reservation(_), BorrowKind::Mut { .. }) | (Activation(_, _), _) | (Write(_), _) => { diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 342aaf9039d10..458c266cef833 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -24,7 +24,7 @@ use rustc::mir::*; use rustc::ty::{self, Ty}; use rustc::ty::layout::VariantIdx; use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use syntax::ast::{Name, NodeId}; use syntax_pos::Span; @@ -182,7 +182,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // 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::default()) + Some(FxHashSet::default()) } else { None }; @@ -734,7 +734,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arm_blocks: &mut ArmBlocks, mut candidates: Vec>, mut block: BasicBlock, - fake_borrows: &mut Option, BorrowKind>>, + fake_borrows: &mut Option>>, ) -> Vec { debug!( "matched_candidate(span={:?}, block={:?}, candidates={:?})", @@ -767,7 +767,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { for Binding { source, .. } in candidates.iter().flat_map(|candidate| &candidate.bindings) { - fake_borrows.insert(source.clone(), BorrowKind::Shared); + fake_borrows.insert(source.clone()); } } @@ -980,7 +980,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { arm_blocks: &mut ArmBlocks, candidates: &[Candidate<'pat, 'tcx>], block: BasicBlock, - fake_borrows: &mut Option, BorrowKind>>, + fake_borrows: &mut Option>>, ) -> (Vec, usize) { // extract the match-pair from the highest priority candidate let match_pair = &candidates.first().unwrap().match_pairs[0]; @@ -1022,9 +1022,9 @@ 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) - }); + if let Some(fake_borrows) = fake_borrows { + fake_borrows.insert(match_pair.place.clone()); + } // perform the test, branching to one of N blocks. For each of // those N possible outcomes, create a (initially empty) @@ -1415,6 +1415,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let borrow_kind = match borrow_kind { BorrowKind::Shared | BorrowKind::Shallow + | BorrowKind::Guard | BorrowKind::Unique => borrow_kind, BorrowKind::Mut { .. } => BorrowKind::Mut { allow_two_phase_borrow: true, @@ -1562,7 +1563,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn add_fake_borrows<'pat>( &mut self, pre_binding_blocks: &[(BasicBlock, Span)], - fake_borrows: FxHashMap, BorrowKind>, + fake_borrows: FxHashSet>, source_info: SourceInfo, start_block: BasicBlock, ) { @@ -1574,7 +1575,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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 + for place in fake_borrows { { let mut prefix_cursor = &place; @@ -1589,7 +1590,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - all_fake_borrows.push((place, borrow_kind)); + all_fake_borrows.push((place, BorrowKind::Guard)); } // Deduplicate and ensure a deterministic order. diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index fc2c6c3ab1f37..f8d89640acb60 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -668,6 +668,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(region)), BorrowKind::Shallow => PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(region)), + BorrowKind::Guard => + PlaceContext::NonMutatingUse(NonMutatingUseContext::GuardBorrow(region)), BorrowKind::Unique => PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(region)), BorrowKind::Mut { .. } => diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 12c13b8f81531..9bbbb1496efc4 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -198,6 +198,7 @@ pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option { PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::GuardBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) | PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 9ccf037139945..6b9b0a0b6b85e 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -55,8 +55,8 @@ fn main() { // _2 = std::option::Option::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _7 = discriminant(_2); -// _9 = &shallow (promoted[2]: std::option::Option); -// _10 = &(((promoted[1]: std::option::Option) as Some).0: i32); +// _9 = &guard (promoted[2]: std::option::Option); +// _10 = &guard (((promoted[1]: std::option::Option) as Some).0: i32); // switchInt(move _7) -> [0isize: bb5, 1isize: bb3, otherwise: bb7]; // } // bb1: { @@ -129,8 +129,8 @@ fn main() { // _2 = std::option::Option::Some(const 42i32,); // FakeRead(ForMatchedPlace, _2); // _7 = discriminant(_2); -// _9 = &shallow _2; -// _10 = &((_2 as Some).0: i32); +// _9 = &guard _2; +// _10 = &guard ((_2 as Some).0: i32); // switchInt(move _7) -> [0isize: bb4, 1isize: bb3, otherwise: bb7]; // } // bb1: { @@ -203,8 +203,8 @@ fn main() { // _2 = std::option::Option::Some(const 1i32,); // FakeRead(ForMatchedPlace, _2); // _11 = discriminant(_2); -// _16 = &shallow _2; -// _17 = &((_2 as Some).0: i32); +// _16 = &guard _2; +// _17 = &guard ((_2 as Some).0: i32); // switchInt(move _11) -> [1isize: bb2, otherwise: bb3]; // } // bb1: { diff --git a/src/test/mir-opt/remove_fake_borrows.rs b/src/test/mir-opt/remove_fake_borrows.rs index 8411fba02e977..9ec518aae7615 100644 --- a/src/test/mir-opt/remove_fake_borrows.rs +++ b/src/test/mir-opt/remove_fake_borrows.rs @@ -21,10 +21,10 @@ fn main() { // bb0: { // FakeRead(ForMatchedPlace, _1); // _2 = discriminant(_1); -// _3 = &shallow _1; +// _3 = &guard _1; // _4 = &shallow ((_1 as Some).0: &' &' i32); // _5 = &shallow (*((_1 as Some).0: &' &' i32)); -// _6 = &shallow (*(*((_1 as Some).0: &' &' i32))); +// _6 = &guard (*(*((_1 as Some).0: &' &' i32))); // switchInt(move _2) -> [1isize: bb6, otherwise: bb4]; // } // bb1: { diff --git a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr index a6487ede6f838..1a80ff0c7961d 100644 --- a/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr +++ b/src/test/ui/borrowck/borrowck-for-loop-head-linkage.nll.stderr @@ -8,7 +8,7 @@ LL | for &x in &vector { | immutable borrow used here, in later iteration of loop LL | let cap = vector.capacity(); LL | vector.extend(repeat(0)); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^ mutable borrow occurs here error[E0502]: cannot borrow `vector` as mutable because it is also borrowed as immutable --> $DIR/borrowck-for-loop-head-linkage.rs:18:9 diff --git a/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr b/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr index 8a9aaa9d8958c..47e1fb98f38f2 100644 --- a/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr +++ b/src/test/ui/borrowck/borrowck-object-lifetime.nll.stderr @@ -4,7 +4,7 @@ error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immut LL | let y = x.borrowed(); | - immutable borrow occurs here LL | let z = x.mut_borrowed(); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^ mutable borrow occurs here LL | y.use_ref(); | - immutable borrow later used here diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr index a3d3da94d54aa..f00e4b1162878 100644 --- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr +++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr @@ -7,7 +7,7 @@ LL | vec.get({ | immutable borrow occurs here LL | LL | vec.push(2); - | ^^^^^^^^^^^ mutable borrow occurs here + | ^^^ mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll.stderr new file mode 100644 index 0000000000000..55d148cc57630 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll.stderr @@ -0,0 +1,14 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:22:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); //~ ERROR cannot borrow `v` as mutable + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs index f9326d944b8e4..d1e6d7aea29d6 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs @@ -8,27 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z borrowck=mir -Z two-phase-borrows - -// This is similar to two-phase-reservation-sharing-interference.rs -// in that it shows a reservation that overlaps with a shared borrow. -// -// Currently, this test fails with lexical lifetimes, but succeeds -// with non-lexical lifetimes. (The reason is because the activation -// of the mutable borrow ends up overlapping with a lexically-scoped -// shared borrow; but a non-lexical shared borrow can end before the -// activation occurs.) +// Test that a reservation conflicts with a shared borrow. // -// So this test is just making a note of the current behavior. +// We conservatively treat reservation as creating a mutable reference, which +// should be unique, and then allowing sharing up to the activation point. #![feature(rustc_attrs)] -#[rustc_error] -fn main() { //~ ERROR compilation successful +fn main() { let mut v = vec![0, 1, 2]; let shared = &v; - v.push(shared.len()); + v.push(shared.len()); //~ ERROR cannot borrow `v` as mutable assert_eq!(v, [0, 1, 2, 3]); } diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr index 2ac10a82f7b05..a1fd64fe81387 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr @@ -1,14 +1,15 @@ -error: compilation successful - --> $DIR/two-phase-reservation-sharing-interference-2.rs:27:1 +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:22:5 | -LL | / fn main() { //~ ERROR compilation successful -LL | | let mut v = vec![0, 1, 2]; -LL | | let shared = &v; -LL | | -... | -LL | | assert_eq!(v, [0, 1, 2, 3]); -LL | | } - | |_^ +LL | let shared = &v; + | - immutable borrow occurs here +LL | +LL | v.push(shared.len()); //~ ERROR cannot borrow `v` as mutable + | ^ mutable borrow occurs here +... +LL | } + | - immutable borrow ends here error: aborting due to previous error +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/error-codes/E0502.nll.stderr b/src/test/ui/error-codes/E0502.nll.stderr index ce08271024698..47d1cc277d02e 100644 --- a/src/test/ui/error-codes/E0502.nll.stderr +++ b/src/test/ui/error-codes/E0502.nll.stderr @@ -1,10 +1,10 @@ error[E0502]: cannot borrow `*a` as mutable because it is also borrowed as immutable - --> $DIR/E0502.rs:14:5 + --> $DIR/E0502.rs:14:9 | LL | let ref y = a; | ----- immutable borrow occurs here LL | bar(a); //~ ERROR E0502 - | ^^^^^^ mutable borrow occurs here + | ^ mutable borrow occurs here LL | y.use_ref(); | - immutable borrow later used here diff --git a/src/test/ui/hashmap-iter-value-lifetime.nll.stderr b/src/test/ui/hashmap-iter-value-lifetime.nll.stderr index 61a28bfd17b2e..0333ea3bedc02 100644 --- a/src/test/ui/hashmap-iter-value-lifetime.nll.stderr +++ b/src/test/ui/hashmap-iter-value-lifetime.nll.stderr @@ -5,7 +5,7 @@ LL | let (_, thing) = my_stuff.iter().next().unwrap(); | -------- immutable borrow occurs here LL | LL | my_stuff.clear(); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^ mutable borrow occurs here LL | LL | println!("{}", *thing); | ------ immutable borrow later used here diff --git a/src/test/ui/hashmap-lifetimes.nll.stderr b/src/test/ui/hashmap-lifetimes.nll.stderr index 4cf87ee8dc75b..89994b0276e62 100644 --- a/src/test/ui/hashmap-lifetimes.nll.stderr +++ b/src/test/ui/hashmap-lifetimes.nll.stderr @@ -4,7 +4,7 @@ error[E0502]: cannot borrow `my_stuff` as mutable because it is also borrowed as LL | let mut it = my_stuff.iter(); | -------- immutable borrow occurs here LL | my_stuff.insert(1, 43); //~ ERROR cannot borrow - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^ mutable borrow occurs here LL | it; | -- immutable borrow later used here diff --git a/src/test/ui/nll/get_default.nll.stderr b/src/test/ui/nll/get_default.nll.stderr deleted file mode 100644 index 4f9c832d423bb..0000000000000 --- a/src/test/ui/nll/get_default.nll.stderr +++ /dev/null @@ -1,84 +0,0 @@ -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:33:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:45:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:51:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:33:17 - | -LL | fn ok(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:45:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:51:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/match-guards-partially-borrow.stderr b/src/test/ui/nll/match-guards-partially-borrow.stderr index 2cbfeb886b572..0ea86ffcd49fa 100644 --- a/src/test/ui/nll/match-guards-partially-borrow.stderr +++ b/src/test/ui/nll/match-guards-partially-borrow.stderr @@ -45,14 +45,14 @@ LL | t = true; //~ ERROR LL | false => (), | ----- borrow later used here -error[E0506]: cannot assign to `u` because it is borrowed +error[E0510]: cannot assign `u` in match guard --> $DIR/match-guards-partially-borrow.rs:83:13 | LL | match u { - | - borrow of `u` occurs here + | - value is immutable in match guard ... LL | u = true; //~ ERROR - | ^^^^^^^^ assignment to borrowed `u` occurs here + | ^^^^^^^^ cannot assign ... LL | x => (), | - borrow later used here @@ -66,14 +66,14 @@ LL | match x { LL | Some(ref mut r) => *r = None, //~ ERROR | ^^^^^^^^^ cannot mutably borrow -error[E0506]: cannot assign to `*w.0` because it is borrowed +error[E0510]: cannot assign `*w.0` in match guard --> $DIR/match-guards-partially-borrow.rs:112:13 | LL | match w { - | - borrow of `*w.0` occurs here + | - value is immutable in match guard ... LL | *w.0 = true; //~ ERROR - | ^^^^^^^^^^^ assignment to borrowed `*w.0` occurs here + | ^^^^^^^^^^^ cannot assign ... LL | x => (), | - borrow later used here @@ -128,5 +128,5 @@ LL | &b => (), error: aborting due to 11 previous errors -Some errors occurred: E0503, E0506, E0510. +Some errors occurred: E0503, 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 index 6a8ce03e8fd25..57e5ceb922cc2 100644 --- a/src/test/ui/nll/match-on-borrowed.rs +++ b/src/test/ui/nll/match-on-borrowed.rs @@ -37,7 +37,7 @@ fn underscore_example(mut c: i32) { } enum E { - V(i32, i32), + V(&'static i32, i32), W, } @@ -46,7 +46,8 @@ fn enum_example(mut e: E) { E::V(ref mut x, _) => x, E::W => panic!(), }; - match e { // OK, no access of borrowed data + // Discriminant accesses the memory x points to. + match e { //~ ERROR _ if false => (), E::V(_, r) => (), E::W => (), @@ -59,7 +60,7 @@ fn indirect_enum_example(mut f: &mut E) { E::V(ref mut x, _) => x, E::W => panic!(), }; - match f { // OK, no access of borrowed data + match f { //~ ERROR _ if false => (), E::V(_, r) => (), E::W => (), diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr index cdff29d44b85b..fc9a6bb8f8b9b 100644 --- a/src/test/ui/nll/match-on-borrowed.stderr +++ b/src/test/ui/nll/match-on-borrowed.stderr @@ -1,5 +1,29 @@ +error[E0503]: cannot use `e` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:50:11 + | +LL | E::V(ref mut x, _) => x, + | --------- borrow of `e.0` occurs here +... +LL | match e { //~ ERROR + | ^ use of borrowed `e.0` +... +LL | x; + | - borrow later used here + +error[E0503]: cannot use `*f` because it was mutably borrowed + --> $DIR/match-on-borrowed.rs:63:11 + | +LL | E::V(ref mut x, _) => x, + | --------- borrow of `f.0` occurs here +... +LL | match f { //~ ERROR + | ^ use of borrowed `f.0` +... +LL | x; + | - borrow later used here + error[E0503]: cannot use `t` because it was mutably borrowed - --> $DIR/match-on-borrowed.rs:82:9 + --> $DIR/match-on-borrowed.rs:83:9 | LL | let x = &mut t; | ------ borrow of `t` occurs here @@ -11,12 +35,12 @@ LL | x; | - borrow later used here error[E0381]: use of possibly uninitialized variable: `n` - --> $DIR/match-on-borrowed.rs:92:11 + --> $DIR/match-on-borrowed.rs:93:11 | LL | match n {} //~ ERROR | ^ use of possibly uninitialized `n` -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors Some errors occurred: E0381, E0503. For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr b/src/test/ui/nll/region-ends-after-if-condition.nll.stderr deleted file mode 100644 index c1bfa4bffc03c..0000000000000 --- a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:29:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:39:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/region-ends-after-if-condition.rs:39:9 - | -LL | let value = &my_struct.field; - | ---------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | drop(value); - | ----- immutable borrow later used here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr index 84cd097e33ca9..70a32f21e7163 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/borrowck-issue-49631.nll.stderr @@ -4,7 +4,7 @@ error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immu LL | while let Some(Ok(string)) = foo.get() { | --- immutable borrow occurs here LL | foo.mutate(); - | ^^^^^^^^^^^^ mutable borrow occurs here + | ^^^ mutable borrow occurs here LL | //~^ ERROR cannot borrow `foo` as mutable LL | println!("foo={:?}", *string); | ------- immutable borrow used here, in later iteration of loop