diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index c1e402391c846..360410fe29e46 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -761,7 +761,10 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Pins<'_, 'tcx> { if let mir::Rvalue::Ref(_, mir::BorrowKind::Pinned(_, kind), place) = rhs && matches!(*kind, mir::PinBorrowKind::Persistent) { - self.gen_pins_on_place(state, *place); + let place_ty = place.ty(self.body, self.tcx).ty; + if !place_ty.is_unpin(self.tcx, self.body.typing_env(self.tcx)) { + self.gen_pins_on_place(state, *place); + } } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index efb24e31511fe..07a66c1ac04e6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1266,23 +1266,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { } } - fn pinned_borrows<'s>( - &self, - state: &'s BorrowckDomain, - ) -> Option<&'s MixedBitSet> { - // FIXME(pin_ergonomics): borrowck behaviors depend on a safe trait - // which should not contain any safety invariants. - // if place - // .ty(self.body, self.infcx.tcx) - // .ty - // .is_unpin(self.infcx.tcx, self.body.typing_env(self.infcx.tcx)) - // { - // None - // } else { - Some(&state.pinned_borrows) - // } - } - #[instrument(level = "debug", skip(self, state))] fn check_access_for_conflict( &mut self, @@ -1295,7 +1278,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let mut error_reported = false; let borrows_in_scope = self.borrows_in_scope(location, state); - let pinned_borrows = self.pinned_borrows(state); + let pinned_borrows = &state.pinned_borrows; each_borrow_involving_path( self, @@ -1304,8 +1287,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { (sd, place_span.0), self.borrow_set, |borrow_index| { - borrows_in_scope.contains(borrow_index) - || pinned_borrows.is_some_and(|p| p.contains(borrow_index)) + borrows_in_scope.contains(borrow_index) || pinned_borrows.contains(borrow_index) }, |this, borrow_index, borrow| match (rw, borrow.kind) { // Obviously an activation is compatible with its own @@ -1388,7 +1370,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { if !borrows_in_scope.contains(borrow_index) => { debug_assert!( - pinned_borrows.is_none_or(|p| p.contains(borrow_index)), + pinned_borrows.contains(borrow_index), "unexpected expired but non-pinned borrow {borrow_index:?}: {borrow:?}", ); match kind { diff --git a/tests/ui/pin-ergonomics/borrow-pinned-projection.rs b/tests/ui/pin-ergonomics/borrow-pinned-projection.rs index 228707234e189..d0c891f8a7772 100644 --- a/tests/ui/pin-ergonomics/borrow-pinned-projection.rs +++ b/tests/ui/pin-ergonomics/borrow-pinned-projection.rs @@ -6,10 +6,11 @@ // of `pair.0` until reassignment. #[pin_v2] -struct Foo; +#[derive(Default)] +struct Foo(std::marker::PhantomPinned); fn mutable_borrow_of_pinned_projection() { - let mut pair = (Foo, Foo); + let mut pair = (Foo::default(), Foo::default()); { let _pin = &pin mut pair.0; @@ -21,7 +22,7 @@ fn mutable_borrow_of_pinned_projection() { } fn move_of_pinned_projection() { - let mut pair = (Foo, Foo); + let mut pair = (Foo::default(), Foo::default()); { let _pin = &pin mut pair.0; @@ -32,4 +33,28 @@ fn move_of_pinned_projection() { //~^ ERROR cannot move out of `pair.0` because it is pinned } +#[pin_v2] +struct ContainsUnpinField { + field: String, + _pin: std::marker::PhantomPinned, +} + +fn pinned_parent_still_blocks_unpin_field_move(mut value: ContainsUnpinField) { + { + let _ = &pin mut value; + } + + let _moved = value.field; + //~^ ERROR cannot move out of `value.field` because it is pinned +} + +fn pinned_parent_still_blocks_unpin_field_mut_borrow(mut value: ContainsUnpinField) { + { + let _ = &pin mut value; + } + + let _ = &mut value.field; + //~^ ERROR cannot borrow `value.field` as mutable 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 index 4b20519f84774..416ad776c96d5 100644 --- a/tests/ui/pin-ergonomics/borrow-pinned-projection.stderr +++ b/tests/ui/pin-ergonomics/borrow-pinned-projection.stderr @@ -1,5 +1,5 @@ error: cannot borrow `pair.0` as mutable because it is pinned - --> $DIR/borrow-pinned-projection.rs:19:19 + --> $DIR/borrow-pinned-projection.rs:20:19 | LL | let _pin = &pin mut pair.0; | --------------- pin of `pair.0` occurs here @@ -8,7 +8,7 @@ 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:31:18 + --> $DIR/borrow-pinned-projection.rs:32:18 | LL | let _pin = &pin mut pair.0; | --------------- pin of `pair.0` occurs here @@ -16,5 +16,23 @@ LL | let _pin = &pin mut pair.0; LL | let _moved = pair.0; | ^^^^^^ move out of `pair.0` occurs here -error: aborting due to 2 previous errors +error: cannot move out of `value.field` because it is pinned + --> $DIR/borrow-pinned-projection.rs:47:18 + | +LL | let _ = &pin mut value; + | -------------- pin of `value` occurs here +... +LL | let _moved = value.field; + | ^^^^^^^^^^^ move out of `value.field` occurs here + +error: cannot borrow `value.field` as mutable because it is pinned + --> $DIR/borrow-pinned-projection.rs:56:13 + | +LL | let _ = &pin mut value; + | -------------- pin of `value` occurs here +... +LL | let _ = &mut value.field; + | ^^^^^^^^^^^^^^^^ borrow of `value.field` as mutable occurs here + +error: aborting due to 4 previous errors diff --git a/tests/ui/pin-ergonomics/borrow-unpin.rs b/tests/ui/pin-ergonomics/borrow-unpin.rs index 23c5b372c687d..ac66c4353e161 100644 --- a/tests/ui/pin-ergonomics/borrow-unpin.rs +++ b/tests/ui/pin-ergonomics/borrow-unpin.rs @@ -2,8 +2,8 @@ #![feature(pin_ergonomics)] #![allow(dead_code, incomplete_features)] -// This test ensures that the place cannot be mutably borrowed or moved after pinned -// no matter if `place` is `Unpin` or not. +// This test ensures `!Unpin` places cannot be mutably borrowed or moved after pinning. +// `Unpin` places still obey ordinary borrow rules, but expired `&pin` borrows do not pin. use std::marker::PhantomPinned; use std::pin::Pin; @@ -27,7 +27,7 @@ fn foo_move(_: Foo) {} fn immutable_pin_mut_then_move() { let mut foo = Foo::default(); foo_pin_mut(&pin mut foo); // ok - foo_move(foo); //~ ERROR cannot move out of `foo` because it is pinned + foo_move(foo); //[pinned]~ ERROR cannot move out of `foo` because it is pinned let mut foo = Foo::default(); let x = &pin mut foo; @@ -38,7 +38,7 @@ fn immutable_pin_mut_then_move() { fn pin_mut_then_move() { let mut foo = Foo::default(); foo_pin_mut(&pin mut foo); // ok - foo_move(foo); //~ ERROR cannot move out of `foo` because it is pinned + foo_move(foo); //[pinned]~ ERROR cannot move out of `foo` because it is pinned let mut foo = Foo::default(); let x = &pin mut foo; // ok @@ -49,7 +49,7 @@ fn pin_mut_then_move() { fn pin_ref_then_move() { let foo = Foo::default(); foo_pin_ref(&pin const foo); // ok - foo_move(foo); //~ ERROR cannot move out of `foo` because it is pinned + foo_move(foo); //[pinned]~ ERROR cannot move out of `foo` because it is pinned let foo = Foo::default(); let x = &pin const foo; // ok diff --git a/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr index 1ff363e004ffc..f8fb6dc75fc98 100644 --- a/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr +++ b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr @@ -1,11 +1,3 @@ -error: cannot move out of `foo` because it is pinned - --> $DIR/borrow-unpin.rs:30:14 - | -LL | foo_pin_mut(&pin mut foo); // ok - | ------------ pin of `foo` occurs here -LL | foo_move(foo); - | ^^^ move out of `foo` occurs here - error[E0505]: cannot move out of `foo` because it is borrowed --> $DIR/borrow-unpin.rs:34:14 | @@ -27,14 +19,6 @@ LL | struct Foo; LL | let x = &pin mut foo; | --- you could clone this value -error: cannot move out of `foo` because it is pinned - --> $DIR/borrow-unpin.rs:41:14 - | -LL | foo_pin_mut(&pin mut foo); // ok - | ------------ pin of `foo` occurs here -LL | foo_move(foo); - | ^^^ move out of `foo` occurs here - error[E0505]: cannot move out of `foo` because it is borrowed --> $DIR/borrow-unpin.rs:45:14 | @@ -56,14 +40,6 @@ LL | struct Foo; LL | let x = &pin mut foo; // ok | --- you could clone this value -error: cannot move out of `foo` because it is pinned - --> $DIR/borrow-unpin.rs:52:14 - | -LL | foo_pin_ref(&pin const foo); // ok - | -------------- pin of `foo` occurs here -LL | foo_move(foo); - | ^^^ move out of `foo` occurs here - error[E0505]: cannot move out of `foo` because it is borrowed --> $DIR/borrow-unpin.rs:56:14 | @@ -125,7 +101,7 @@ LL | foo_pin_ref(&pin const foo); LL | foo_pin_mut(x); | - mutable borrow later used here -error: aborting due to 10 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0499, E0502, E0505. For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/pin-ergonomics/borrow.rs b/tests/ui/pin-ergonomics/borrow.rs index be06d83c5270e..ba4a912d8c5cf 100644 --- a/tests/ui/pin-ergonomics/borrow.rs +++ b/tests/ui/pin-ergonomics/borrow.rs @@ -4,22 +4,24 @@ // Makes sure we can handle `&pin mut place` and `&pin const place` as sugar for // `std::pin::pin!(place)` and `Pin::new(&place)`. +use std::marker::PhantomPinned; use std::pin::Pin; #[pin_v2] -struct Foo; +#[derive(Default)] +struct Foo(PhantomPinned); fn foo_pin_mut(_: Pin<&mut Foo>) {} fn foo_pin_ref(_: Pin<&Foo>) {} fn bar() { - let mut x: Pin<&mut _> = &pin mut Foo; + let mut x: Pin<&mut _> = &pin mut Foo::default(); foo_pin_mut(x.as_mut()); foo_pin_mut(x.as_mut()); foo_pin_ref(x); - let x: Pin<&_> = &pin const Foo; + let x: Pin<&_> = &pin const Foo::default(); foo_pin_ref(x); foo_pin_ref(x); @@ -32,7 +34,7 @@ fn baz(mut x: Foo, mut y: Foo) { let _x = &mut x; //~ ERROR cannot borrow `x` as mutable because it is pinned let _x = x; //~ ERROR cannot move out of `x` because it is pinned - x = Foo; + x = Foo::default(); let _x = &mut x; // ok { diff --git a/tests/ui/pin-ergonomics/borrow.stderr b/tests/ui/pin-ergonomics/borrow.stderr index 9ff7e4e2a73d4..3161df5fd6c60 100644 --- a/tests/ui/pin-ergonomics/borrow.stderr +++ b/tests/ui/pin-ergonomics/borrow.stderr @@ -1,5 +1,5 @@ error: cannot borrow `x` as mutable because it is pinned - --> $DIR/borrow.rs:32:14 + --> $DIR/borrow.rs:34:14 | LL | let _x = &pin mut x; | ---------- pin of `x` occurs here @@ -8,7 +8,7 @@ LL | let _x = &mut x; | ^^^^^^ borrow of `x` as mutable occurs here error: cannot move out of `x` because it is pinned - --> $DIR/borrow.rs:33:14 + --> $DIR/borrow.rs:35:14 | LL | let _x = &pin mut x; | ---------- pin of `x` occurs here @@ -17,7 +17,7 @@ LL | let _x = x; | ^ move out of `x` occurs here error: cannot borrow `y` as mutable because it is pinned - --> $DIR/borrow.rs:41:14 + --> $DIR/borrow.rs:43:14 | LL | let _y = &pin const y; | ------------ pin of `y` occurs here @@ -26,7 +26,7 @@ LL | let _y = &mut y; | ^^^^^^ borrow of `y` as mutable occurs here error: cannot move out of `y` because it is pinned - --> $DIR/borrow.rs:42:14 + --> $DIR/borrow.rs:44:14 | LL | let _y = &pin const y; | ------------ pin of `y` occurs here diff --git a/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.rs b/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.rs index 53ebd236c357c..cddaeca50387c 100644 --- a/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.rs +++ b/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.rs @@ -80,4 +80,28 @@ fn direct_pin_mut_drop_generic(mut input: DropGenericAdt) { //~^ ERROR cannot directly pin a type that is not structurally pinnable } +fn direct_pin_mut_unpin_then_mut_borrow_and_move() { + let mut value = UnpinAdt; + { + let _ = &pin mut value; + } + let _ = &mut value; + let _ = value; +} + +fn direct_pin_const_unpin_then_move() { + let value = UnpinAdt; + { + let _ = &pin const value; + } + let _ = value; +} + +fn direct_pin_mut_generic_unpin_bound_then_move(mut value: T) { + { + let _ = &pin mut value; + } + let _ = value; +} + fn main() {}