Make struct layout not depend on unsizeable tail
This commit is contained in:
@@ -828,6 +828,7 @@ fn univariant(
|
|||||||
if optimize && fields.len() > 1 {
|
if optimize && fields.len() > 1 {
|
||||||
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
||||||
let optimizing = &mut inverse_memory_index.raw[..end];
|
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
|
// 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
|
// 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
|
// Otherwise we just leave things alone and actually optimize the type's fields
|
||||||
} else {
|
} else {
|
||||||
let max_field_align = fields.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1);
|
// To allow unsizing `&Foo<Type>` -> `&Foo<dyn Trait>`, the layout of the struct must
|
||||||
let largest_niche_size = fields
|
// 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()
|
.iter()
|
||||||
.filter_map(|f| f.largest_niche())
|
.filter_map(|f| f.largest_niche())
|
||||||
.map(|n| n.available(dl))
|
.map(|n| n.available(dl))
|
||||||
|
|||||||
25
tests/ui/layout/issue-112048-unsizing-field-order.rs
Normal file
25
tests/ui/layout/issue-112048-unsizing-field-order.rs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// run-pass
|
||||||
|
|
||||||
|
// Check that unsizing doesn't reorder fields.
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct GcNode<T: ?Sized> {
|
||||||
|
gets_swapped_with_next: usize,
|
||||||
|
next: Option<&'static GcNode<dyn Debug>>,
|
||||||
|
tail: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let node: Box<GcNode<dyn Debug>> = 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());
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user