From f0b30c4336ec0441debe2c2120b8364b9f45babf Mon Sep 17 00:00:00 2001 From: Frank King Date: Mon, 24 Nov 2025 15:18:59 +0800 Subject: [PATCH] Forbid manual `Unpin` impls for structurally pinned types --- compiler/rustc_hir_analysis/messages.ftl | 4 ++++ compiler/rustc_hir_analysis/src/coherence/mod.rs | 14 ++++++++++++++ compiler/rustc_hir_analysis/src/errors.rs | 11 +++++++++++ tests/ui/pin-ergonomics/impl-unpin.rs | 11 +++++++++++ tests/ui/pin-ergonomics/impl-unpin.stderr | 14 ++++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 tests/ui/pin-ergonomics/impl-unpin.rs create mode 100644 tests/ui/pin-ergonomics/impl-unpin.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a313b91ef9bda..8fe02cad12595 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -222,6 +222,10 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` .note = parent implementation is in crate `{$cname}` +hir_analysis_impl_unpin_for_pin_projected_type = explicit impls for the `Unpin` trait are not permitted for structurally pinned types + .label = impl of `Unpin` not allowed + .help = `{$adt_name}` is structurally pinned because it is marked as `#[pin_v2]` + hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait .label = impl requires at least one non-auto trait .note = define and implement a new trait or type instead diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index bc3231cff9b47..0d2f0db6d8d16 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -90,6 +90,20 @@ fn enforce_trait_manually_implementable( return Err(err.emit()); } + // Disallow explicit impls of the `Unpin` trait for structurally pinned types + if tcx.features().pin_ergonomics() + && tcx.is_lang_item(trait_def_id, LangItem::Unpin) + && let Some(adt) = + tcx.impl_trait_ref(impl_def_id).instantiate_identity().self_ty().ty_adt_def() + && adt.is_pin_project() + { + return Err(tcx.dcx().emit_err(crate::errors::ImplUnpinForPinProjectedType { + span: impl_header_span, + adt_span: tcx.def_span(adt.did()), + adt_name: tcx.item_name(adt.did()), + })); + } + if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind { if !tcx.features().specialization() diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 209b0156de323..9ba446647ff3d 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1708,3 +1708,14 @@ pub(crate) struct AsyncDropWithoutSyncDrop { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_impl_unpin_for_pin_projected_type)] +pub(crate) struct ImplUnpinForPinProjectedType { + #[primary_span] + #[label] + pub span: Span, + #[help] + pub adt_span: Span, + pub adt_name: Symbol, +} diff --git a/tests/ui/pin-ergonomics/impl-unpin.rs b/tests/ui/pin-ergonomics/impl-unpin.rs new file mode 100644 index 0000000000000..0a4b20e6ff8ab --- /dev/null +++ b/tests/ui/pin-ergonomics/impl-unpin.rs @@ -0,0 +1,11 @@ +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +#[pin_v2] +struct Foo; +struct Bar; + +impl Unpin for Foo {} //~ ERROR explicit impls for the `Unpin` trait are not permitted for structurally pinned types +impl Unpin for Bar {} // ok + +fn main() {} diff --git a/tests/ui/pin-ergonomics/impl-unpin.stderr b/tests/ui/pin-ergonomics/impl-unpin.stderr new file mode 100644 index 0000000000000..d82c6dc11a581 --- /dev/null +++ b/tests/ui/pin-ergonomics/impl-unpin.stderr @@ -0,0 +1,14 @@ +error: explicit impls for the `Unpin` trait are not permitted for structurally pinned types + --> $DIR/impl-unpin.rs:8:1 + | +LL | impl Unpin for Foo {} + | ^^^^^^^^^^^^^^^^^^ impl of `Unpin` not allowed + | +help: `Foo` is structurally pinned because it is marked as `#[pin_v2]` + --> $DIR/impl-unpin.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ + +error: aborting due to 1 previous error +