Reject #[repr(packed)] on #[pin_v2] types#157542
Open
Dnreikronos wants to merge 2 commits into
Open
Conversation
A `#[repr(packed)]` type can store an over-aligned field below its alignment. Drop glue for such a type moves the field to a properly aligned location before dropping it, which would move a structurally pinned field out from under a `Pin<&mut _>` that was handed out, breaking Pin's invariant. Reject the combination at the type definition so the unsound program never compiles.
Collaborator
|
r? @folkertdev rustbot has assigned @folkertdev. Use Why was this reviewer chosen?The reviewer was selected based on:
|
mejrs
requested changes
Jun 6, 2026
Comment on lines
+1639
to
+1647
| if def.is_pin_project() | ||
| && let Some(pin_v2_span) = find_attr!(tcx, def.did(), PinV2(span) => *span) | ||
| { | ||
| tcx.dcx().emit_err(errors::PinV2OnPacked { | ||
| span: sp, | ||
| pin_v2_span, | ||
| adt_name: tcx.item_name(def.did()), | ||
| }); | ||
| } |
Contributor
There was a problem hiding this comment.
This error should be emitted whether or not the attribute can be found. Your best option is to use Option<Span> instead. Take for example
rust/compiler/rustc_hir_analysis/src/check/always_applicable.rs
Lines 408 to 415 in 61d7280
Collaborator
|
Reminder, once the PR becomes ready for a review, use |
Tie emission to `is_pin_project()` alone and pass the `#[pin_v2]` span as `Option<Span>`, so the error still fires if the span cannot be found, mirroring `PinV2WithoutPinDrop`.
75249a0 to
9663384
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #157011
#[repr(packed)]can store an over-aligned field below its alignment, and the drop glue for a packed type moves that field to a properly aligned spot before dropping it. When the field is structurally pinned, that move pulls it out from under aPin<&mut _>we already handed out, which breaks the pin invariant. The repro in the issue makes it pretty clear: it prints one address during pinned access and a different one on drop.So the fix just rejects the combo at the type definition. If a type is both
#[pin_v2]and#[repr(packed)], it no longer compiles. The check sits incheck_packedinrustc_hir_analysis, so it catches the concrete case and the generic one too (likeOne<T>, where we don't knowT's alignment yet), with no layout or monomorphization needed.One thing I want to be upfront about: this is necessary but don't solve the problem entirely. Sure, it stops the spelling the issue used, but you can still trigger the same move-on-drop through an explicit
&pin mut/ref pin mutprojection with no#[pin_v2]anywhere. Leaving that broader case open is intentional, imo the narrow ban is the right call for now, and the leftover stays tracked on the pin ergonomics tracking issue #130494.This is the direction we landed on with
@workingjubileeover on Zulip, lgtm from their side: https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/.60pin_v2.60.20is.20unsound.20with.20.60packed.60/with/600522893Tests live in
tests/ui/pin-ergonomics/pin_v2-packed.rs: the three rejected shapes (packed struct, genericpacked(4)struct, packed union), plus two controls that still compile fine,#[pin_v2]without packed and packed without#[pin_v2].Disclosure: AI tooling was used on the code changes, and everything was strictly validated by me before sending to remote.