Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,7 +1386,7 @@ pub(crate) struct ProjectOnNonPinProjectType {
}

#[derive(Diagnostic)]
#[diag("cannot directly pin an ADT that is not `#[pin_v2]`")]
#[diag("cannot directly pin a type that is not structurally pinnable")]
pub(crate) struct DirectPinBorrowOfNonPinProjectType {
#[primary_span]
pub span: Span,
Expand Down
27 changes: 23 additions & 4 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,10 +529,8 @@ 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());
if self.direct_pin_borrow_requires_pin_v2(ty, span) {
let def_span = ty.ty_adt_def().and_then(|adt| 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,
Expand All @@ -542,6 +540,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

fn direct_pin_borrow_requires_pin_v2(&self, ty: Ty<'tcx>, span: Span) -> bool {
if ty.references_error() {
return false;
}

// Manual `Unpin` impls do not prove that pinned projections through a generic ADT
// are safe, so keep those cases aligned with pinned-pattern projection checks.
match ty.kind() {
ty::Adt(adt, args) if adt.is_pin_project() || adt.is_pin() => false,
ty::Adt(_, args) if args.types().next().is_some() => true,
ty::Adt(..) => !self.type_known_to_be_unpin(ty, span),
ty::Param(..) => !self.type_known_to_be_unpin(ty, span),
_ => ty.has_param() || ty.has_infer() || ty.has_aliases() || ty.has_placeholders(),
}
}

fn type_known_to_be_unpin(&self, ty: Ty<'tcx>, span: Span) -> bool {
let unpin_def_id = self.tcx.require_lang_item(LangItem::Unpin, span);
self.type_implements_trait(unpin_def_id, [ty], self.param_env).must_apply_modulo_regions()
}

/// Does this expression refer to a place that either:
/// * Is based on a local or static.
/// * Contains a dereference
Expand Down
78 changes: 72 additions & 6 deletions tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,83 @@
#![feature(pin_ergonomics)]
#![allow(incomplete_features)]
#![allow(dead_code, incomplete_features)]
//@ normalize-stderr: "\n\n\z" -> "\n"

struct NotPinV2;
use std::marker::PhantomPinned;
use std::pin::Pin;

fn direct_pin_mut(mut value: NotPinV2) {
struct UnpinAdt;

struct NotUnpin {
_pin: PhantomPinned,
}

#[pin_v2]
struct PinV2NotUnpin {
_pin: PhantomPinned,
}

struct GenericAdt<T> {
x: T,
}

impl<T> Unpin for GenericAdt<T> {}

struct DropGenericAdt<T>(T);

impl<T> Drop for DropGenericAdt<T> {
fn drop(&mut self) {}
}

fn direct_pin_mut_unpin() {
let _: Pin<&mut _> = &pin mut UnpinAdt;
}

fn direct_pin_const_unpin() {
let _: Pin<&_> = &pin const UnpinAdt;
}

fn direct_pin_mut_not_unpin() {
let _ = &pin mut NotUnpin { _pin: PhantomPinned };
//~^ ERROR cannot directly pin a type that is not structurally pinnable
}

fn direct_pin_const_not_unpin() {
let _ = &pin const NotUnpin { _pin: PhantomPinned };
//~^ ERROR cannot directly pin a type that is not structurally pinnable
}

fn direct_pin_mut_pin_v2_not_unpin() {
let _: Pin<&mut _> = &pin mut PinV2NotUnpin { _pin: PhantomPinned };
}

fn direct_pin_const_pin_v2_not_unpin() {
let _: Pin<&_> = &pin const PinV2NotUnpin { _pin: PhantomPinned };
}

fn direct_pin_mut_generic<T>(mut value: GenericAdt<T>) {
let _ = &pin mut value;
//~^ ERROR cannot directly pin an ADT that is not `#[pin_v2]`
//~^ ERROR cannot directly pin a type that is not structurally pinnable
}

fn direct_pin_const(value: NotPinV2) {
fn direct_pin_const_generic<T>(value: GenericAdt<T>) {
let _ = &pin const value;
//~^ ERROR cannot directly pin an ADT that is not `#[pin_v2]`
//~^ ERROR cannot directly pin a type that is not structurally pinnable
}

pub fn unsound_pin_borrow<T>(input: &pin mut GenericAdt<T>) -> &pin mut T {
&pin mut input.x
//~^ ERROR cannot directly pin a type that is not structurally pinnable
}

fn direct_pin_mut_manual_unpin_generic() {
let mut value = GenericAdt { x: NotUnpin { _pin: PhantomPinned } };
let _ = &pin mut value;
//~^ ERROR cannot directly pin a type that is not structurally pinnable
}

fn direct_pin_mut_drop_generic(mut input: DropGenericAdt<NotUnpin>) {
let _: &pin mut _ = &pin mut input;
//~^ ERROR cannot directly pin a type that is not structurally pinnable
}

fn main() {}
100 changes: 87 additions & 13 deletions tests/ui/pin-ergonomics/direct-borrow-requires-pin-v2.stderr
Original file line number Diff line number Diff line change
@@ -1,35 +1,109 @@
error: cannot directly pin an ADT that is not `#[pin_v2]`
--> $DIR/direct-borrow-requires-pin-v2.rs:8:13
error: cannot directly pin a type that is not structurally pinnable
--> $DIR/direct-borrow-requires-pin-v2.rs:40:13
|
LL | let _ = &pin mut NotUnpin { _pin: PhantomPinned };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: type defined here
--> $DIR/direct-borrow-requires-pin-v2.rs:10:1
|
LL | struct NotUnpin {
| ^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NotUnpin {
|

error: cannot directly pin a type that is not structurally pinnable
--> $DIR/direct-borrow-requires-pin-v2.rs:45:13
|
LL | let _ = &pin const NotUnpin { _pin: PhantomPinned };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: type defined here
--> $DIR/direct-borrow-requires-pin-v2.rs:10:1
|
LL | struct NotUnpin {
| ^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NotUnpin {
|

error: cannot directly pin a type that is not structurally pinnable
--> $DIR/direct-borrow-requires-pin-v2.rs:58:13
|
LL | let _ = &pin mut value;
| ^^^^^^^^^^^^^^
|
note: type defined here
--> $DIR/direct-borrow-requires-pin-v2.rs:5:1
--> $DIR/direct-borrow-requires-pin-v2.rs:19:1
|
LL | struct NotPinV2;
| ^^^^^^^^^^^^^^^
LL | struct GenericAdt<T> {
| ^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NotPinV2;
LL | struct GenericAdt<T> {
|

error: cannot directly pin an ADT that is not `#[pin_v2]`
--> $DIR/direct-borrow-requires-pin-v2.rs:13:13
error: cannot directly pin a type that is not structurally pinnable
--> $DIR/direct-borrow-requires-pin-v2.rs:63:13
|
LL | let _ = &pin const value;
| ^^^^^^^^^^^^^^^^
|
note: type defined here
--> $DIR/direct-borrow-requires-pin-v2.rs:5:1
--> $DIR/direct-borrow-requires-pin-v2.rs:19:1
|
LL | struct NotPinV2;
| ^^^^^^^^^^^^^^^
LL | struct GenericAdt<T> {
| ^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct GenericAdt<T> {
|

error: cannot directly pin a type that is not structurally pinnable
--> $DIR/direct-borrow-requires-pin-v2.rs:68:5
|
LL | &pin mut input.x
| ^^^^^^^^^^^^^^^^

error: cannot directly pin a type that is not structurally pinnable
--> $DIR/direct-borrow-requires-pin-v2.rs:74:13
|
LL | let _ = &pin mut value;
| ^^^^^^^^^^^^^^
|
note: type defined here
--> $DIR/direct-borrow-requires-pin-v2.rs:19:1
|
LL | struct GenericAdt<T> {
| ^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct GenericAdt<T> {
|

error: cannot directly pin a type that is not structurally pinnable
--> $DIR/direct-borrow-requires-pin-v2.rs:79:25
|
LL | let _: &pin mut _ = &pin mut input;
| ^^^^^^^^^^^^^^
|
note: type defined here
--> $DIR/direct-borrow-requires-pin-v2.rs:25:1
|
LL | struct DropGenericAdt<T>(T);
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[pin_v2]` here
|
LL + #[pin_v2]
LL | struct NotPinV2;
LL | struct DropGenericAdt<T>(T);
|

error: aborting due to 2 previous errors
error: aborting due to 7 previous errors
Loading