diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index f11c1c77f9c..6f22345617d 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -828,6 +828,7 @@ fn univariant( if optimize && fields.len() > 1 { let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; let optimizing = &mut inverse_memory_index.raw[..end]; + let fields_excluding_tail = &fields.raw[..end]; // If `-Z randomize-layout` was enabled for the type definition we can shuffle // the field ordering to try and catch some code making assumptions about layouts @@ -844,8 +845,11 @@ fn univariant( } // Otherwise we just leave things alone and actually optimize the type's fields } else { - let max_field_align = fields.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1); - let largest_niche_size = fields + // To allow unsizing `&Foo` -> `&Foo`, the layout of the struct must + // not depend on the layout of the tail. + let max_field_align = + fields_excluding_tail.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1); + let largest_niche_size = fields_excluding_tail .iter() .filter_map(|f| f.largest_niche()) .map(|n| n.available(dl)) diff --git a/tests/ui/layout/issue-112048-unsizing-field-order.rs b/tests/ui/layout/issue-112048-unsizing-field-order.rs new file mode 100644 index 00000000000..ebc4b9e98b7 --- /dev/null +++ b/tests/ui/layout/issue-112048-unsizing-field-order.rs @@ -0,0 +1,25 @@ +// run-pass + +// Check that unsizing doesn't reorder fields. + +#![allow(dead_code)] + +use std::fmt::Debug; + +#[derive(Debug)] +struct GcNode { + gets_swapped_with_next: usize, + next: Option<&'static GcNode>, + tail: T, +} + +fn main() { + let node: Box> = Box::new(GcNode { + gets_swapped_with_next: 42, + next: None, + tail: Box::new(1), + }); + + assert_eq!(node.gets_swapped_with_next, 42); + assert!(node.next.is_none()); +}