diff --git a/.travis.yml b/.travis.yml index 0646f4d4687a6..940a675c01206 100644 --- a/.travis.yml +++ b/.travis.yml @@ -167,7 +167,6 @@ matrix: - env: IMAGE=i686-gnu-nopt if: branch = auto - env: IMAGE=wasm32-unknown - if: branch = auto - env: IMAGE=x86_64-gnu if: branch = auto - env: IMAGE=x86_64-gnu-full-bootstrap 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 3fdb7d7f27d7e..f29870623a9ee 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use borrow_check::{WriteKind, StorageDeadOrDrop}; +use borrow_check::WriteKind; use borrow_check::prefixes::IsPrefixOf; use borrow_check::nll::explain_borrow::BorrowExplanation; use rustc::middle::region::ScopeTree; use rustc::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, FakeReadCause, Field, Local, - LocalDecl, LocalKind, Location, Operand, Place, ProjectionElem, Rvalue, Statement, - StatementKind, TerminatorKind, VarBindingForm, + LocalDecl, LocalKind, Location, Operand, Place, PlaceProjection, ProjectionElem, Rvalue, + Statement, StatementKind, TerminatorKind, VarBindingForm, }; use rustc::hir; use rustc::hir::def_id::DefId; @@ -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 { @@ -452,13 +482,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.access_place_error_reported .insert((root_place.clone(), borrow_span)); - if let Some(WriteKind::StorageDeadOrDrop(StorageDeadOrDrop::Destructor)) = kind { + if let StorageDeadOrDrop::Destructor(dropped_ty) + = self.classify_drop_access_kind(&borrow.borrowed_place) + { // If a borrow of path `B` conflicts with drop of `D` (and // we're not in the uninteresting case where `B` is a // prefix of `D`), then report this as a more interesting // destructor conflict. if !borrow.borrowed_place.is_prefix_of(place_span.0) { - self.report_borrow_conflicts_with_destructor(context, borrow, place_span, kind); + self.report_borrow_conflicts_with_destructor( + context, + borrow, + place_span, + kind, + dropped_ty, + ); return; } } @@ -566,6 +604,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { borrow: &BorrowData<'tcx>, (place, drop_span): (&Place<'tcx>, Span), kind: Option, + dropped_ty: ty::Ty<'tcx>, ) { debug!( "report_borrow_conflicts_with_destructor(\ @@ -579,28 +618,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mut err = self.infcx.tcx.cannot_borrow_across_destructor(borrow_span, Origin::Mir); - let (what_was_dropped, dropped_ty) = { - let desc = match self.describe_place(place) { - Some(name) => format!("`{}`", name.as_str()), - None => format!("temporary value"), - }; - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); - (desc, ty) + let what_was_dropped = match self.describe_place(place) { + Some(name) => format!("`{}`", name.as_str()), + None => format!("temporary value"), }; - let label = match dropped_ty.sty { - ty::Adt(adt, _) if adt.has_dtor(self.infcx.tcx) && !adt.is_box() => { - match self.describe_place(&borrow.borrowed_place) { - Some(borrowed) => - format!("here, drop of {D} needs exclusive access to `{B}`, \ - because the type `{T}` implements the `Drop` trait", - D=what_was_dropped, T=dropped_ty, B=borrowed), - None => - format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait", - D=what_was_dropped, T=dropped_ty), - } - } - _ => format!("drop of {D} occurs here", D=what_was_dropped), + let label = match self.describe_place(&borrow.borrowed_place) { + Some(borrowed) => + format!("here, drop of {D} needs exclusive access to `{B}`, \ + because the type `{T}` implements the `Drop` trait", + D=what_was_dropped, T=dropped_ty, B=borrowed), + None => + format!("here is drop of {D}; whose type `{T}` implements the `Drop` trait", + D=what_was_dropped, T=dropped_ty), }; err.span_label(drop_span, label); @@ -664,9 +694,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let tcx = self.infcx.tcx; let mut err = - tcx.path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir); - err.span_label(proper_span, "temporary value does not live long enough"); - err.span_label(drop_span, "temporary value only lives until here"); + tcx.temporary_value_borrowed_for_too_long(proper_span, Origin::Mir); + err.span_label(proper_span, "creates a temporary which is freed while still in use"); + err.span_label(drop_span, "temporary value is freed at the end of this statement"); let explanation = self.explain_why_borrow_contains_point(context, borrow, None); match explanation { @@ -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"); @@ -880,6 +920,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { pub(super) struct IncludingDowncast(bool); +/// Which case a StorageDeadOrDrop is for. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum StorageDeadOrDrop<'tcx> { + LocalStorageDead, + BoxedStorageDead, + Destructor(ty::Ty<'tcx>), +} + impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // End-user visible description of `place` if one can be found. If the // place is a temporary for instance, None will be returned. @@ -1167,6 +1215,56 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } + fn classify_drop_access_kind(&self, place: &Place<'tcx>) -> StorageDeadOrDrop<'tcx> { + let tcx = self.infcx.tcx; + match place { + Place::Local(_) + | Place::Static(_) + | Place::Promoted(_) => StorageDeadOrDrop::LocalStorageDead, + Place::Projection(box PlaceProjection { base, elem }) => { + let base_access = self.classify_drop_access_kind(base); + match elem { + ProjectionElem::Deref => { + match base_access { + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + assert!(base.ty(self.mir, tcx).to_ty(tcx).is_box(), + "Drop of value behind a reference or raw pointer"); + StorageDeadOrDrop::BoxedStorageDead + } + StorageDeadOrDrop::Destructor(_) => { + base_access + } + } + } + ProjectionElem::Field(..) + | ProjectionElem::Downcast(..) => { + let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + match base_ty.sty { + ty::Adt(def, _) if def.has_dtor(tcx) => { + // Report the outermost adt with a destructor + match base_access { + StorageDeadOrDrop::Destructor(_) => { + base_access + } + StorageDeadOrDrop::LocalStorageDead + | StorageDeadOrDrop::BoxedStorageDead => { + StorageDeadOrDrop::Destructor(base_ty) + } + } + } + _ => base_access, + } + } + + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Index(_) => base_access, + } + } + } + } + /// Annotate argument and return type of function and closure with (synthesized) lifetime for /// borrow of local value that does not live long enough. fn annotate_argument_and_return_for_borrow( diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 06884875598df..06394ee44ccbe 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -23,13 +23,12 @@ use rustc::mir::{ClearCrossCrate, Local, Location, Mir, Mutability, Operand, Pla use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; use rustc::ty::query::Providers; -use rustc::ty::{self, ParamEnv, TyCtxt, Ty}; +use rustc::ty::{self, TyCtxt}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::indexed_vec::Idx; use smallvec::SmallVec; use std::rc::Rc; @@ -251,7 +250,6 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( mir, mir_def_id: def_id, move_data: &mdpe.move_data, - param_env: param_env, location_table, movable_generator, locals_are_invalidated_at_exit, @@ -393,7 +391,6 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// when MIR borrowck begins. location_table: &'cx LocationTable, - param_env: ParamEnv<'gcx>, movable_generator: bool, /// This keeps track of whether local variables are free-ed when the function /// exits even without a `StorageDead`, which appears to be the case for @@ -502,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, ); } @@ -574,8 +580,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx self.access_place( ContextKind::StorageDead.new(location), (&Place::Local(local), span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::LocalStorageDead))), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, flow_state, ); @@ -630,8 +635,13 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}", loc, term, drop_place, drop_place_ty, span); - self.visit_terminator_drop( - loc, term, flow_state, drop_place, drop_place_ty, span, SeenTy(None)); + self.access_place( + ContextKind::Drop.new(loc), + (drop_place, span), + (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + flow_state, + ); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -748,16 +758,17 @@ enum MutateMode { } use self::ReadOrWrite::{Activation, Read, Reservation, Write}; -use self::ShallowOrDeep::{Deep, Shallow}; +use self::AccessDepth::{Deep, Shallow}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ArtificialField { Discriminant, ArrayLength, + ShallowBorrow, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum ShallowOrDeep { +enum AccessDepth { /// From the RFC: "A *shallow* access means that the immediate /// fields reached at P are accessed, but references or pointers /// found within are not dereferenced. Right now, the only access @@ -769,6 +780,10 @@ enum ShallowOrDeep { /// through the given place may be invalidated or accesses by /// this action." Deep, + + /// Access is Deep only when there is a Drop implementation that + /// can reach the data behind the reference. + Drop, } /// Kind of access to a value: read or write @@ -803,21 +818,12 @@ enum ReadKind { /// (For informational purposes only) #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum WriteKind { - StorageDeadOrDrop(StorageDeadOrDrop), + StorageDeadOrDrop, MutableBorrow(BorrowKind), Mutate, Move, } -/// Specify whether which case a StorageDeadOrDrop is in. -/// (For informational purposes only) -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum StorageDeadOrDrop { - LocalStorageDead, - BoxedStorageDead, - Destructor, -} - /// When checking permissions for a place access, this flag is used to indicate that an immutable /// local place can be mutated. /// @@ -839,6 +845,7 @@ enum LocalMutationIsAllowed { enum InitializationRequiringAction { Update, Borrow, + MatchOn, Use, Assignment, } @@ -853,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", } @@ -862,237 +870,14 @@ impl InitializationRequiringAction { match self { InitializationRequiringAction::Update => "updated", InitializationRequiringAction::Borrow => "borrowed", + InitializationRequiringAction::MatchOn => "matched on", InitializationRequiringAction::Use => "used", InitializationRequiringAction::Assignment => "assigned", } } } -/// A simple linked-list threaded up the stack of recursive calls in `visit_terminator_drop`. -#[derive(Copy, Clone, Debug)] -struct SeenTy<'a, 'gcx: 'a>(Option<(Ty<'gcx>, &'a SeenTy<'a, 'gcx>)>); - -impl<'a, 'gcx> SeenTy<'a, 'gcx> { - /// Return a new list with `ty` prepended to the front of `self`. - fn cons(&'a self, ty: Ty<'gcx>) -> Self { - SeenTy(Some((ty, self))) - } - - /// True if and only if `ty` occurs on the linked list `self`. - fn have_seen(self, ty: Ty) -> bool { - let mut this = self.0; - loop { - match this { - None => return false, - Some((seen_ty, recur)) => { - if seen_ty == ty { - return true; - } else { - this = recur.0; - continue; - } - } - } - } - } -} - impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { - /// Invokes `access_place` as appropriate for dropping the value - /// at `drop_place`. Note that the *actual* `Drop` in the MIR is - /// always for a variable (e.g., `Drop(x)`) -- but we recursively - /// break this variable down into subpaths (e.g., `Drop(x.foo)`) - /// to indicate more precisely which fields might actually be - /// accessed by a destructor. - fn visit_terminator_drop( - &mut self, - loc: Location, - term: &Terminator<'tcx>, - flow_state: &Flows<'cx, 'gcx, 'tcx>, - drop_place: &Place<'tcx>, - erased_drop_place_ty: ty::Ty<'gcx>, - span: Span, - prev_seen: SeenTy<'_, 'gcx>, - ) { - if prev_seen.have_seen(erased_drop_place_ty) { - // if we have directly seen the input ty `T`, then we must - // have had some *direct* ownership loop between `T` and - // some directly-owned (as in, actually traversed by - // recursive calls below) part that is also of type `T`. - // - // Note: in *all* such cases, the data in question cannot - // be constructed (nor destructed) in finite time/space. - // - // Proper examples, some of which are statically rejected: - // - // * `struct A { field: A, ... }`: - // statically rejected as infinite size - // - // * `type B = (B, ...);`: - // statically rejected as cyclic - // - // * `struct C { field: Box, ... }` - // * `struct D { field: Box<(D, D)>, ... }`: - // *accepted*, though impossible to construct - // - // Here is *NOT* an example: - // * `struct Z { field: Option>, ... }`: - // Here, the type is both representable in finite space (due to the boxed indirection) - // and constructable in finite time (since the recursion can bottom out with `None`). - // This is an obvious instance of something the compiler must accept. - // - // Since some of the above impossible cases like `C` and - // `D` are accepted by the compiler, we must take care not - // to infinite-loop while processing them. But since such - // cases cannot actually arise, it is sound for us to just - // skip them during drop. If the developer uses unsafe - // code to construct them, they should not be surprised by - // weird drop behavior in their resulting code. - debug!("visit_terminator_drop previously seen \ - erased_drop_place_ty: {:?} on prev_seen: {:?}; returning early.", - erased_drop_place_ty, prev_seen); - return; - } - - let gcx = self.infcx.tcx.global_tcx(); - let drop_field = |mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, - (index, field): (usize, ty::Ty<'gcx>)| { - let field_ty = gcx.normalize_erasing_regions(mir.param_env, field); - let place = drop_place.clone().field(Field::new(index), field_ty); - - debug!("visit_terminator_drop drop_field place: {:?} field_ty: {:?}", place, field_ty); - let seen = prev_seen.cons(erased_drop_place_ty); - mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span, seen); - }; - - match erased_drop_place_ty.sty { - // When a struct is being dropped, we need to check - // whether it has a destructor, if it does, then we can - // call it, if it does not then we need to check the - // individual fields instead. This way if `foo` has a - // destructor but `bar` does not, we will only check for - // borrows of `x.foo` and not `x.bar`. See #47703. - ty::Adt(def, substs) if def.is_struct() && !def.has_dtor(self.infcx.tcx) => { - def.all_fields() - .map(|field| field.ty(gcx, substs)) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Same as above, but for tuples. - ty::Tuple(tys) => { - tys.iter() - .cloned() - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Closures also have disjoint fields, but they are only - // directly accessed in the body of the closure. - ty::Closure(def, substs) - if *drop_place == Place::Local(Local::new(1)) - && !self.mir.upvar_decls.is_empty() => - { - substs - .upvar_tys(def, self.infcx.tcx) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Generators also have disjoint fields, but they are only - // directly accessed in the body of the generator. - ty::Generator(def, substs, _) - if *drop_place == Place::Local(Local::new(1)) - && !self.mir.upvar_decls.is_empty() => - { - substs - .upvar_tys(def, self.infcx.tcx) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - - // #45696: special-case Box by treating its dtor as - // only deep *across owned content*. Namely, we know - // dropping a box does not touch data behind any - // references it holds; if we were to instead fall into - // the base case below, we would have a Deep Write due to - // the box being `needs_drop`, and that Deep Write would - // touch `&mut` data in the box. - ty::Adt(def, _) if def.is_box() => { - // When/if we add a `&own T` type, this action would - // be like running the destructor of the `&own T`. - // (And the owner of backing storage referenced by the - // `&own T` would be responsible for deallocating that - // backing storage.) - - // we model dropping any content owned by the box by - // recurring on box contents. This catches cases like - // `Box>>`, while - // still restricting Write to *owned* content. - let ty = erased_drop_place_ty.boxed_ty(); - let deref_place = drop_place.clone().deref(); - debug!("visit_terminator_drop drop-box-content deref_place: {:?} ty: {:?}", - deref_place, ty); - let seen = prev_seen.cons(erased_drop_place_ty); - self.visit_terminator_drop( - loc, term, flow_state, &deref_place, ty, span, seen); - } - - _ => { - // We have now refined the type of the value being - // dropped (potentially) to just the type of a - // subfield; so check whether that field's type still - // "needs drop". - if erased_drop_place_ty.needs_drop(gcx, self.param_env) { - // If so, we assume that the destructor may access - // any data it likes (i.e., a Deep Write). - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Deep, Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::Destructor))), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } else { - // If there is no destructor, we still include a - // *shallow* write. This essentially ensures that - // borrows of the memory directly at `drop_place` - // cannot continue to be borrowed across the drop. - // - // If we were to use a Deep Write here, then any - // `&mut T` that is reachable from `drop_place` - // would get invalidated; fixing that is the - // essence of resolving issue #45696. - // - // * Note: In the compiler today, doing a Deep - // Write here would not actually break - // anything beyond #45696; for example it does not - // break this example: - // - // ```rust - // fn reborrow(x: &mut i32) -> &mut i32 { &mut *x } - // ``` - // - // Why? Because we do not schedule/emit - // `Drop(x)` in the MIR unless `x` needs drop in - // the first place. - self.access_place( - ContextKind::Drop.new(loc), - (drop_place, span), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop( - // rust-lang/rust#52059: distinguish - // between invaliding the backing storage - // vs running a destructor. - // - // See also: rust-lang/rust#52782, - // specifically #discussion_r206658948 - StorageDeadOrDrop::BoxedStorageDead))), - LocalMutationIsAllowed::Yes, - flow_state, - ); - } - } - } - } - /// Checks an access to the given place to see if it is allowed. Examines the set of borrows /// that are in scope, as well as which paths have been initialized, to ensure that (a) the /// place is initialized and (b) it is not borrowed in some way that would prevent this @@ -1103,7 +888,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &mut self, context: Context, place_span: (&Place<'tcx>, Span), - kind: (ShallowOrDeep, ReadOrWrite), + kind: (AccessDepth, ReadOrWrite), is_local_mutation_allowed: LocalMutationIsAllowed, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { @@ -1159,7 +944,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &mut self, context: Context, place_span: (&Place<'tcx>, Span), - sd: ShallowOrDeep, + sd: AccessDepth, rw: ReadOrWrite, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) -> bool { @@ -1200,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 } @@ -1212,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) } @@ -1252,7 +1043,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported = true; this.report_conflicting_borrow(context, place_span, bk, &borrow) } - WriteKind::StorageDeadOrDrop(_) => { + WriteKind::StorageDeadOrDrop => { error_reported = true; this.report_borrowed_value_does_not_live_long_enough( context, @@ -1281,7 +1072,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { &mut self, context: Context, place_span: (&Place<'tcx>, Span), - kind: ShallowOrDeep, + kind: AccessDepth, mode: MutateMode, flow_state: &Flows<'cx, 'gcx, 'tcx>, ) { @@ -1336,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); @@ -1355,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, ); @@ -1543,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. @@ -1597,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, }); @@ -1897,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) => { @@ -1925,10 +1730,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Reservation(wk @ WriteKind::Move) | Write(wk @ WriteKind::Move) - | Reservation(wk @ WriteKind::StorageDeadOrDrop(_)) + | Reservation(wk @ WriteKind::StorageDeadOrDrop) | Reservation(wk @ WriteKind::MutableBorrow(BorrowKind::Shared)) - | Write(wk @ WriteKind::StorageDeadOrDrop(_)) - | Write(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::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 @@ -1942,7 +1749,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_access = match wk { WriteKind::MutableBorrow(_) => AccessKind::MutableBorrow, WriteKind::Move => AccessKind::Move, - WriteKind::StorageDeadOrDrop(_) | + WriteKind::StorageDeadOrDrop | WriteKind::Mutate => AccessKind::Mutate, }; self.report_mutability_error( @@ -1971,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/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 755148b699253..f4052f948013a 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -143,13 +143,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name { Some(local_name) => { let mut should_note_order = false; - if let Some((WriteKind::StorageDeadOrDrop(_), place)) = kind_place { + if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { if let Place::Local(borrowed_local) = place { let dropped_local_scope = mir.local_decls[local].visibility_scope; let borrowed_local_scope = mir.local_decls[*borrowed_local].visibility_scope; - if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) { + if mir.is_sub_scope(borrowed_local_scope, dropped_local_scope) + && local != *borrowed_local + { should_note_order = true; } } diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index cd760746c125a..41f228f313b58 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -11,32 +11,28 @@ use borrow_check::borrow_set::BorrowSet; use borrow_check::location::LocationTable; use borrow_check::{JustWrite, WriteAndRead}; -use borrow_check::{ShallowOrDeep, Deep, Shallow}; +use borrow_check::{AccessDepth, Deep, Shallow}; use borrow_check::{ReadOrWrite, Activation, Read, Reservation, Write}; use borrow_check::{Context, ContextKind}; use borrow_check::{LocalMutationIsAllowed, MutateMode}; use borrow_check::ArtificialField; -use borrow_check::{ReadKind, WriteKind, StorageDeadOrDrop}; +use borrow_check::{ReadKind, WriteKind}; use borrow_check::nll::facts::AllFacts; use borrow_check::path_utils::*; use dataflow::move_paths::indexes::BorrowIndex; -use rustc::hir::def_id::DefId; -use rustc::infer::InferCtxt; +use rustc::ty::TyCtxt; use rustc::mir::visit::Visitor; -use rustc::mir::{BasicBlock, Location, Mir, Place, Rvalue, Local}; +use rustc::mir::{BasicBlock, Location, Mir, Place, Rvalue}; use rustc::mir::{Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; -use rustc::mir::{Field, Operand, BorrowKind}; -use rustc::ty::{self, ParamEnv}; -use rustc_data_structures::indexed_vec::Idx; +use rustc::mir::{Operand, BorrowKind}; use rustc_data_structures::graph::dominators::Dominators; pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( - infcx: &InferCtxt<'cx, 'gcx, 'tcx>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, all_facts: &mut Option, location_table: &LocationTable, mir: &Mir<'tcx>, - mir_def_id: DefId, borrow_set: &BorrowSet<'tcx>, ) { if !all_facts.is_some() { @@ -44,37 +40,32 @@ pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( return; } - let param_env = infcx.tcx.param_env(mir_def_id); - if let Some(all_facts) = all_facts { let dominators = mir.dominators(); let mut ig = InvalidationGenerator { all_facts, borrow_set, - infcx, + tcx, location_table, mir, dominators, - param_env, }; ig.visit_mir(mir); } } -/// 'cg = the duration of the constraint generation process itself. -struct InvalidationGenerator<'cg, 'cx: 'cg, 'tcx: 'cx, 'gcx: 'tcx> { - infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>, - all_facts: &'cg mut AllFacts, - location_table: &'cg LocationTable, - mir: &'cg Mir<'tcx>, +struct InvalidationGenerator<'cx, 'tcx: 'cx, 'gcx: 'tcx> { + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + all_facts: &'cx mut AllFacts, + location_table: &'cx LocationTable, + mir: &'cx Mir<'tcx>, dominators: Dominators, - borrow_set: &'cg BorrowSet<'tcx>, - param_env: ParamEnv<'gcx>, + borrow_set: &'cx BorrowSet<'tcx>, } /// Visits the whole MIR and generates invalidates() facts /// Most of the code implementing this was stolen from borrow_check/mod.rs -impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { +impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>, @@ -154,8 +145,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc self.access_place( ContextKind::StorageDead.new(location), &Place::Local(local), - (Shallow(None), Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::LocalStorageDead))), + (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), LocalMutationIsAllowed::Yes, ); } @@ -184,12 +174,12 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc target: _, unwind: _, } => { - let tcx = self.infcx.tcx; - let gcx = tcx.global_tcx(); - let drop_place_ty = drop_place.ty(self.mir, tcx); - let drop_place_ty = tcx.erase_regions(&drop_place_ty).to_ty(tcx); - let drop_place_ty = gcx.lift(&drop_place_ty).unwrap(); - self.visit_terminator_drop(location, terminator, drop_place, drop_place_ty); + self.access_place( + ContextKind::Drop.new(location), + drop_place, + (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)), + LocalMutationIsAllowed::Yes, + ); } TerminatorKind::DropAndReplace { location: ref drop_place, @@ -286,83 +276,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tc } } -impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { - /// Simulates dropping of a variable - fn visit_terminator_drop( - &mut self, - loc: Location, - term: &Terminator<'tcx>, - drop_place: &Place<'tcx>, - erased_drop_place_ty: ty::Ty<'gcx>, - ) { - let gcx = self.infcx.tcx.global_tcx(); - let drop_field = | - ig: &mut InvalidationGenerator<'cg, 'cx, 'gcx, 'tcx>, - (index, field): (usize, ty::Ty<'gcx>), - | { - let field_ty = gcx.normalize_erasing_regions(ig.param_env, field); - let place = drop_place.clone().field(Field::new(index), field_ty); - - ig.visit_terminator_drop(loc, term, &place, field_ty); - }; - - match erased_drop_place_ty.sty { - // When a struct is being dropped, we need to check - // whether it has a destructor, if it does, then we can - // call it, if it does not then we need to check the - // individual fields instead. This way if `foo` has a - // destructor but `bar` does not, we will only check for - // borrows of `x.foo` and not `x.bar`. See #47703. - ty::Adt(def, substs) if def.is_struct() && !def.has_dtor(self.infcx.tcx) => { - def.all_fields() - .map(|field| field.ty(gcx, substs)) - .enumerate() - .for_each(|field| drop_field(self, field)); - } - // Same as above, but for tuples. - ty::Tuple(tys) => { - tys.iter().cloned().enumerate() - .for_each(|field| drop_field(self, field)); - } - // Closures and generators also have disjoint fields, but they are only - // directly accessed in the body of the closure/generator. - ty::Generator(def, substs, ..) - if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() - => { - substs.upvar_tys(def, self.infcx.tcx).enumerate() - .for_each(|field| drop_field(self, field)); - } - ty::Closure(def, substs) - if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() - => { - substs.upvar_tys(def, self.infcx.tcx).enumerate() - .for_each(|field| drop_field(self, field)); - } - _ => { - // We have now refined the type of the value being - // dropped (potentially) to just the type of a - // subfield; so check whether that field's type still - // "needs drop". If so, we assume that the destructor - // may access any data it likes (i.e., a Deep Write). - if erased_drop_place_ty.needs_drop(gcx, self.param_env) { - self.access_place( - ContextKind::Drop.new(loc), - drop_place, - (Deep, Write(WriteKind::StorageDeadOrDrop( - StorageDeadOrDrop::Destructor))), - LocalMutationIsAllowed::Yes, - ); - } - } - } - } - +impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { /// Simulates mutation of a place fn mutate_place( &mut self, context: Context, place: &Place<'tcx>, - kind: ShallowOrDeep, + kind: AccessDepth, _mode: MutateMode, ) { self.access_place( @@ -409,10 +329,13 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, '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); - if allow_two_phase_borrow(&self.infcx.tcx, bk) { + if allow_two_phase_borrow(&self.tcx, bk) { (Deep, Reservation(wk)) } else { (Deep, Write(wk)) @@ -471,7 +394,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { &mut self, context: Context, place: &Place<'tcx>, - kind: (ShallowOrDeep, ReadOrWrite), + kind: (AccessDepth, ReadOrWrite), _is_local_mutation_allowed: LocalMutationIsAllowed, ) { let (sd, rw) = kind; @@ -483,7 +406,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { &mut self, context: Context, place: &Place<'tcx>, - sd: ShallowOrDeep, + sd: AccessDepth, rw: ReadOrWrite, ) { debug!( @@ -494,7 +417,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { sd, rw, ); - let tcx = self.infcx.tcx; + let tcx = self.tcx; let mir = self.mir; let borrow_set = self.borrow_set.clone(); let indices = self.borrow_set.borrows.indices(); @@ -519,6 +442,10 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { // have already taken the reservation } + (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) => { + // Sccess_place be called for BorrowKind::Match. + unreachable!(); + } (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) => { // Reads/reservations don't invalidate shared borrows } @@ -527,7 +454,7 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> { // Reading from mere reservations of mutable-borrows is OK. if !is_active(&this.dominators, borrow, context.loc) { // If the borrow isn't active yet, reads don't invalidate it - assert!(allow_two_phase_borrow(&this.infcx.tcx, borrow.kind)); + assert!(allow_two_phase_borrow(&this.tcx, borrow.kind)); return Control::Continue; } diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index 7cab0acb4326a..b9f22c7402a07 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -160,11 +160,10 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>( // Generate various additional constraints. invalidation::generate_invalidates( - infcx, + infcx.tcx, &mut all_facts, location_table, &mir, - def_id, borrow_set, ); diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs index 70b4e0ea2f03c..9250c04969f98 100644 --- a/src/librustc_mir/borrow_check/path_utils.rs +++ b/src/librustc_mir/borrow_check/path_utils.rs @@ -11,7 +11,7 @@ use borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation}; use borrow_check::places_conflict; use borrow_check::Context; -use borrow_check::ShallowOrDeep; +use borrow_check::AccessDepth; use dataflow::indexes::BorrowIndex; use rustc::mir::{BasicBlock, Location, Mir, Place}; use rustc::mir::{ProjectionElem, BorrowKind}; @@ -43,7 +43,7 @@ pub(super) fn each_borrow_involving_path<'a, 'tcx, 'gcx: 'tcx, F, I, S> ( tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, _context: Context, - access_place: (ShallowOrDeep, &Place<'tcx>), + access_place: (AccessDepth, &Place<'tcx>), borrow_set: &BorrowSet<'tcx>, candidates: I, mut op: F, @@ -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 3f055283e0c3f..3118f52dc90ba 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -10,22 +10,23 @@ use borrow_check::ArtificialField; use borrow_check::Overlap; -use borrow_check::{Deep, Shallow, ShallowOrDeep}; +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: ShallowOrDeep, + 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,8 +56,9 @@ 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: ShallowOrDeep, + access: AccessDepth, ) -> bool { // The borrowck rules for proving disjointness are applied from the "root" of the // borrow forwards, iterating over "similar" projections in lockstep until @@ -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,20 +185,30 @@ 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), _) => { - // the borrow goes through a dereference of a shared reference. - // - // I'm not sure why we are tracking these borrows - shared - // references can *always* be aliased, which means the - // permission check already account for this borrow. - debug!("places_conflict: behind a shared ref"); + // Shouldn't be tracked + bug!("Tracking borrow behind shared reference."); + } + (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"); return false; } + (ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => { + // Drop can read/write arbitrary projections, so places + // conflict regardless of further projections. + if def.has_dtor(tcx) { + return true; + } + } + (ProjectionElem::Deref, _, Deep) + | (ProjectionElem::Deref, _, AccessDepth::Drop) | (ProjectionElem::Field { .. }, _, _) | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) @@ -215,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; + } } } } @@ -231,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..aac5fc5ed7e91 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 @@ -2241,7 +2261,92 @@ that after `demo` finishes excuting, something else (such as the destructor!) could access `s.data` after the end of that shorter lifetime, which would again violate the `&mut`-borrow's exclusive access. +"##, + +E0714: r##" +This error indicates that a temporary value is being dropped +while a borrow is still in active use. + +Erroneous code example: +```compile_fail,E0714 +# #![feature(nll)] +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let p = bar(&foo()); + // ------ creates a temporary +let q = *p; +``` + +Here, the expression `&foo()` is borrowing the expression +`foo()`. As `foo()` is call to a function, and not the name of +a variable, this creates a **temporary** -- that temporary stores +the return value from `foo()` so that it can be borrowed. +So you might imagine that `let p = bar(&foo())` is equivalent +to this: + +```compile_fail,E0597 +# fn foo() -> i32 { 22 } +# fn bar(x: &i32) -> &i32 { x } +let p = { + let tmp = foo(); // the temporary + bar(&tmp) +}; // <-- tmp is freed as we exit this block +let q = p; +``` + +Whenever a temporary is created, it is automatically dropped (freed) +according to fixed rules. Ordinarily, the temporary is dropped +at the end of the enclosing statement -- in this case, after the `let`. +This is illustrated in the example above by showing that `tmp` would +be freed as we exit the block. + +To fix this problem, you need to create a local variable +to store the value in rather than relying on a temporary. +For example, you might change the original program to +the following: + +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = foo(); // dropped at the end of the enclosing block +let p = bar(&value); +let q = *p; +``` + +By introducing the explicit `let value`, we allocate storage +that will last until the end of the enclosing block (when `value` +goes out of scope). When we borrow `&value`, we are borrowing a +local variable that already exists, and hence no temporary is created. + +Temporaries are not always dropped at the end of the enclosing +statement. In simple cases where the `&` expression is immediately +stored into a variable, the compiler will automatically extend +the lifetime of the temporary until the end of the enclosinb +block. Therefore, an alternative way to fix the original +program is to write `let tmp = &foo()` and not `let tmp = foo()`: + +``` +fn foo() -> i32 { 22 } +fn bar(x: &i32) -> &i32 { x } +let value = &foo(); +let p = bar(value); +let q = *p; +``` + +Here, we are still borrowing `foo()`, but as the borrow is assigned +directly into a variable, the temporary will not be dropped until +the end of the enclosing block. Similar rules apply when temporaries +are stored into aggregate structures like a tuple or struct: + +``` +// Here, two temporaries are created, but +// as they are stored directly into `value`, +// they are not dropped until the end of the +// enclosing block. +fn foo() -> i32 { 22 } +let value = (&foo(), &foo()); +``` "##, } 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..c78020a260979 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, @@ -707,6 +730,22 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self.cancel_if_wrong_origin(err, o) } + + fn temporary_value_borrowed_for_too_long( + self, + span: Span, + o: Origin, + ) -> DiagnosticBuilder<'cx> { + let err = struct_span_err!( + self, + span, + E0714, + "temporary value dropped while borrowed{OGN}", + OGN = o + ); + + self.cancel_if_wrong_origin(err, o) + } } impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> { 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..fe2593678a068 --- /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 unwinding being disabled causes differences in output + +#![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-borrow-from-temporary.nll.stderr b/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr new file mode 100644 index 0000000000000..894eb4cc4a2ee --- /dev/null +++ b/src/test/ui/borrowck/borrowck-borrow-from-temporary.nll.stderr @@ -0,0 +1,18 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/borrowck-borrow-from-temporary.rs:19:24 + | +LL | let &Foo(ref x) = &id(Foo(3)); //~ ERROR borrowed value does not live long enough + | ^^^^^^^^^^ creates a temporary which is freed while still in use +LL | x +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 18:8... + --> $DIR/borrowck-borrow-from-temporary.rs:18:8 + | +LL | fn foo<'a>() -> &'a isize { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr index eee3f9bd5c130..1b5a1f4b29bf0 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue-2.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-borrowed-uniq-rvalue-2.rs:32:20 | LL | let x = defer(&vec!["Goodbye", "world!"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use LL | x.x[0]; | ------ borrow later used here | @@ -13,4 +13,4 @@ LL | x.x[0]; error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr index ebf229696d8a9..9236e9e228833 100644 --- a/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr +++ b/src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-borrowed-uniq-rvalue.rs:20:28 | LL | buggy_map.insert(42, &*Box::new(1)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | buggy_map.insert(43, &*tmp); | --------- borrow later used here @@ -13,4 +13,4 @@ LL | buggy_map.insert(43, &*tmp); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. 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/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr index 52f1547bce6f8..a4fc91f208df4 100644 --- a/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr +++ b/src/test/ui/borrowck/promote-ref-mut-in-let-issue-46557.nll.stderr @@ -1,57 +1,57 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:15:21 | LL | let ref mut x = 1234543; //~ ERROR - | ^^^^^^^ temporary value does not live long enough + | ^^^^^^^ creates a temporary which is freed while still in use LL | x LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:20:25 | LL | let (ref mut x, ) = (1234543, ); //~ ERROR - | ^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^ creates a temporary which is freed while still in use LL | x LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:25:11 | LL | match 1234543 { - | ^^^^^^^ temporary value does not live long enough + | ^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:31:11 | LL | match (123443,) { - | ^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/promote-ref-mut-in-let-issue-46557.rs:37:10 | LL | &mut 1234543 //~ ERROR - | ^^^^^^^ temporary value does not live long enough + | ^^^^^^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. 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/dont_promote_unstable_const_fn.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr new file mode 100644 index 0000000000000..e257fdb31e767 --- /dev/null +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.nll.stderr @@ -0,0 +1,43 @@ +error: `foo` is not yet stable as a const fn + --> $DIR/dont_promote_unstable_const_fn.rs:25:25 + | +LL | const fn bar() -> u32 { foo() } //~ ERROR `foo` is not yet stable as a const fn + | ^^^^^ + | + = help: in Nightly builds, add `#![feature(foo)]` to the crate attributes to enable + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:28:28 + | +LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:32:28 + | +LL | let _: &'static u32 = &meh(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn.rs:33:26 + | +LL | let x: &'static _ = &std::time::Duration::from_millis(42).subsec_millis(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr new file mode 100644 index 0000000000000..6ec0733640961 --- /dev/null +++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn_cross_crate.nll.stderr @@ -0,0 +1,24 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:18:28 + | +LL | let _: &'static u32 = &foo(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/dont_promote_unstable_const_fn_cross_crate.rs:19:29 + | +LL | let _x: &'static u32 = &foo(); //~ ERROR does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. 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/consts/const-eval/promoted_raw_ptr_ops.nll.stderr b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr new file mode 100644 index 0000000000000..acc6104d9e21c --- /dev/null +++ b/src/test/ui/consts/const-eval/promoted_raw_ptr_ops.nll.stderr @@ -0,0 +1,35 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:14:29 + | +LL | let x: &'static bool = &(42 as *const i32 == 43 as *const i32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:16:30 + | +LL | let y: &'static usize = &(&1 as *const i32 as usize + 1); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/promoted_raw_ptr_ops.rs:17:28 + | +LL | let z: &'static i32 = &(unsafe { *(42 as *const i32) }); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr b/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr new file mode 100644 index 0000000000000..e11f589b1052d --- /dev/null +++ b/src/test/ui/consts/const-eval/transmute-const-promotion.nll.stderr @@ -0,0 +1,14 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/transmute-const-promotion.rs:16:37 + | +LL | let x: &'static u32 = unsafe { &mem::transmute(3.0f32) }; + | ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR value does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-eval/union_promotion.nll.stderr b/src/test/ui/consts/const-eval/union_promotion.nll.stderr new file mode 100644 index 0000000000000..9437cacd7734c --- /dev/null +++ b/src/test/ui/consts/const-eval/union_promotion.nll.stderr @@ -0,0 +1,16 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/union_promotion.rs:19:29 + | +LL | let x: &'static bool = &unsafe { //~ borrowed value does not live long enough + | _____________________________^ +LL | | Foo { a: &1 }.b == Foo { a: &2 }.b +LL | | }; + | |_____^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-conversion.nll.stderr b/src/test/ui/consts/const-int-conversion.nll.stderr new file mode 100644 index 0000000000000..922905477f380 --- /dev/null +++ b/src/test/ui/consts/const-int-conversion.nll.stderr @@ -0,0 +1,80 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:14:28 + | +LL | let x: &'static i32 = &(5_i32.reverse_bits()); + | ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:16:28 + | +LL | let y: &'static i32 = &(i32::from_be_bytes([0x12, 0x34, 0x56, 0x78])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:18:28 + | +LL | let z: &'static i32 = &(i32::from_le_bytes([0x12, 0x34, 0x56, 0x78])); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:20:28 + | +LL | let a: &'static i32 = &(i32::from_be(i32::from_ne_bytes([0x80, 0, 0, 0]))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:22:29 + | +LL | let b: &'static [u8] = &(0x12_34_56_78_i32.to_be_bytes()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:24:29 + | +LL | let c: &'static [u8] = &(0x12_34_56_78_i32.to_le_bytes()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-conversion.rs:26:29 + | +LL | let d: &'static [u8] = &(i32::min_value().to_be().to_ne_bytes()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-overflowing.nll.stderr b/src/test/ui/consts/const-int-overflowing.nll.stderr new file mode 100644 index 0000000000000..fd420658c7ad4 --- /dev/null +++ b/src/test/ui/consts/const-int-overflowing.nll.stderr @@ -0,0 +1,35 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:12:36 + | +LL | let x: &'static (i32, bool) = &(5_i32.overflowing_add(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:13:36 + | +LL | let y: &'static (i32, bool) = &(5_i32.overflowing_sub(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-overflowing.rs:14:36 + | +LL | let z: &'static (i32, bool) = &(5_i32.overflowing_mul(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-rotate.nll.stderr b/src/test/ui/consts/const-int-rotate.nll.stderr new file mode 100644 index 0000000000000..d66017a289bca --- /dev/null +++ b/src/test/ui/consts/const-int-rotate.nll.stderr @@ -0,0 +1,24 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-rotate.rs:12:28 + | +LL | let x: &'static i32 = &(5_i32.rotate_left(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-rotate.rs:13:28 + | +LL | let y: &'static i32 = &(5_i32.rotate_right(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-sign.nll.stderr b/src/test/ui/consts/const-int-sign.nll.stderr new file mode 100644 index 0000000000000..62a2b111ed9c3 --- /dev/null +++ b/src/test/ui/consts/const-int-sign.nll.stderr @@ -0,0 +1,24 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-sign.rs:12:29 + | +LL | let x: &'static bool = &(5_i32.is_negative()); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-sign.rs:13:29 + | +LL | let y: &'static bool = &(5_i32.is_positive()); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/const-int-wrapping.nll.stderr b/src/test/ui/consts/const-int-wrapping.nll.stderr new file mode 100644 index 0000000000000..4c6c98188dccb --- /dev/null +++ b/src/test/ui/consts/const-int-wrapping.nll.stderr @@ -0,0 +1,57 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:12:28 + | +LL | let x: &'static i32 = &(5_i32.wrapping_add(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:13:28 + | +LL | let y: &'static i32 = &(5_i32.wrapping_sub(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:14:28 + | +LL | let z: &'static i32 = &(5_i32.wrapping_mul(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:15:28 + | +LL | let a: &'static i32 = &(5_i32.wrapping_shl(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error[E0714]: temporary value dropped while borrowed + --> $DIR/const-int-wrapping.rs:16:28 + | +LL | let b: &'static i32 = &(5_i32.wrapping_shr(3)); //~ ERROR does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr index 5803b5e355a2c..d79fd6571192e 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.nll.stderr @@ -190,13 +190,13 @@ error: trait bounds other than `Sized` on const fn parameters are unstable LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/min_const_fn.rs:144:64 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^^ - temporary value only lives until here + | ^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... @@ -220,5 +220,5 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } error: aborting due to 36 previous errors -Some errors occurred: E0493, E0597. +Some errors occurred: E0493, E0714. For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr index cfcc7990fb30d..8d8fe7cfbebf6 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.nll.stderr @@ -10,16 +10,16 @@ error: trait bounds other than `Sized` on const fn parameters are unstable LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | ^^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/min_const_fn_dyn.rs:24:67 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } - | ^ - temporary value only lives until here + | ^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/dropck/dropck-union.nll.stderr b/src/test/ui/dropck/dropck-union.nll.stderr index 35d7ffc7879ed..ffb322b85dc34 100644 --- a/src/test/ui/dropck/dropck-union.nll.stderr +++ b/src/test/ui/dropck/dropck-union.nll.stderr @@ -8,8 +8,6 @@ LL | } | | | `v` dropped here while still borrowed | borrow later used here, when `v` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/generator/dropck.nll.stderr b/src/test/ui/generator/dropck.nll.stderr index b49bf81715079..ef7e64ffd97ae 100644 --- a/src/test/ui/generator/dropck.nll.stderr +++ b/src/test/ui/generator/dropck.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `*cell` dropped here while still borrowed | borrow later used here, when `gen` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `ref_` does not live long enough --> $DIR/dropck.rs:22:11 diff --git a/src/test/ui/issues/issue-11681.nll.stderr b/src/test/ui/issues/issue-11681.nll.stderr new file mode 100644 index 0000000000000..8ded4f6e76879 --- /dev/null +++ b/src/test/ui/issues/issue-11681.nll.stderr @@ -0,0 +1,18 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-11681.rs:22:20 + | +LL | let testValue = &Test; //~ ERROR borrowed value does not live long enough + | ^^^^ creates a temporary which is freed while still in use +LL | return testValue; +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 21:15... + --> $DIR/issue-11681.rs:21:15 + | +LL | fn createTest<'a>() -> &'a Test { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-17545.nll.stderr b/src/test/ui/issues/issue-17545.nll.stderr index 50a4b3f7f3e82..3f9fa694c349e 100644 --- a/src/test/ui/issues/issue-17545.nll.stderr +++ b/src/test/ui/issues/issue-17545.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-17545.rs:17:10 | LL | &id(()), //~ ERROR borrowed value does not live long enough - | ^^^^^^ temporary value does not live long enough + | ^^^^^^ creates a temporary which is freed while still in use LL | )); - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:12... --> $DIR/issue-17545.rs:15:12 @@ -14,4 +14,4 @@ LL | pub fn foo<'a, F: Fn(&'a ())>(bar: F) { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr b/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr new file mode 100644 index 0000000000000..c0795acbbb9d0 --- /dev/null +++ b/src/test/ui/issues/issue-17718-constants-not-static.nll.stderr @@ -0,0 +1,13 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-17718-constants-not-static.rs:15:31 + | +LL | fn foo() -> &'static usize { &id(FOO) } + | ^^^^^^^ - temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. 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/issues/issue-27592.nll.stderr b/src/test/ui/issues/issue-27592.nll.stderr index 36a15e79ac825..a41b3f8201893 100644 --- a/src/test/ui/issues/issue-27592.nll.stderr +++ b/src/test/ui/issues/issue-27592.nll.stderr @@ -1,19 +1,19 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-27592.rs:26:27 | LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^ - temporary value only lives until here + | ^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-27592.rs:26:33 | LL | write(|| format_args!("{}", String::from("Hello world"))); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-30438-a.nll.stderr b/src/test/ui/issues/issue-30438-a.nll.stderr index 2d27cd55e019a..9acaaaa274709 100644 --- a/src/test/ui/issues/issue-30438-a.nll.stderr +++ b/src/test/ui/issues/issue-30438-a.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-30438-a.rs:22:17 | LL | return &Test { s: &self.s}; - | ^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 21:5... --> $DIR/issue-30438-a.rs:21:5 @@ -17,4 +17,4 @@ LL | | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-30438-b.nll.stderr b/src/test/ui/issues/issue-30438-b.nll.stderr new file mode 100644 index 0000000000000..02344c50a38ad --- /dev/null +++ b/src/test/ui/issues/issue-30438-b.nll.stderr @@ -0,0 +1,21 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-30438-b.rs:23:10 + | +LL | &Test { s: &self.s} + | ^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR: borrowed value does not live long enough +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 22:5... + --> $DIR/issue-30438-b.rs:22:5 + | +LL | / fn index(&self, _: usize) -> &Self::Output { +LL | | &Test { s: &self.s} +LL | | //~^ ERROR: borrowed value does not live long enough +LL | | } + | |_____^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-36082.ast.nll.stderr b/src/test/ui/issues/issue-36082.ast.nll.stderr index e02f21f6e1247..4a481da6522ce 100644 --- a/src/test/ui/issues/issue-36082.ast.nll.stderr +++ b/src/test/ui/issues/issue-36082.ast.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-36082.rs:23:19 | LL | let val: &_ = x.borrow().0; - | ^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | println!("{}", val); | --- borrow later used here @@ -13,4 +13,4 @@ LL | println!("{}", val); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-36082.mir.stderr b/src/test/ui/issues/issue-36082.mir.stderr index e02f21f6e1247..4a481da6522ce 100644 --- a/src/test/ui/issues/issue-36082.mir.stderr +++ b/src/test/ui/issues/issue-36082.mir.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-36082.rs:23:19 | LL | let val: &_ = x.borrow().0; - | ^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | println!("{}", val); | --- borrow later used here @@ -13,4 +13,4 @@ LL | println!("{}", val); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-36082.rs b/src/test/ui/issues/issue-36082.rs index 579ec4d923be1..018d5bf091885 100644 --- a/src/test/ui/issues/issue-36082.rs +++ b/src/test/ui/issues/issue-36082.rs @@ -25,9 +25,9 @@ fn main() { //[ast]~| NOTE temporary value dropped here while still borrowed //[ast]~| NOTE temporary value does not live long enough //[ast]~| NOTE consider using a `let` binding to increase its lifetime - //[mir]~^^^^^ ERROR borrowed value does not live long enough [E0597] - //[mir]~| NOTE temporary value does not live long enough - //[mir]~| NOTE temporary value only lives until here + //[mir]~^^^^^ ERROR temporary value dropped while borrowed [E0714] + //[mir]~| NOTE temporary value is freed at the end of this statement + //[mir]~| NOTE creates a temporary which is freed while still in use //[mir]~| NOTE consider using a `let` binding to create a longer lived value println!("{}", val); //[mir]~^ borrow later used here diff --git a/src/test/ui/issues/issue-44373.nll.stderr b/src/test/ui/issues/issue-44373.nll.stderr new file mode 100644 index 0000000000000..9a6c59aaa20d6 --- /dev/null +++ b/src/test/ui/issues/issue-44373.nll.stderr @@ -0,0 +1,13 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/issue-44373.rs:15:42 + | +LL | let _val: &'static [&'static u32] = &[&FOO]; //~ ERROR borrowed value does not live long enough + | ^^^^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr index 70d819f0f4678..5c753817e358d 100644 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr +++ b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.migrate.stderr @@ -23,7 +23,7 @@ LL | &mut *(*s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^ ... LL | } - | - here, drop of `*s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 @@ -41,7 +41,7 @@ LL | &mut *(**s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^^ ... LL | } - | - here, drop of `**s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 diff --git a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr index 72ec5affb182b..79a7c0631f480 100644 --- a/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr +++ b/src/test/ui/issues/issue-45696-scribble-on-boxed-borrow.nll.stderr @@ -20,7 +20,7 @@ LL | &mut *(*s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^ ... LL | } - | - here, drop of `*s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20 @@ -35,7 +35,7 @@ LL | &mut *(**s).0 //[nll]~ ERROR borrow may still be in use when destructor | ^^^^^^^^^^^^^ ... LL | } - | - here, drop of `**s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait + | - here, drop of `s` needs exclusive access to `*s.0`, because the type `Scribble<'_>` implements the `Drop` trait | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26... --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26 diff --git a/src/test/ui/issues/issue-46472.rs b/src/test/ui/issues/issue-46472.rs index 02c4dd7cb21d8..79e805c5356c5 100644 --- a/src/test/ui/issues/issue-46472.rs +++ b/src/test/ui/issues/issue-46472.rs @@ -13,7 +13,7 @@ fn bar<'a>() -> &'a mut u32 { &mut 4 //~^ ERROR borrowed value does not live long enough (Ast) [E0597] - //~| ERROR borrowed value does not live long enough (Mir) [E0597] + //~| ERROR temporary value dropped while borrowed (Mir) [E0714] } fn main() { } diff --git a/src/test/ui/issues/issue-46472.stderr b/src/test/ui/issues/issue-46472.stderr index 9e5acf56d26ca..39c4e091fd2a1 100644 --- a/src/test/ui/issues/issue-46472.stderr +++ b/src/test/ui/issues/issue-46472.stderr @@ -13,14 +13,14 @@ note: borrowed value must be valid for the lifetime 'a as defined on the functio LL | fn bar<'a>() -> &'a mut u32 { | ^^ -error[E0597]: borrowed value does not live long enough (Mir) +error[E0714]: temporary value dropped while borrowed (Mir) --> $DIR/issue-46472.rs:14:10 | LL | &mut 4 - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:8... --> $DIR/issue-46472.rs:13:8 @@ -30,4 +30,5 @@ LL | fn bar<'a>() -> &'a mut u32 { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-47184.rs b/src/test/ui/issues/issue-47184.rs index 0831b7e0af8e2..fbf67a3b4fc08 100644 --- a/src/test/ui/issues/issue-47184.rs +++ b/src/test/ui/issues/issue-47184.rs @@ -12,5 +12,5 @@ fn main() { let _vec: Vec<&'static String> = vec![&String::new()]; - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] } diff --git a/src/test/ui/issues/issue-47184.stderr b/src/test/ui/issues/issue-47184.stderr index 32a9783e9c213..1a4b7ae16bffd 100644 --- a/src/test/ui/issues/issue-47184.stderr +++ b/src/test/ui/issues/issue-47184.stderr @@ -1,13 +1,13 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-47184.rs:14:44 | LL | let _vec: Vec<&'static String> = vec![&String::new()]; - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/issues/issue-52049.nll.stderr b/src/test/ui/issues/issue-52049.nll.stderr index 6f71f1676119a..ad4cd48c9deb9 100644 --- a/src/test/ui/issues/issue-52049.nll.stderr +++ b/src/test/ui/issues/issue-52049.nll.stderr @@ -1,13 +1,13 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-52049.rs:16:10 | LL | foo(&unpromotable(5u32)); - | ^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr index a8a1b33c925bc..0747405cf14cc 100644 --- a/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion.rs:12:17 | LL | let mut x = vec![1].iter(); - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use LL | //~^ ERROR borrowed value does not live long enough LL | x.use_mut(); | - borrow later used here @@ -14,4 +14,4 @@ LL | x.use_mut(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. 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/borrowed-temporary-error.rs b/src/test/ui/nll/borrowed-temporary-error.rs index 7aad7205a52a1..d0b53359cd0e4 100644 --- a/src/test/ui/nll/borrowed-temporary-error.rs +++ b/src/test/ui/nll/borrowed-temporary-error.rs @@ -18,7 +18,7 @@ fn main() { let x = gimme({ let v = 22; &(v,) - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] }); println!("{:?}", x); } diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr index 8b69c57d3765d..a929914d8df71 100644 --- a/src/test/ui/nll/borrowed-temporary-error.stderr +++ b/src/test/ui/nll/borrowed-temporary-error.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowed-temporary-error.rs:20:10 | LL | &(v,) - | ^^^^ temporary value does not live long enough -LL | //~^ ERROR borrowed value does not live long enough [E0597] + | ^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR temporary value dropped while borrowed [E0714] LL | }); - | - temporary value only lives until here + | - temporary value is freed at the end of this statement LL | println!("{:?}", x); | - borrow later used here | @@ -13,4 +13,4 @@ LL | println!("{:?}", x); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/nll/borrowed-universal-error.rs b/src/test/ui/nll/borrowed-universal-error.rs index 9482b9b140002..5ea91d3618afd 100644 --- a/src/test/ui/nll/borrowed-universal-error.rs +++ b/src/test/ui/nll/borrowed-universal-error.rs @@ -18,7 +18,7 @@ fn gimme(x: &(u32,)) -> &u32 { fn foo<'a>(x: &'a (u32,)) -> &'a u32 { let v = 22; gimme(&(v,)) - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] } fn main() {} diff --git a/src/test/ui/nll/borrowed-universal-error.stderr b/src/test/ui/nll/borrowed-universal-error.stderr index da287980e8c5f..a65a396d2ab64 100644 --- a/src/test/ui/nll/borrowed-universal-error.stderr +++ b/src/test/ui/nll/borrowed-universal-error.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowed-universal-error.rs:20:12 | LL | gimme(&(v,)) - | ^^^^ temporary value does not live long enough -LL | //~^ ERROR borrowed value does not live long enough [E0597] + | ^^^^ creates a temporary which is freed while still in use +LL | //~^ ERROR temporary value dropped while borrowed [E0714] LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 18:8... --> $DIR/borrowed-universal-error.rs:18:8 @@ -15,4 +15,4 @@ LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/nll/enum-drop-access.rs b/src/test/ui/nll/enum-drop-access.rs new file mode 100644 index 0000000000000..dc436d20fd857 --- /dev/null +++ b/src/test/ui/nll/enum-drop-access.rs @@ -0,0 +1,51 @@ +#![feature(nll)] + +enum DropOption { + Some(T), + None, +} + +impl Drop for DropOption { + fn drop(&mut self) {} +} + +// Dropping opt could access the value behind the reference, +fn drop_enum(opt: DropOption<&mut i32>) -> Option<&mut i32> { + match opt { + DropOption::Some(&mut ref mut r) => { //~ ERROR + Some(r) + }, + DropOption::None => None, + } +} + +fn optional_drop_enum(opt: Option>) -> Option<&mut i32> { + match opt { + Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR + Some(r) + }, + Some(DropOption::None) | None => None, + } +} + +// Ok, dropping opt doesn't access the reference +fn optional_tuple(opt: Option<(&mut i32, String)>) -> Option<&mut i32> { + match opt { + Some((&mut ref mut r, _)) => { + Some(r) + }, + None => None, + } +} + +// Ok, dropping res doesn't access the Ok case. +fn different_variants(res: Result<&mut i32, String>) -> Option<&mut i32> { + match res { + Ok(&mut ref mut r) => { + Some(r) + }, + Err(_) => None, + } +} + +fn main() {} diff --git a/src/test/ui/nll/enum-drop-access.stderr b/src/test/ui/nll/enum-drop-access.stderr new file mode 100644 index 0000000000000..57daf26596dfb --- /dev/null +++ b/src/test/ui/nll/enum-drop-access.stderr @@ -0,0 +1,45 @@ +error[E0713]: borrow may still be in use when destructor runs + --> $DIR/enum-drop-access.rs:15:31 + | +LL | DropOption::Some(&mut ref mut r) => { //~ ERROR + | ^^^^^^^^^ +... +LL | } + | - here, drop of `opt` needs exclusive access to `*opt.0`, because the type `DropOption<&mut i32>` implements the `Drop` trait + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1... + --> $DIR/enum-drop-access.rs:13:1 + | +LL | / fn drop_enum(opt: DropOption<&mut i32>) -> Option<&mut i32> { +LL | | match opt { +LL | | DropOption::Some(&mut ref mut r) => { //~ ERROR +LL | | Some(r) +... | +LL | | } +LL | | } + | |_^ + +error[E0713]: borrow may still be in use when destructor runs + --> $DIR/enum-drop-access.rs:24:36 + | +LL | Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR + | ^^^^^^^^^ +... +LL | } + | - here, drop of `opt` needs exclusive access to `*opt.0.0`, because the type `DropOption<&mut i32>` implements the `Drop` trait + | +note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 22:1... + --> $DIR/enum-drop-access.rs:22:1 + | +LL | / fn optional_drop_enum(opt: Option>) -> Option<&mut i32> { +LL | | match opt { +LL | | Some(DropOption::Some(&mut ref mut r)) => { //~ ERROR +LL | | Some(r) +... | +LL | | } +LL | | } + | |_^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0713`. diff --git a/src/test/ui/nll/issue-52534-1.stderr b/src/test/ui/nll/issue-52534-1.stderr index e2f8134e3be0e..9bb32c3ed3dc7 100644 --- a/src/test/ui/nll/issue-52534-1.stderr +++ b/src/test/ui/nll/issue-52534-1.stderr @@ -52,13 +52,13 @@ LL | } = note: functions cannot return a borrow to data owned within the function's scope, functions can only return borrows to data passed as arguments = note: to learn more, visit -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-52534-1.rs:30:6 | LL | &&x - | ^^ temporary value does not live long enough + | ^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 28:1... --> $DIR/issue-52534-1.rs:28:1 @@ -137,4 +137,5 @@ LL | } error: aborting due to 8 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`. 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`. diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.rs b/src/test/ui/nll/return-ref-mut-issue-46557.rs index 79150f340cad8..82222530335e7 100644 --- a/src/test/ui/nll/return-ref-mut-issue-46557.rs +++ b/src/test/ui/nll/return-ref-mut-issue-46557.rs @@ -14,7 +14,7 @@ #![allow(dead_code)] fn gimme_static_mut() -> &'static mut u32 { - let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597] + let ref mut x = 1234543; //~ ERROR temporary value dropped while borrowed [E0714] x } diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.stderr b/src/test/ui/nll/return-ref-mut-issue-46557.stderr index f441085f242ed..1e8224c8ddbd5 100644 --- a/src/test/ui/nll/return-ref-mut-issue-46557.stderr +++ b/src/test/ui/nll/return-ref-mut-issue-46557.stderr @@ -1,14 +1,14 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/return-ref-mut-issue-46557.rs:17:21 | -LL | let ref mut x = 1234543; //~ ERROR borrowed value does not live long enough [E0597] - | ^^^^^^^ temporary value does not live long enough +LL | let ref mut x = 1234543; //~ ERROR temporary value dropped while borrowed [E0714] + | ^^^^^^^ creates a temporary which is freed while still in use LL | x LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/nll/user-annotations/patterns.rs b/src/test/ui/nll/user-annotations/patterns.rs index 53d97360c869e..971a737702490 100644 --- a/src/test/ui/nll/user-annotations/patterns.rs +++ b/src/test/ui/nll/user-annotations/patterns.rs @@ -51,13 +51,13 @@ fn underscore_with_initializer() { let _: &'static u32 = &x; //~ ERROR let _: Vec<&'static String> = vec![&String::new()]; - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); - //~^ ERROR borrowed value does not live long enough [E0597] + //~^ ERROR temporary value dropped while borrowed [E0714] } fn pair_underscores_with_initializer() { diff --git a/src/test/ui/nll/user-annotations/patterns.stderr b/src/test/ui/nll/user-annotations/patterns.stderr index f359608462d1d..0e3109413bdf0 100644 --- a/src/test/ui/nll/user-annotations/patterns.stderr +++ b/src/test/ui/nll/user-annotations/patterns.stderr @@ -40,33 +40,33 @@ LL | } | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/patterns.rs:53:41 | LL | let _: Vec<&'static String> = vec![&String::new()]; - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/patterns.rs:56:52 | LL | let (_, a): (Vec<&'static String>, _) = (vec![&String::new()], 44); - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/patterns.rs:59:53 | LL | let (_a, b): (Vec<&'static String>, _) = (vec![&String::new()], 44); - | ^^^^^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | = note: borrowed value must be valid for the static lifetime... @@ -140,4 +140,5 @@ LL | let (y, _z): (&'static u32, u32) = (x, 44); //~ ERROR error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/regions/regions-creating-enums.nll.stderr b/src/test/ui/regions/regions-creating-enums.nll.stderr index 58dff9c6c37c7..df2e3558612c3 100644 --- a/src/test/ui/regions/regions-creating-enums.nll.stderr +++ b/src/test/ui/regions/regions-creating-enums.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-creating-enums.rs:33:17 | LL | return &ast::num((*f)(x)); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 30:13... --> $DIR/regions-creating-enums.rs:30:13 @@ -12,13 +12,13 @@ note: borrowed value must be valid for the lifetime 'a as defined on the functio LL | fn map_nums<'a,'b, F>(x: &ast, f: &mut F) -> &'a ast<'b> where F: FnMut(usize) -> usize { | ^^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-creating-enums.rs:38:17 | LL | return &ast::add(m_x, m_y); //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 30:13... --> $DIR/regions-creating-enums.rs:30:13 @@ -28,4 +28,4 @@ LL | fn map_nums<'a,'b, F>(x: &ast, f: &mut F) -> &'a ast<'b> where F: FnMut(usi error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr index acf7a033ade17..3bac4db347545 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-free-region-ordering-caller1.rs:19:27 | LL | let z: &'a & usize = &(&y); - | ^^^^ temporary value does not live long enough + | ^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:10... --> $DIR/regions-free-region-ordering-caller1.rs:15:10 @@ -15,4 +15,4 @@ LL | fn call1<'a>(x: &'a usize) { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr new file mode 100644 index 0000000000000..0a6b9b718b5c8 --- /dev/null +++ b/src/test/ui/regions/regions-lifetime-of-struct-or-enum-variant.nll.stderr @@ -0,0 +1,33 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:24:20 + | +LL | let testValue = &id(Test); + | ^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 23:19... + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:23:19 + | +LL | fn structLifetime<'a>() -> &'a Test { + | ^^ + +error[E0714]: temporary value dropped while borrowed + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:30:20 + | +LL | let testValue = &id(MyEnum::Variant1); + | ^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use +... +LL | } + | - temporary value is freed at the end of this statement + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 29:20... + --> $DIR/regions-lifetime-of-struct-or-enum-variant.rs:29:20 + | +LL | fn variantLifetime<'a>() -> &'a MyEnum { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr b/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr index 87fe858769d18..af84d36e0b4e2 100644 --- a/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr +++ b/src/test/ui/regions/regions-ref-in-fn-arg.nll.stderr @@ -1,22 +1,22 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-ref-in-fn-arg.rs:14:13 | LL | fn arg_item(box ref x: Box) -> &'static isize { - | ^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^ creates a temporary which is freed while still in use LL | x //~^ ERROR borrowed value does not live long enough LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-ref-in-fn-arg.rs:21:11 | LL | with(|box ref x| x) //~ ERROR borrowed value does not live long enough - | ^^^^^^^^^ - temporary value only lives until here + | ^^^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-ret.nll.stderr b/src/test/ui/regions/regions-ret.nll.stderr index cacc119d41013..8dfb7c18480b6 100644 --- a/src/test/ui/regions/regions-ret.nll.stderr +++ b/src/test/ui/regions/regions-ret.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-ret.rs:14:13 | LL | return &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^- temporary value only lives until here + | ^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 13:1... --> $DIR/regions-ret.rs:13:1 @@ -16,4 +16,4 @@ LL | | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr b/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr new file mode 100644 index 0000000000000..919e29e4ec46d --- /dev/null +++ b/src/test/ui/regions/regions-return-stack-allocated-vec.nll.stderr @@ -0,0 +1,13 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/regions-return-stack-allocated-vec.rs:14:6 + | +LL | &[x] //~ ERROR borrowed value does not live long enough + | ^^^ creates a temporary which is freed while still in use +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr b/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr index aa744a3ae8a74..6d1b9938a8b35 100644 --- a/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr +++ b/src/test/ui/regions/regions-var-type-out-of-scope.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-var-type-out-of-scope.rs:19:14 | LL | x = &id(3); //~ ERROR borrowed value does not live long enough - | ^^^^^- temporary value only lives until here + | ^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use LL | assert_eq!(*x, 3); | ------------------ borrow later used here | @@ -13,4 +13,4 @@ LL | assert_eq!(*x, 3); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr b/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr index 001eba4b039b1..765d8b36b0e69 100644 --- a/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr +++ b/src/test/ui/span/borrowck-let-suggestion-suffixes.nll.stderr @@ -1,36 +1,36 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:28:14 | LL | v3.push(&id('x')); // statement 6 - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here | = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:38:18 | LL | v4.push(&id('y')); - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | v4.use_ref(); | -- borrow later used here | = note: consider using a `let` binding to create a longer lived value -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/borrowck-let-suggestion-suffixes.rs:49:14 | LL | v5.push(&id('z')); - | ^^^^^^^ - temporary value only lives until here + | ^^^^^^^ - temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use ... LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); | -- borrow later used here @@ -39,4 +39,4 @@ LL | (v1, v2, v3, /* v4 is above. */ v5).use_ref(); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr b/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr index c94558f12bbde..c565842c2c002 100644 --- a/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr +++ b/src/test/ui/span/borrowck-ref-into-rvalue.nll.stderr @@ -1,11 +1,11 @@ -error[E0713]: borrow may still be in use when destructor runs - --> $DIR/borrowck-ref-into-rvalue.rs:14:14 +error[E0597]: borrowed value does not live long enough + --> $DIR/borrowck-ref-into-rvalue.rs:13:11 | -LL | Some(ref m) => { - | ^^^^^ +LL | match Some("Hello".to_string()) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough ... LL | } - | - drop of temporary value occurs here + | - temporary value only lives until here LL | println!("{}", *msg); | ---- borrow later used here | @@ -13,4 +13,4 @@ LL | println!("{}", *msg); error: aborting due to previous error -For more information about this error, try `rustc --explain E0713`. +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr b/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr index 76a25fa661ece..74db695e7e560 100644 --- a/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr +++ b/src/test/ui/span/dropck_arr_cycle_checked.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `b2` dropped here while still borrowed | borrow later used here, when `b1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `b3` does not live long enough --> $DIR/dropck_arr_cycle_checked.rs:105:24 @@ -21,6 +23,8 @@ LL | } | | | `b3` dropped here while still borrowed | borrow later used here, when `b1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `b1` does not live long enough --> $DIR/dropck_arr_cycle_checked.rs:111:24 diff --git a/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr b/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr index 2884b1818baa9..baf3cef2ae83c 100644 --- a/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr +++ b/src/test/ui/span/dropck_direct_cycle_with_drop.nll.stderr @@ -23,8 +23,6 @@ LL | } | | | `d1` dropped here while still borrowed | borrow later used here, when `d1` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr index e6f43e0a71b56..f7ff4e5169fd4 100644 --- a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr +++ b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `c2` dropped here while still borrowed | borrow later used here, when `c1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c3` does not live long enough --> $DIR/dropck_vec_cycle_checked.rs:115:24 @@ -21,6 +23,8 @@ LL | } | | | `c3` dropped here while still borrowed | borrow later used here, when `c1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c1` does not live long enough --> $DIR/dropck_vec_cycle_checked.rs:121:24 diff --git a/src/test/ui/span/issue-15480.nll.stderr b/src/test/ui/span/issue-15480.nll.stderr index 8dcf486f83011..098e1ce62a82c 100644 --- a/src/test/ui/span/issue-15480.nll.stderr +++ b/src/test/ui/span/issue-15480.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/issue-15480.rs:15:10 | LL | &id(3) - | ^^^^^ temporary value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use LL | ]; - | - temporary value only lives until here + | - temporary value is freed at the end of this statement ... LL | for &&x in &v { | -- borrow later used here @@ -13,4 +13,4 @@ LL | for &&x in &v { error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/issue-29106.nll.stderr b/src/test/ui/span/issue-29106.nll.stderr index 2cf408d097b83..a1451866e677c 100644 --- a/src/test/ui/span/issue-29106.nll.stderr +++ b/src/test/ui/span/issue-29106.nll.stderr @@ -8,6 +8,8 @@ LL | } | | | `x` dropped here while still borrowed | borrow later used here, when `y` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `x` does not live long enough --> $DIR/issue-29106.rs:33:25 @@ -19,6 +21,8 @@ LL | } | | | `x` dropped here while still borrowed | borrow later used here, when `y` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error: aborting due to 2 previous errors diff --git a/src/test/ui/span/issue28498-reject-ex1.nll.stderr b/src/test/ui/span/issue28498-reject-ex1.nll.stderr index 1f72b78ebc76d..0f6f6e381d801 100644 --- a/src/test/ui/span/issue28498-reject-ex1.nll.stderr +++ b/src/test/ui/span/issue28498-reject-ex1.nll.stderr @@ -11,7 +11,6 @@ LL | } | borrow later used here, when `foo` is dropped | = note: consider using a `let` binding to create a longer lived value - = note: values in a scope are dropped in the opposite order they are defined error: aborting due to previous error diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr index 3788b5a328495..0e5fc749d9691 100644 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.nll.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/regions-close-over-borrowed-ref-in-obj.rs:22:27 | LL | let ss: &isize = &id(1); - | ^^^^^ temporary value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement LL | } | - borrow later used here, when `blah` is dropped | @@ -13,4 +13,4 @@ LL | } error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/slice-borrow.nll.stderr b/src/test/ui/span/slice-borrow.nll.stderr index 4a15d8ff45537..0aeb549d95e58 100644 --- a/src/test/ui/span/slice-borrow.nll.stderr +++ b/src/test/ui/span/slice-borrow.nll.stderr @@ -1,11 +1,11 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/slice-borrow.rs:16:28 | LL | let x: &[isize] = &vec![1, 2, 3, 4, 5]; - | ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement LL | y.use_ref(); | - borrow later used here | @@ -14,4 +14,4 @@ LL | y.use_ref(); error: aborting due to previous error -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr b/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr index ee51304800d32..292c007f51225 100644 --- a/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr +++ b/src/test/ui/span/vec-must-not-hide-type-from-dropck.nll.stderr @@ -9,6 +9,8 @@ LL | } | | | `c2` dropped here while still borrowed | borrow later used here, when `c1` is dropped + | + = note: values in a scope are dropped in the opposite order they are defined error[E0597]: `c1` does not live long enough --> $DIR/vec-must-not-hide-type-from-dropck.rs:129:24 diff --git a/src/test/ui/static/static-drop-scope.nll.stderr b/src/test/ui/static/static-drop-scope.nll.stderr new file mode 100644 index 0000000000000..36c645479dde8 --- /dev/null +++ b/src/test/ui/static/static-drop-scope.nll.stderr @@ -0,0 +1,60 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:19:60 + | +LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^ statics cannot evaluate destructors + +error[E0714]: temporary value dropped while borrowed + --> $DIR/static-drop-scope.rs:19:60 + | +LL | static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:23:59 + | +LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^ constants cannot evaluate destructors + +error[E0714]: temporary value dropped while borrowed + --> $DIR/static-drop-scope.rs:23:59 + | +LL | const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor); + | ^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary which is freed while still in use + | + = note: borrowed value must be valid for the static lifetime... + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:27:28 + | +LL | static EARLY_DROP_S: i32 = (WithDtor, 0).1; + | ^^^^^^^^^^^^^ statics cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:30:27 + | +LL | const EARLY_DROP_C: i32 = (WithDtor, 0).1; + | ^^^^^^^^^^^^^ constants cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:33:24 + | +LL | const fn const_drop(_: T) {} + | ^ constant functions cannot evaluate destructors + +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/static-drop-scope.rs:37:5 + | +LL | (x, ()).1 + | ^^^^^^^ constant functions cannot evaluate destructors + +error: aborting due to 8 previous errors + +Some errors occurred: E0493, E0714. +For more information about an error, try `rustc --explain E0493`. diff --git a/src/test/ui/static/static-reference-to-fn-2.nll.stderr b/src/test/ui/static/static-reference-to-fn-2.nll.stderr index 9ef94189e90ca..3740d9051be6a 100644 --- a/src/test/ui/static/static-reference-to-fn-2.nll.stderr +++ b/src/test/ui/static/static-reference-to-fn-2.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:28:22 | LL | self_.statefn = &id(state2 as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 27:1... --> $DIR/static-reference-to-fn-2.rs:27:1 @@ -16,13 +16,13 @@ LL | | return Some("state1"); LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:34:22 | LL | self_.statefn = &id(state3 as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 33:1... --> $DIR/static-reference-to-fn-2.rs:33:1 @@ -34,13 +34,13 @@ LL | | return Some("state2"); LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:40:22 | LL | self_.statefn = &id(finished as StateMachineFunc); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value only lives until here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement | | - | temporary value does not live long enough + | creates a temporary which is freed while still in use | note: borrowed value must be valid for the anonymous lifetime #2 defined on the function body at 39:1... --> $DIR/static-reference-to-fn-2.rs:39:1 @@ -52,17 +52,17 @@ LL | | return Some("state3"); LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/static-reference-to-fn-2.rs:51:19 | LL | statefn: &id(state1 as StateMachineFunc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use ... LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | = note: borrowed value must be valid for the static lifetime... error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/static/static-region-bound.nll.stderr b/src/test/ui/static/static-region-bound.nll.stderr new file mode 100644 index 0000000000000..3bb763eb1c779 --- /dev/null +++ b/src/test/ui/static/static-region-bound.nll.stderr @@ -0,0 +1,14 @@ +error[E0714]: temporary value dropped while borrowed + --> $DIR/static-region-bound.rs:20:14 + | +LL | let x = &id(3); //~ ERROR borrowed value does not live long enough + | ^^^^^ creates a temporary which is freed while still in use +LL | f(x); +LL | } + | - temporary value is freed at the end of this statement + | + = note: borrowed value must be valid for the static lifetime... + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0714`. diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr index 8cda1e60ba988..afd90237d16ae 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.nll.stderr @@ -11,8 +11,6 @@ LL | } | | | `factorial` dropped here while still borrowed | borrow later used here, when `factorial` is dropped - | - = note: values in a scope are dropped in the opposite order they are defined error[E0506]: cannot assign to `factorial` because it is borrowed --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:30:5 diff --git a/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr b/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr index 48a68bf5749f9..656a2eb698c05 100644 --- a/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr +++ b/src/test/ui/wf/wf-misc-methods-issue-28609.nll.stderr @@ -1,10 +1,10 @@ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:32:31 | LL | s.transmute_inherent(&mut 42) //~ ERROR does not live long enough - | ^^ temporary value does not live long enough + | ^^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 30:1... --> $DIR/wf-misc-methods-issue-28609.rs:30:1 @@ -55,13 +55,13 @@ LL | | &*s LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:63:15 | LL | s << &mut 3 //~ ERROR does not live long enough - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 61:1... --> $DIR/wf-misc-methods-issue-28609.rs:61:1 @@ -72,13 +72,13 @@ LL | | s << &mut 3 //~ ERROR does not live long enough LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:68:16 | LL | s.shl(&mut 3) //~ ERROR does not live long enough - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 66:1... --> $DIR/wf-misc-methods-issue-28609.rs:66:1 @@ -89,13 +89,13 @@ LL | | s.shl(&mut 3) //~ ERROR does not live long enough LL | | } | |_^ -error[E0597]: borrowed value does not live long enough +error[E0714]: temporary value dropped while borrowed --> $DIR/wf-misc-methods-issue-28609.rs:73:21 | LL | S2::shl(s, &mut 3) //~ ERROR does not live long enough - | ^ temporary value does not live long enough + | ^ creates a temporary which is freed while still in use LL | } - | - temporary value only lives until here + | - temporary value is freed at the end of this statement | note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 71:1... --> $DIR/wf-misc-methods-issue-28609.rs:71:1 @@ -108,4 +108,5 @@ LL | | } error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0597`. +Some errors occurred: E0597, E0714. +For more information about an error, try `rustc --explain E0597`.