diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs index 0452e47c68c0d..fb7e54afcb19e 100644 --- a/compiler/rustc_borrowck/src/borrow_set.rs +++ b/compiler/rustc_borrowck/src/borrow_set.rs @@ -124,8 +124,8 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> { mir::BorrowKind::Mut { kind: mir::MutBorrowKind::Default | mir::MutBorrowKind::TwoPhaseBorrow, } => "mut ", - mir::BorrowKind::Pinned(mir::Mutability::Not) => "pin const ", - mir::BorrowKind::Pinned(mir::Mutability::Mut) => "pin mut ", + mir::BorrowKind::Pinned(mir::Mutability::Not, _) => "pin const ", + mir::BorrowKind::Pinned(mir::Mutability::Mut, _) => "pin mut ", }; write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place) } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index a4c97097ed690..c1e402391c846 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -757,9 +757,10 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Pins<'_, 'tcx> { mir::StatementKind::Assign(box (lhs, rhs)) => { self.kill_pins_on_place(state, *lhs); - // Check if this is a pinned borrow - if let mir::Rvalue::Ref(_, mir::BorrowKind::Pinned(_), place) = rhs { - // Generate the pin + // Only user-written `&pin` borrows create long-lived pin facts. + if let mir::Rvalue::Ref(_, mir::BorrowKind::Pinned(_, kind), place) = rhs + && matches!(*kind, mir::PinBorrowKind::Persistent) + { self.gen_pins_on_place(state, *place); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 82500684d8420..bab4ab158fb9d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1773,9 +1773,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ( BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) - | BorrowKind::Pinned(mir::Mutability::Not), + | BorrowKind::Pinned(mir::Mutability::Not, _), BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } - | BorrowKind::Pinned(mir::Mutability::Mut), + | BorrowKind::Pinned(mir::Mutability::Mut, _), ) => { first_borrow_desc = "mutable "; let mut err = self.cannot_reborrow_already_borrowed( @@ -1800,10 +1800,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } ( BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } - | BorrowKind::Pinned(mir::Mutability::Mut), + | BorrowKind::Pinned(mir::Mutability::Mut, _), BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) - | BorrowKind::Pinned(mir::Mutability::Not), + | BorrowKind::Pinned(mir::Mutability::Not, _), ) => { first_borrow_desc = "immutable "; let mut err = self.cannot_reborrow_already_borrowed( @@ -1835,9 +1835,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ( BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } - | BorrowKind::Pinned(mir::Mutability::Mut), + | BorrowKind::Pinned(mir::Mutability::Mut, _), BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } - | BorrowKind::Pinned(mir::Mutability::Mut), + | BorrowKind::Pinned(mir::Mutability::Mut, _), ) => { first_borrow_desc = "first "; let mut err = self.cannot_mutably_borrow_multiply( @@ -1877,7 +1877,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } ( - BorrowKind::Mut { .. } | BorrowKind::Pinned(mir::Mutability::Mut), + BorrowKind::Mut { .. } | BorrowKind::Pinned(mir::Mutability::Mut, _), BorrowKind::Fake(FakeBorrowKind::Shallow), ) => { if let Some(immutable_section_description) = @@ -1944,7 +1944,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ( BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) - | BorrowKind::Pinned(mir::Mutability::Not), + | BorrowKind::Pinned(mir::Mutability::Not, _), BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, ) => { first_borrow_desc = "first "; @@ -1962,7 +1962,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } ( - BorrowKind::Mut { .. } | BorrowKind::Pinned(mir::Mutability::Mut), + BorrowKind::Mut { .. } | BorrowKind::Pinned(mir::Mutability::Mut, _), BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture }, ) => { first_borrow_desc = "first "; @@ -1982,15 +1982,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ( BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) - | BorrowKind::Pinned(mir::Mutability::Not), - BorrowKind::Shared | BorrowKind::Fake(_) | BorrowKind::Pinned(mir::Mutability::Not), + | BorrowKind::Pinned(mir::Mutability::Not, _), + BorrowKind::Shared + | BorrowKind::Fake(_) + | BorrowKind::Pinned(mir::Mutability::Not, _), ) | ( BorrowKind::Fake(FakeBorrowKind::Shallow), BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_) - | BorrowKind::Pinned(_), + | BorrowKind::Pinned(..), ) => { unreachable!() } diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index fc4afd0bb4b50..bb1eb9ee4a5c5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -869,11 +869,13 @@ impl UseSpans<'_> { | rustc_middle::mir::BorrowKind::Fake(_) | rustc_middle::mir::BorrowKind::Pinned( rustc_middle::mir::Mutability::Not, + _, ) => CaptureVarKind::Immut { kind_span: capture_kind_span }, rustc_middle::mir::BorrowKind::Mut { .. } | rustc_middle::mir::BorrowKind::Pinned( rustc_middle::mir::Mutability::Mut, + _, ) => CaptureVarKind::Mut { kind_span: capture_kind_span }, }, None => CaptureVarKind::Move { kind_span: capture_kind_span }, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 9cbf047126793..efb24e31511fe 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1328,16 +1328,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ( Read(_), - BorrowKind::Shared | BorrowKind::Fake(_) | BorrowKind::Pinned(Mutability::Not), + BorrowKind::Shared + | BorrowKind::Fake(_) + | BorrowKind::Pinned(Mutability::Not, _), ) | ( Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))), - BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut), + BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut, _), ) => ControlFlow::Continue(()), ( Reservation(_), - BorrowKind::Fake(_) | BorrowKind::Shared | BorrowKind::Pinned(Mutability::Not), + BorrowKind::Fake(_) + | BorrowKind::Shared + | BorrowKind::Pinned(Mutability::Not, _), ) => { // This used to be a future compatibility warning (to be // disallowed on NLL). See rust-lang/rust#56254 @@ -1350,13 +1354,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } // Ignore the expired borrow (pinnedness never conflicts with a read) - (Read(_), BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut)) + (Read(_), BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut, _)) if !borrows_in_scope.contains(borrow_index) => { ControlFlow::Continue(()) } - (Read(kind), BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut)) => { + (Read(kind), BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut, _)) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators(), borrow, location) { assert!(borrow.kind.is_two_phase_borrow()); @@ -1393,7 +1397,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ControlFlow::Continue(()) } // Mutable (pinned) borrow doesn't conflict with an expired borrow - WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Mut)) => { + WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Mut, _)) => { ControlFlow::Continue(()) } // Mutable (but non-pinned) borrow conflicts with an earlier pinned borrow @@ -1550,12 +1554,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { BorrowKind::Fake(FakeBorrowKind::Shallow) => { (Shallow(Some(ArtificialField::FakeBorrow)), Read(ReadKind::Borrow(bk))) } - BorrowKind::Pinned(Mutability::Not) => { - (Shallow(None), Read(ReadKind::Borrow(BorrowKind::Pinned(Mutability::Not)))) - } - BorrowKind::Pinned(Mutability::Mut) => ( + BorrowKind::Pinned(Mutability::Not, pin_kind) => ( + Shallow(None), + Read(ReadKind::Borrow(BorrowKind::Pinned(Mutability::Not, pin_kind))), + ), + BorrowKind::Pinned(Mutability::Mut, pin_kind) => ( Shallow(None), - Write(WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Mut))), + Write(WriteKind::MutableBorrow(BorrowKind::Pinned( + Mutability::Mut, + pin_kind, + ))), ), BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => { (Deep, Read(ReadKind::Borrow(bk))) @@ -1922,9 +1930,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Fake(_) | BorrowKind::Pinned(Mutability::Not) => - false, - BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut) => true, + BorrowKind::Shared + | BorrowKind::Fake(_) + | BorrowKind::Pinned(Mutability::Not, _) => false, + BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut, _) => true, }); self.access_place( @@ -2501,7 +2510,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { | WriteKind::StorageDeadOrDrop | WriteKind::MutableBorrow(BorrowKind::Shared) | WriteKind::MutableBorrow(BorrowKind::Fake(_)) - | WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Mut)), + | WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Mut, _)), ) => { if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err() && !self.has_buffered_diags() @@ -2529,18 +2538,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Fake(_) - | BorrowKind::Pinned(Mutability::Not), + | BorrowKind::Pinned(Mutability::Not, _), ) | ReadKind::Copy, ) => { // Access authorized return false; } - Reservation(WriteKind::MutableBorrow(BorrowKind::Pinned(_))) => { + Reservation(WriteKind::MutableBorrow(BorrowKind::Pinned(..))) => { span_bug!(span, "invalid reservation with a pinned borrow kind: {:?}", kind); } - Write(WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Not))) - | Read(ReadKind::Borrow(BorrowKind::Pinned(Mutability::Mut))) => { + Write(WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Not, _))) + | Read(ReadKind::Borrow(BorrowKind::Pinned(Mutability::Mut, _))) => { span_bug!( span, "invalid read with a pinned mutable borrow kind or write with an immutable pinned borrow kind: {:?}", diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 02940f00a1b2f..ecf28552b444e 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -262,12 +262,17 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { BorrowKind::Shared | BorrowKind::Fake(FakeBorrowKind::Deep) => { (Deep, Read(ReadKind::Borrow(bk))) } - BorrowKind::Pinned(Mutability::Not) => { - (Deep, Read(ReadKind::Borrow(BorrowKind::Pinned(Mutability::Not)))) - } - BorrowKind::Pinned(Mutability::Mut) => { - (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Pinned(Mutability::Mut)))) - } + BorrowKind::Pinned(Mutability::Not, pin_kind) => ( + Deep, + Read(ReadKind::Borrow(BorrowKind::Pinned(Mutability::Not, pin_kind))), + ), + BorrowKind::Pinned(Mutability::Mut, pin_kind) => ( + Deep, + Write(WriteKind::MutableBorrow(BorrowKind::Pinned( + Mutability::Mut, + pin_kind, + ))), + ), BorrowKind::Mut { .. } => { let wk = WriteKind::MutableBorrow(bk); if bk.is_two_phase_borrow() { @@ -383,7 +388,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { Read(_), BorrowKind::Fake(_) | BorrowKind::Shared - | BorrowKind::Pinned(Mutability::Not), + | BorrowKind::Pinned(Mutability::Not, _), ) | ( Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))), @@ -392,7 +397,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { // Reads don't invalidate shared or shallow borrows } - (Read(_), BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut)) => { + (Read(_), BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut, _)) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(this.dominators, borrow, location) { // If the borrow isn't active yet, reads don't invalidate it @@ -433,9 +438,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { // only mutable borrows should be 2-phase assert!(match borrow.kind { - BorrowKind::Shared | BorrowKind::Fake(_) | BorrowKind::Pinned(Mutability::Not) => - false, - BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut) => true, + BorrowKind::Shared + | BorrowKind::Fake(_) + | BorrowKind::Pinned(Mutability::Not, _) => false, + BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut, _) => true, }); self.access_place( diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 76a6e6ba0f0bd..10c07d2f1d5e6 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -582,7 +582,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } } - Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut), place) + Rvalue::Ref( + _, + BorrowKind::Mut { .. } | BorrowKind::Pinned(Mutability::Mut, _), + place, + ) | Rvalue::RawPtr(RawPtrKind::Mut, place) => { // Inside mutable statics, we allow arbitrary mutable references. // We've allowed `static mut FOO = &mut [elements];` for a long time (the exact @@ -598,7 +602,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Ref( _, - BorrowKind::Shared | BorrowKind::Fake(_) | BorrowKind::Pinned(Mutability::Not), + BorrowKind::Shared | BorrowKind::Fake(_) | BorrowKind::Pinned(Mutability::Not, _), place, ) | Rvalue::RawPtr(RawPtrKind::Const, place) => { diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 6d0938ed9efda..63022a82eeadd 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -103,10 +103,10 @@ where fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool { match kind { - mir::BorrowKind::Mut { .. } | mir::BorrowKind::Pinned(mir::Mutability::Mut) => true, + mir::BorrowKind::Mut { .. } | mir::BorrowKind::Pinned(mir::Mutability::Mut, _) => true, mir::BorrowKind::Shared | mir::BorrowKind::Fake(_) - | mir::BorrowKind::Pinned(mir::Mutability::Not) => { + | mir::BorrowKind::Pinned(mir::Mutability::Not, _) => { self.shared_borrow_allows_mutation(place) } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 1f04cc73d1342..03b7e32103e4f 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1117,8 +1117,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { BorrowKind::Fake(FakeBorrowKind::Deep) => "fake ", BorrowKind::Fake(FakeBorrowKind::Shallow) => "fake shallow ", BorrowKind::Mut { .. } => "mut ", - BorrowKind::Pinned(Mutability::Not) => "pin ", - BorrowKind::Pinned(Mutability::Mut) => "pin mut ", + BorrowKind::Pinned(Mutability::Not, _) => "pin ", + BorrowKind::Pinned(Mutability::Mut, _) => "pin mut ", }; // When printing regions, add trailing space if necessary. diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 9b549995f44ac..a4351d000bc58 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -838,7 +838,7 @@ impl BorrowKind { match *self { BorrowKind::Shared | BorrowKind::Fake(_) => Mutability::Not, BorrowKind::Mut { .. } => Mutability::Mut, - BorrowKind::Pinned(mutability) => mutability, + BorrowKind::Pinned(mutability, _) => mutability, } } @@ -849,7 +849,7 @@ impl BorrowKind { BorrowKind::Shared | BorrowKind::Fake(_) | BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::ClosureCapture } - | BorrowKind::Pinned(_) => false, + | BorrowKind::Pinned(..) => false, BorrowKind::Mut { kind: MutBorrowKind::TwoPhaseBorrow } => true, } } @@ -862,7 +862,7 @@ impl BorrowKind { // We have no type corresponding to a shallow borrow, so use // `&` as an approximation. BorrowKind::Fake(_) => hir::Mutability::Not, - BorrowKind::Pinned(mutability) => mutability, + BorrowKind::Pinned(mutability, _) => mutability, } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 87bd025cb4822..c30dc64e22fe5 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -179,8 +179,22 @@ pub enum BorrowKind { /// Data is mutable and not aliasable. Mut { kind: MutBorrowKind }, - /// Data is pinned and cannot be moved or mutably borrowed until dropped or reassigned. - Pinned(Mutability), + /// Data is pinned. + Pinned(Mutability, PinBorrowKind), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Hash, HashStable)] +pub enum PinBorrowKind { + /// A user-written `&pin` borrow. + /// + /// The borrowed place stays pinned after this borrow ends, until reassignment. + Persistent, + /// A compiler-generated pinned borrow used for adjustments or coercions. + /// + /// This remains a normal borrow while live, but does not create a persistent + /// pin fact after it ends. + Transient, } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 1ff413123e1f0..52288e4e13fcb 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -726,8 +726,8 @@ macro_rules! make_mir_visitor { ), BorrowKind::Mut { .. } => PlaceContext::MutatingUse(MutatingUseContext::Borrow), - BorrowKind::Pinned(Mutability::Not) => PlaceContext::NonMutatingUse(NonMutatingUseContext::PinnedBorrow), - BorrowKind::Pinned(Mutability::Mut) => PlaceContext::MutatingUse(MutatingUseContext::PinnedBorrow), + BorrowKind::Pinned(Mutability::Not, _) => PlaceContext::NonMutatingUse(NonMutatingUseContext::PinnedBorrow), + BorrowKind::Pinned(Mutability::Mut, _) => PlaceContext::MutatingUse(MutatingUseContext::PinnedBorrow), }; self.visit_place(path, ctx, location); } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 8ddef167b98e5..a6541d7a89afb 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -678,17 +678,17 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { match borrow_kind { BorrowKind::Fake(_) | BorrowKind::Shared - | BorrowKind::Pinned(hir::Mutability::Not) + | BorrowKind::Pinned(hir::Mutability::Not, _) if !self.thir[arg].ty.is_freeze(self.tcx, self.typing_env) => { self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField) } - BorrowKind::Mut { .. } | BorrowKind::Pinned(hir::Mutability::Mut) => { + BorrowKind::Mut { .. } | BorrowKind::Pinned(hir::Mutability::Mut, _) => { self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField) } BorrowKind::Fake(_) | BorrowKind::Shared - | BorrowKind::Pinned(hir::Mutability::Not) => {} + | BorrowKind::Pinned(hir::Mutability::Not, _) => {} } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 22f06ad9e844b..0a419d8ab2ba2 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -10,7 +10,7 @@ use rustc_middle::hir::place::{ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind, }; use rustc_middle::middle::region; -use rustc_middle::mir::{self, AssignOp, BinOp, BorrowKind, UnOp}; +use rustc_middle::mir::{self, AssignOp, BinOp, BorrowKind, PinBorrowKind, UnOp}; use rustc_middle::thir::*; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, DerefAdjustKind, PointerCoercion, @@ -191,8 +191,8 @@ impl<'tcx> ThirBuildCx<'tcx> { ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) } } Adjust::Borrow(AutoBorrow::Pin(mutbl)) => { - // expr = &pin (mut|const|) arget - let borrow_kind = BorrowKind::Pinned(mutbl); + // Build the transient `&pin` borrow needed by this adjustment. + let borrow_kind = BorrowKind::Pinned(mutbl, PinBorrowKind::Transient); let new_pin_target = Ty::new_ref(self.tcx, self.tcx.lifetimes.re_erased, expr.ty, mutbl); let arg = self.thir.exprs.push(expr); @@ -453,7 +453,10 @@ impl<'tcx> ThirBuildCx<'tcx> { temp_scope_id: expr.hir_id.local_id, ty, span: expr.span, - kind: ExprKind::Borrow { borrow_kind: BorrowKind::Pinned(mutability), arg }, + kind: ExprKind::Borrow { + borrow_kind: BorrowKind::Pinned(mutability, PinBorrowKind::Persistent), + arg, + }, }); ExprKind::Adt(Box::new(AdtExpr { adt_def, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index b319d8db34fbe..aca586eb72f78 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -80,7 +80,7 @@ where Rvalue::RawPtr(_, borrowed_place) | Rvalue::Ref( _, - BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Pinned(_), + BorrowKind::Mut { .. } | BorrowKind::Shared | BorrowKind::Pinned(..), borrowed_place, ) => { if !borrowed_place.is_indirect() { diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 7eacea4224ba0..331870b387139 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -399,7 +399,7 @@ impl<'tcx> Validator<'_, 'tcx> { return Err(Unpromotable); } - BorrowKind::Shared | BorrowKind::Pinned(Mutability::Not) => { + BorrowKind::Shared | BorrowKind::Pinned(Mutability::Not, _) => { let has_mut_interior = self.qualif_local::(place.local); if has_mut_interior { return Err(Unpromotable); @@ -409,7 +409,7 @@ impl<'tcx> Validator<'_, 'tcx> { // FIXME: consider changing this to only promote &mut [] for default borrows, // also forbidding two phase borrows BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } - | BorrowKind::Pinned(Mutability::Mut) => { + | BorrowKind::Pinned(Mutability::Mut, _) => { let ty = place.ty(self.body, self.tcx).ty; // In theory, any zero-sized value could be borrowed diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 3cb6a8dedaaed..774728d3bb6da 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -281,8 +281,8 @@ impl<'tcx> Stable<'tcx> for mir::BorrowKind { Shared => crate::mir::BorrowKind::Shared, Fake(kind) => crate::mir::BorrowKind::Fake(kind.stable(tables, cx)), Mut { kind } => crate::mir::BorrowKind::Mut { kind: kind.stable(tables, cx) }, - Pinned(mir::Mutability::Not) => crate::mir::BorrowKind::Shared, - Pinned(mir::Mutability::Mut) => { + Pinned(mir::Mutability::Not, _) => crate::mir::BorrowKind::Shared, + Pinned(mir::Mutability::Mut, _) => { crate::mir::BorrowKind::Mut { kind: crate::mir::MutBorrowKind::Default } } } diff --git a/tests/ui/pin-ergonomics/borrow-pinned-projection.rs b/tests/ui/pin-ergonomics/borrow-pinned-projection.rs new file mode 100644 index 0000000000000..648d001830efa --- /dev/null +++ b/tests/ui/pin-ergonomics/borrow-pinned-projection.rs @@ -0,0 +1,34 @@ +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +// This protects pinning projected places. Pinning `pair.0` must not pin +// unrelated disjoint fields, but it must reject later mutable borrows or moves +// of `pair.0` until reassignment. + +struct Foo; + +fn mutable_borrow_of_pinned_projection() { + let mut pair = (Foo, Foo); + + { + let _pin = &pin mut pair.0; + } + + let _other = &mut pair.1; + let _borrow = &mut pair.0; + //~^ ERROR cannot borrow `pair.0` as mutable because it is pinned +} + +fn move_of_pinned_projection() { + let mut pair = (Foo, Foo); + + { + let _pin = &pin mut pair.0; + } + + let _other = &mut pair.1; + let _moved = pair.0; + //~^ ERROR cannot move out of `pair.0` because it is pinned +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/borrow-pinned-projection.stderr b/tests/ui/pin-ergonomics/borrow-pinned-projection.stderr new file mode 100644 index 0000000000000..93028eb651dfd --- /dev/null +++ b/tests/ui/pin-ergonomics/borrow-pinned-projection.stderr @@ -0,0 +1,20 @@ +error: cannot borrow `pair.0` as mutable because it is pinned + --> $DIR/borrow-pinned-projection.rs:18:19 + | +LL | let _pin = &pin mut pair.0; + | --------------- pin of `pair.0` occurs here +... +LL | let _borrow = &mut pair.0; + | ^^^^^^^^^^^ borrow of `pair.0` as mutable occurs here + +error: cannot move out of `pair.0` because it is pinned + --> $DIR/borrow-pinned-projection.rs:30:18 + | +LL | let _pin = &pin mut pair.0; + | --------------- pin of `pair.0` occurs here +... +LL | let _moved = pair.0; + | ^^^^^^ move out of `pair.0` occurs here + +error: aborting due to 2 previous errors + diff --git a/tests/ui/pin-ergonomics/pin-coercion-get-mut-then-as-mut.rs b/tests/ui/pin-ergonomics/pin-coercion-get-mut-then-as-mut.rs new file mode 100644 index 0000000000000..2ea4cf871e8ae --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-get-mut-then-as-mut.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ edition:2024 + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +// This protects calling `Pin<&mut T>::as_mut()` after using `get_mut()` for +// `T: Unpin`; the `get_mut()` path must not make the later `as_mut()` borrow +// fail as pinned. + +fn pin_mut_to_ref(value: &pin mut T) -> &T { + value +} + +fn regression(value: &mut T) { + let mut value: &pin mut T = value; + let _: &mut T = value.get_mut(); + let _: &T = pin_mut_to_ref(value.as_mut()); +} + +fn main() { + let mut value = (); + regression(&mut value); +} diff --git a/tests/ui/pin-ergonomics/pin-coercion-unpin-roundtrip.rs b/tests/ui/pin-ergonomics/pin-coercion-unpin-roundtrip.rs new file mode 100644 index 0000000000000..6038787d5ef2f --- /dev/null +++ b/tests/ui/pin-ergonomics/pin-coercion-unpin-roundtrip.rs @@ -0,0 +1,29 @@ +//@ check-pass +//@ edition:2024 + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +// This protects the `T: Unpin` round trip from `&mut T` to `&pin mut T` and +// back to `&mut T`, which must not leave the reference falsely treated as pinned. + +fn to_pin_mut(value: &mut T) -> &pin mut T { + value +} + +fn to_mut(value: &pin mut T) -> &mut T { + value +} + +fn touch_mut(_: &mut T) {} + +fn regression(value: &mut T) { + let value: &pin mut T = to_pin_mut(value); + let value: &mut T = to_mut(value); + touch_mut(value); +} + +fn main() { + let mut value = (); + regression(&mut value); +}