closure field capturing: don't depend on alignment of packed fields by RalfJung · Pull Request #115315 · rust-lang/rust (original) (raw)

This fixes the closure field capture part of #115305: field capturing always stops at projections into packed structs, no matter the alignment of the field. This means changing a private field type from u8 to u64 can never change how closures capture fields, which is probably what we want.

Here's an example where, before this PR, changing the type of a private field in a repr(Rust) struct can change the output of a program:

#![allow(dead_code)]

mod m { // before patch #[derive(Default)] pub struct S1(u8); // after patch #[derive(Default)] pub struct S2(u64); }

struct NoisyDrop; impl Drop for NoisyDrop { fn drop(&mut self) { eprintln!("dropped!"); } }

#[repr(packed)] struct MyType { field: m::S1, // output changes when this becomes S2 other_field: NoisyDrop, third_field: Vec<()>, }

fn test(r: MyType) { let c = || { let _val = std::ptr::addr_of!(r.field); let _val = r.third_field; }; drop(c); eprintln!("before dropping"); }

fn main() { test(MyType { field: Default::default(), other_field: NoisyDrop, third_field: Vec::new(), }); }

Of course this is a breaking change for the same reason that doing field capturing in the first place was a breaking change. Packed fields are relatively rare and depending on drop order is relatively rare, so I don't expect this to have much impact, but it's hard to be sure and even a crater run will only tell us so much.

Also see the nomination comment.

Cc @rust-lang/wg-rfc-2229 @ehuss