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
10 changes: 10 additions & 0 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1633,6 +1633,16 @@ fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalab
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
let repr = def.repr();
if repr.packed() {
// `#[pin_v2]` on a packed type is unsound: drop glue for a packed type moves an
// over-aligned field to an aligned location before running its destructor, which would
// move a structurally pinned field out from under a `Pin<&mut _>` that was handed out.
if def.is_pin_project() {
tcx.dcx().emit_err(errors::PinV2OnPacked {
span: sp,
pin_v2_span: find_attr!(tcx, def.did(), PinV2(span) => *span),
adt_name: tcx.item_name(def.did()),
});
}
if let Some(reprs) = find_attr!(tcx, def.did(), Repr { reprs, .. } => reprs) {
for (r, _) in reprs {
if let ReprPacked(pack) = r
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2035,3 +2035,16 @@ pub(crate) struct PinV2WithoutPinDrop {
pub pin_v2_span: Option<Span>,
pub adt_name: Symbol,
}

#[derive(Diagnostic)]
#[diag("`#[pin_v2]` types may not have `#[repr(packed)]`")]
#[note(
"fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow"
)]
pub(crate) struct PinV2OnPacked {
#[primary_span]
pub span: Span,
#[note("`{$adt_name}` is marked `#[pin_v2]` here")]
pub pin_v2_span: Option<Span>,
pub adt_name: Symbol,
}
42 changes: 42 additions & 0 deletions tests/ui/pin-ergonomics/pin_v2-packed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! `#[pin_v2]` is not allowed on `#[repr(packed)]` types.
//!
//! Drop glue for a packed type moves an over-aligned field to an aligned location before running
//! its destructor. That move carries along any structurally pinned leaf, so a value handed out as
//! `Pin<&mut _>` would be moved before it is dropped, violating `Pin`'s invariant.
//!
//! Regression test for <https://github.com/rust-lang/rust/issues/157011>.

#![feature(pin_ergonomics)]
#![allow(incomplete_features)]

use std::marker::PhantomPinned;

#[pin_v2]
#[repr(packed)]
struct Packed { //~ ERROR `#[pin_v2]` types may not have `#[repr(packed)]`
field: PhantomPinned,
}

// The generic case from the issue: alignment of `T` is unknown at definition time, so this is
// rejected regardless of how it is later monomorphized.
#[pin_v2]
#[repr(C, packed(4))]
struct PackedN<T>(T);
//~^ ERROR `#[pin_v2]` types may not have `#[repr(packed)]`

#[pin_v2]
#[repr(packed)]
union PackedUnion { //~ ERROR `#[pin_v2]` types may not have `#[repr(packed)]`
field: (),
}

// Allowed: `#[pin_v2]` without `#[repr(packed)]` still compiles.
#[pin_v2]
#[repr(C)]
struct Unpacked<T>(T);

// Allowed: `#[repr(packed)]` without `#[pin_v2]` is unaffected by the ban.
#[repr(packed)]
struct PackedNoPin(u8);

fn main() {}
41 changes: 41 additions & 0 deletions tests/ui/pin-ergonomics/pin_v2-packed.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
error: `#[pin_v2]` types may not have `#[repr(packed)]`
--> $DIR/pin_v2-packed.rs:16:1
|
LL | struct Packed {
| ^^^^^^^^^^^^^
|
= note: fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow
note: `Packed` is marked `#[pin_v2]` here
--> $DIR/pin_v2-packed.rs:14:1
|
LL | #[pin_v2]
| ^^^^^^^^^

error: `#[pin_v2]` types may not have `#[repr(packed)]`
--> $DIR/pin_v2-packed.rs:24:1
|
LL | struct PackedN<T>(T);
| ^^^^^^^^^^^^^^^^^
|
= note: fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow
note: `PackedN` is marked `#[pin_v2]` here
--> $DIR/pin_v2-packed.rs:22:1
|
LL | #[pin_v2]
| ^^^^^^^^^

error: `#[pin_v2]` types may not have `#[repr(packed)]`
--> $DIR/pin_v2-packed.rs:29:1
|
LL | union PackedUnion {
| ^^^^^^^^^^^^^^^^^
|
= note: fields of a `#[repr(packed)]` type can be under-aligned, so a structurally pinned field may be moved to a properly aligned location, which `Pin` does not allow
note: `PackedUnion` is marked `#[pin_v2]` here
--> $DIR/pin_v2-packed.rs:27:1
|
LL | #[pin_v2]
| ^^^^^^^^^

error: aborting due to 3 previous errors

Loading