diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index b55e7933cc1e9..5959f57128ae0 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1385,6 +1385,21 @@ pub(crate) struct ProjectOnNonPinProjectType { pub sugg_span: Option, } +#[derive(Diagnostic)] +#[diag("cannot directly pin an ADT that is not `#[pin_v2]`")] +pub(crate) struct DirectPinBorrowOfNonPinProjectType { + #[primary_span] + pub span: Span, + #[note("type defined here")] + pub def_span: Option, + #[suggestion( + "add `#[pin_v2]` here", + code = "#[pin_v2]\n", + applicability = "machine-applicable" + )] + pub sugg_span: Option, +} + #[derive(Diagnostic)] #[diag("falling back to `f32` as the trait bound `f32: From` is not satisfied")] pub(crate) struct FloatLiteralF32Fallback { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 084079561a6d3..890c0fdde085e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -499,6 +499,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_ptr(self.tcx, ty, mutbl) } hir::BorrowKind::Ref | hir::BorrowKind::Pin => { + if kind == hir::BorrowKind::Pin { + self.check_pin_borrow_of_adt_requires_pin_v2(ty, expr.span); + } + // Note: at this point, we cannot say what the best lifetime // is to use for resulting pointer. We want to use the // shortest lifetime possible so as to avoid spurious borrowck @@ -523,6 +527,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_pin_borrow_of_adt_requires_pin_v2(&self, ty: Ty<'tcx>, span: Span) { + let ty = self.structurally_resolve_type(span, ty); + if let Some(adt) = ty.ty_adt_def() + && !adt.is_pin_project() + { + let def_span = self.tcx.hir_span_if_local(adt.did()); + let sugg_span = def_span.map(|span| span.shrink_to_lo()); + self.dcx().emit_err(crate::errors::DirectPinBorrowOfNonPinProjectType { + span, + def_span, + sugg_span, + }); + } + } + /// Does this expression refer to a place that either: /// * Is based on a local or static. /// * Contains a dereference diff --git a/tests/ui/pin-ergonomics/borrow-pinned-projection.rs b/tests/ui/pin-ergonomics/borrow-pinned-projection.rs index 648d001830efa..228707234e189 100644 --- a/tests/ui/pin-ergonomics/borrow-pinned-projection.rs +++ b/tests/ui/pin-ergonomics/borrow-pinned-projection.rs @@ -5,6 +5,7 @@ // unrelated disjoint fields, but it must reject later mutable borrows or moves // of `pair.0` until reassignment. +#[pin_v2] struct Foo; fn mutable_borrow_of_pinned_projection() { diff --git a/tests/ui/pin-ergonomics/borrow-pinned-projection.stderr b/tests/ui/pin-ergonomics/borrow-pinned-projection.stderr index 93028eb651dfd..4b20519f84774 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:18:19 + --> $DIR/borrow-pinned-projection.rs:19: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:30:18 + --> $DIR/borrow-pinned-projection.rs:31:18 | LL | let _pin = &pin mut pair.0; | --------------- pin of `pair.0` occurs here diff --git a/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr index b309dace105f4..89bae9b4cf802 100644 --- a/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr +++ b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr @@ -1,5 +1,5 @@ error: cannot move out of `foo` because it is pinned - --> $DIR/borrow-unpin.rs:28:14 + --> $DIR/borrow-unpin.rs:30:14 | LL | foo_pin_mut(&pin mut foo); // ok | ------------ pin of `foo` occurs here @@ -7,7 +7,7 @@ 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:32:14 + --> $DIR/borrow-unpin.rs:34:14 | LL | let mut foo = Foo::default(); | ------- binding `foo` declared here @@ -19,7 +19,7 @@ LL | foo_pin_mut(x); // ok | - borrow later used here | note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/borrow-unpin.rs:13:1 + --> $DIR/borrow-unpin.rs:14:1 | LL | struct Foo(PhantomPinned); | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -28,7 +28,7 @@ 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:39:14 + --> $DIR/borrow-unpin.rs:41:14 | LL | foo_pin_mut(&pin mut foo); // ok | ------------ pin of `foo` occurs here @@ -36,7 +36,7 @@ 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:43:14 + --> $DIR/borrow-unpin.rs:45:14 | LL | let mut foo = Foo::default(); | ------- binding `foo` declared here @@ -48,7 +48,7 @@ LL | foo_pin_mut(x); // ok | - borrow later used here | note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/borrow-unpin.rs:13:1 + --> $DIR/borrow-unpin.rs:14:1 | LL | struct Foo(PhantomPinned); | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -57,7 +57,7 @@ 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:50:14 + --> $DIR/borrow-unpin.rs:52:14 | LL | foo_pin_ref(&pin const foo); // ok | -------------- pin of `foo` occurs here @@ -65,7 +65,7 @@ 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:54:14 + --> $DIR/borrow-unpin.rs:56:14 | LL | let foo = Foo::default(); | --- binding `foo` declared here @@ -77,7 +77,7 @@ LL | foo_pin_ref(x); | - borrow later used here | note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/borrow-unpin.rs:13:1 + --> $DIR/borrow-unpin.rs:14:1 | LL | struct Foo(PhantomPinned); | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -86,7 +86,7 @@ LL | let x = &pin const foo; // ok | --- you could clone this value error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrow-unpin.rs:65:13 + --> $DIR/borrow-unpin.rs:67:13 | LL | let x = &pin mut foo; // ok | ------------ mutable borrow occurs here @@ -96,7 +96,7 @@ LL | foo_pin_mut(x); | - mutable borrow later used here error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/borrow-unpin.rs:87:17 + --> $DIR/borrow-unpin.rs:89:17 | LL | let x = &pin mut foo; // ok | ------------ first mutable borrow occurs here @@ -106,7 +106,7 @@ LL | foo_pin_mut(x); | - first borrow later used here error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrow-unpin.rs:98:17 + --> $DIR/borrow-unpin.rs:100:17 | LL | let x = &pin const foo; // ok | -------------- immutable borrow occurs here @@ -116,7 +116,7 @@ LL | foo_pin_ref(x); | - immutable borrow later used here error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrow-unpin.rs:109:17 + --> $DIR/borrow-unpin.rs:111:17 | LL | let x = &pin mut foo; // ok | ------------ mutable borrow occurs here diff --git a/tests/ui/pin-ergonomics/borrow-unpin.rs b/tests/ui/pin-ergonomics/borrow-unpin.rs index caab5c0f49369..23c5b372c687d 100644 --- a/tests/ui/pin-ergonomics/borrow-unpin.rs +++ b/tests/ui/pin-ergonomics/borrow-unpin.rs @@ -9,10 +9,12 @@ use std::marker::PhantomPinned; use std::pin::Pin; #[cfg(pinned)] +#[pin_v2] #[derive(Default)] struct Foo(PhantomPinned); #[cfg(unpin)] +#[pin_v2] #[derive(Default)] struct Foo; diff --git a/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr index b338426d7b0b5..1ff363e004ffc 100644 --- a/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr +++ b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr @@ -1,5 +1,5 @@ error: cannot move out of `foo` because it is pinned - --> $DIR/borrow-unpin.rs:28:14 + --> $DIR/borrow-unpin.rs:30:14 | LL | foo_pin_mut(&pin mut foo); // ok | ------------ pin of `foo` occurs here @@ -7,7 +7,7 @@ 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:32:14 + --> $DIR/borrow-unpin.rs:34:14 | LL | let mut foo = Foo::default(); | ------- binding `foo` declared here @@ -19,7 +19,7 @@ LL | foo_pin_mut(x); // ok | - borrow later used here | note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/borrow-unpin.rs:17:1 + --> $DIR/borrow-unpin.rs:19:1 | LL | struct Foo; | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -28,7 +28,7 @@ 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:39:14 + --> $DIR/borrow-unpin.rs:41:14 | LL | foo_pin_mut(&pin mut foo); // ok | ------------ pin of `foo` occurs here @@ -36,7 +36,7 @@ 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:43:14 + --> $DIR/borrow-unpin.rs:45:14 | LL | let mut foo = Foo::default(); | ------- binding `foo` declared here @@ -48,7 +48,7 @@ LL | foo_pin_mut(x); // ok | - borrow later used here | note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/borrow-unpin.rs:17:1 + --> $DIR/borrow-unpin.rs:19:1 | LL | struct Foo; | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -57,7 +57,7 @@ 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:50:14 + --> $DIR/borrow-unpin.rs:52:14 | LL | foo_pin_ref(&pin const foo); // ok | -------------- pin of `foo` occurs here @@ -65,7 +65,7 @@ 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:54:14 + --> $DIR/borrow-unpin.rs:56:14 | LL | let foo = Foo::default(); | --- binding `foo` declared here @@ -77,7 +77,7 @@ LL | foo_pin_ref(x); | - borrow later used here | note: if `Foo` implemented `Clone`, you could clone the value - --> $DIR/borrow-unpin.rs:17:1 + --> $DIR/borrow-unpin.rs:19:1 | LL | struct Foo; | ^^^^^^^^^^ consider implementing `Clone` for this type @@ -86,7 +86,7 @@ LL | let x = &pin const foo; // ok | --- you could clone this value error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrow-unpin.rs:65:13 + --> $DIR/borrow-unpin.rs:67:13 | LL | let x = &pin mut foo; // ok | ------------ mutable borrow occurs here @@ -96,7 +96,7 @@ LL | foo_pin_mut(x); | - mutable borrow later used here error[E0499]: cannot borrow `foo` as mutable more than once at a time - --> $DIR/borrow-unpin.rs:87:17 + --> $DIR/borrow-unpin.rs:89:17 | LL | let x = &pin mut foo; // ok | ------------ first mutable borrow occurs here @@ -106,7 +106,7 @@ LL | foo_pin_mut(x); | - first borrow later used here error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable - --> $DIR/borrow-unpin.rs:98:17 + --> $DIR/borrow-unpin.rs:100:17 | LL | let x = &pin const foo; // ok | -------------- immutable borrow occurs here @@ -116,7 +116,7 @@ LL | foo_pin_ref(x); | - immutable borrow later used here error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable - --> $DIR/borrow-unpin.rs:109:17 + --> $DIR/borrow-unpin.rs:111:17 | LL | let x = &pin mut foo; // ok | ------------ mutable borrow occurs here diff --git a/tests/ui/pin-ergonomics/borrow.rs b/tests/ui/pin-ergonomics/borrow.rs index 214832340b2d3..be06d83c5270e 100644 --- a/tests/ui/pin-ergonomics/borrow.rs +++ b/tests/ui/pin-ergonomics/borrow.rs @@ -6,6 +6,7 @@ use std::pin::Pin; +#[pin_v2] struct Foo; fn foo_pin_mut(_: Pin<&mut Foo>) {} diff --git a/tests/ui/pin-ergonomics/borrow.stderr b/tests/ui/pin-ergonomics/borrow.stderr index 75376eff1d35a..9ff7e4e2a73d4 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:31:14 + --> $DIR/borrow.rs:32: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:32:14 + --> $DIR/borrow.rs:33: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:40:14 + --> $DIR/borrow.rs:41: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:41:14 + --> $DIR/borrow.rs:42: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 new file mode 100644 index 0000000000000..4d5ab1630ea9a --- /dev/null +++ b/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.rs @@ -0,0 +1,17 @@ +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] +//@ normalize-stderr: "\n\n\z" -> "\n" + +struct NotPinV2; + +fn direct_pin_mut(mut value: NotPinV2) { + let _ = &pin mut value; + //~^ ERROR cannot directly pin an ADT that is not `#[pin_v2]` +} + +fn direct_pin_const(value: NotPinV2) { + let _ = &pin const value; + //~^ ERROR cannot directly pin an ADT that is not `#[pin_v2]` +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.stderr b/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.stderr new file mode 100644 index 0000000000000..1e82a18f4a12c --- /dev/null +++ b/tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.stderr @@ -0,0 +1,35 @@ +error: cannot directly pin an ADT that is not `#[pin_v2]` + --> $DIR/direct-borrow-requires-pin-v2.rs:8:13 + | +LL | let _ = &pin mut value; + | ^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/direct-borrow-requires-pin-v2.rs:5:1 + | +LL | struct NotPinV2; + | ^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NotPinV2; + | + +error: cannot directly pin an ADT that is not `#[pin_v2]` + --> $DIR/direct-borrow-requires-pin-v2.rs:13:13 + | +LL | let _ = &pin const value; + | ^^^^^^^^^^^^^^^^ + | +note: type defined here + --> $DIR/direct-borrow-requires-pin-v2.rs:5:1 + | +LL | struct NotPinV2; + | ^^^^^^^^^^^^^^^ +help: add `#[pin_v2]` here + | +LL + #[pin_v2] +LL | struct NotPinV2; + | + +error: aborting due to 2 previous errors diff --git a/tests/ui/pin-ergonomics/user-type-projection.rs b/tests/ui/pin-ergonomics/user-type-projection.rs index f482586b6ebcc..4e8ef9887425e 100644 --- a/tests/ui/pin-ergonomics/user-type-projection.rs +++ b/tests/ui/pin-ergonomics/user-type-projection.rs @@ -9,6 +9,7 @@ // Historically, this could occur when the code handling those projections did not know // about `&pin` patterns, and incorrectly treated them as plain `&`/`&mut` patterns instead. +#[pin_v2] struct Data { x: u32 }