From 8b0f7c0245d7a0b72d5327fe3a14c4024a498ca9 Mon Sep 17 00:00:00 2001 From: Mohamad Alsadhan Date: Thu, 12 Mar 2026 12:06:30 +0300 Subject: [PATCH] internal: add missing where clause to projection types `#[pin_data]` failed to propagate the struct's `where` clause to the generated projection struct. As a result, bounds written in a `where` clause could be dropped during expansion, causing type errors when fields depended on those bounds. Fix this by adding the missing `where` clause to the generated projection struct. Add a regression test covering `#[pin_data]` with `where`-clause bounds. Bless expand tests (only `many_generics.rs`) that became outdated. Link: https://rust-for-linux.zulipchat.com/#narrow/channel/561532-pin-init/topic/generic.20bounds.20and.20.60.23.5Bpin_data.5D.60/with/578381591 Reported-by: Andreas Hindborg Signed-off-by: Mohamad Alsadhan --- internal/src/pin_data.rs | 4 +- tests/ui/expand/many_generics.expanded.rs | 11 ++-- tests/where_bounds.rs | 64 +++++++++++++++++++++++ 3 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 tests/where_bounds.rs diff --git a/internal/src/pin_data.rs b/internal/src/pin_data.rs index 7d871236..6b1b8f26 100644 --- a/internal/src/pin_data.rs +++ b/internal/src/pin_data.rs @@ -304,7 +304,9 @@ fn generate_projections( #[doc = #docs] #[allow(dead_code)] #[doc(hidden)] - #vis struct #projection #generics_with_pin_lt { + #vis struct #projection #generics_with_pin_lt + #whr + { #(#fields_decl)* ___pin_phantom_data: ::core::marker::PhantomData<&'__pin mut ()>, } diff --git a/tests/ui/expand/many_generics.expanded.rs b/tests/ui/expand/many_generics.expanded.rs index 35f99102..f6962e3a 100644 --- a/tests/ui/expand/many_generics.expanded.rs +++ b/tests/ui/expand/many_generics.expanded.rs @@ -15,13 +15,10 @@ where /// Pin-projections of [`Foo`] #[allow(dead_code)] #[doc(hidden)] -struct FooProjection< - '__pin, - 'a, - 'b: 'a, - T: Bar<'b> + ?Sized + 'a, - const SIZE: usize = 0, -> { +struct FooProjection<'__pin, 'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize = 0> +where + T: Bar<'a, 1>, +{ array: &'__pin mut [u8; 1024 * 1024], r: &'__pin mut &'b mut [&'a mut T; SIZE], _pin: ::core::pin::Pin<&'__pin mut PhantomPinned>, diff --git a/tests/where_bounds.rs b/tests/where_bounds.rs new file mode 100644 index 00000000..4221c419 --- /dev/null +++ b/tests/where_bounds.rs @@ -0,0 +1,64 @@ +#![cfg_attr(USE_RUSTC_FEATURES, feature(lint_reasons))] +#![cfg_attr(USE_RUSTC_FEATURES, feature(raw_ref_op))] + +use core::marker::PhantomData; +use pin_init::*; + +struct Queue + 'static> { + _marker: PhantomData, +} + +impl + 'static> Queue { + fn new() -> impl PinInit { + init!(Self { + _marker: PhantomData, + }) + } +} + +#[pin_data] +struct InlineBoundHandler + 'static> { + #[pin] + queue: Queue, +} + +impl + 'static> InlineBoundHandler { + fn new() -> impl PinInit { + pin_init!(Self { + queue <- Queue::new(), + }) + } +} + +#[pin_data] +struct WhereBoundHandler +where + T: Iterator + 'static, +{ + #[pin] + queue: Queue, +} + +impl WhereBoundHandler +where + T: Iterator + 'static, +{ + fn new() -> impl PinInit { + pin_init!(Self { + queue <- Queue::new(), + }) + } +} + +#[test] +fn pin_data_preserves_inline_and_where_bounds() { + type Iter = core::iter::Empty; + + stack_pin_init!(let inline = InlineBoundHandler::::new()); + let inline_proj = inline.as_mut().project(); + let _ = inline_proj.queue; + + stack_pin_init!(let where_ = WhereBoundHandler::::new()); + let where_proj = where_.as_mut().project(); + let _ = where_proj.queue; +}