1
Fork 0

Bring back generic FieldIdx

This commit is contained in:
Lukas Wirth 2023-09-29 17:09:56 +02:00
parent 3b99d73f5a
commit b47ad3b744
3 changed files with 113 additions and 104 deletions

View file

@ -1,12 +1,14 @@
use std::fmt::Write; use std::fmt::{self, Write};
use std::ops::Deref;
use std::{borrow::Borrow, cmp, iter, ops::Bound}; use std::{borrow::Borrow, cmp, iter, ops::Bound};
use rustc_index::Idx;
use tracing::debug; use tracing::debug;
use crate::{ use crate::{
Abi, AbiAndPrefAlign, Align, FieldIdx, FieldsShape, IndexSlice, IndexVec, Integer, Layout, Abi, AbiAndPrefAlign, Align, FieldsShape, IndexSlice, IndexVec, Integer, LayoutS, Niche,
LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout,
TargetDataLayout, VariantIdx, Variants, WrappingRange, FIRST_VARIANT, VariantIdx, Variants, WrappingRange, FIRST_VARIANT,
}; };
pub trait LayoutCalculator { pub trait LayoutCalculator {
type TargetDataLayoutRef: Borrow<TargetDataLayout>; type TargetDataLayoutRef: Borrow<TargetDataLayout>;
@ -14,7 +16,7 @@ pub trait LayoutCalculator {
fn delay_bug(&self, txt: String); fn delay_bug(&self, txt: String);
fn current_data_layout(&self) -> Self::TargetDataLayoutRef; fn current_data_layout(&self) -> Self::TargetDataLayoutRef;
fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS { fn scalar_pair<FieldIdx: Idx>(&self, a: Scalar, b: Scalar) -> LayoutS<FieldIdx> {
let dl = self.current_data_layout(); let dl = self.current_data_layout();
let dl = dl.borrow(); let dl = dl.borrow();
let b_align = b.align(dl); let b_align = b.align(dl);
@ -44,13 +46,13 @@ pub trait LayoutCalculator {
} }
} }
fn univariant( fn univariant<'a, FieldIdx: Idx, F: Deref<Target = &'a LayoutS<FieldIdx>> + fmt::Debug>(
&self, &self,
dl: &TargetDataLayout, dl: &TargetDataLayout,
fields: &IndexSlice<FieldIdx, Layout<'_>>, fields: &IndexSlice<FieldIdx, F>,
repr: &ReprOptions, repr: &ReprOptions,
kind: StructKind, kind: StructKind,
) -> Option<LayoutS> { ) -> Option<LayoutS<FieldIdx>> {
let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start); let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start);
// Enums prefer niches close to the beginning or the end of the variants so that other // Enums prefer niches close to the beginning or the end of the variants so that other
// (smaller) data-carrying variants can be packed into the space after/before the niche. // (smaller) data-carrying variants can be packed into the space after/before the niche.
@ -113,7 +115,7 @@ pub trait LayoutCalculator {
layout layout
} }
fn layout_of_never_type(&self) -> LayoutS { fn layout_of_never_type<FieldIdx: Idx>(&self) -> LayoutS<FieldIdx> {
let dl = self.current_data_layout(); let dl = self.current_data_layout();
let dl = dl.borrow(); let dl = dl.borrow();
LayoutS { LayoutS {
@ -128,10 +130,14 @@ pub trait LayoutCalculator {
} }
} }
fn layout_of_struct_or_enum( fn layout_of_struct_or_enum<
'a,
FieldIdx: Idx,
F: Deref<Target = &'a LayoutS<FieldIdx>> + fmt::Debug,
>(
&self, &self,
repr: &ReprOptions, repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, Layout<'_>>>, variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool, is_enum: bool,
is_unsafe_cell: bool, is_unsafe_cell: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>), scalar_valid_range: (Bound<u128>, Bound<u128>),
@ -139,7 +145,7 @@ pub trait LayoutCalculator {
discriminants: impl Iterator<Item = (VariantIdx, i128)>, discriminants: impl Iterator<Item = (VariantIdx, i128)>,
dont_niche_optimize_enum: bool, dont_niche_optimize_enum: bool,
always_sized: bool, always_sized: bool,
) -> Option<LayoutS> { ) -> Option<LayoutS<FieldIdx>> {
let dl = self.current_data_layout(); let dl = self.current_data_layout();
let dl = dl.borrow(); let dl = dl.borrow();
@ -154,11 +160,11 @@ pub trait LayoutCalculator {
// but *not* an encoding of the discriminant (e.g., a tag value). // but *not* an encoding of the discriminant (e.g., a tag value).
// See issue #49298 for more details on the need to leave space // See issue #49298 for more details on the need to leave space
// for non-ZST uninhabited data (mostly partial initialization). // for non-ZST uninhabited data (mostly partial initialization).
let absent = |fields: &IndexSlice<FieldIdx, Layout<'_>>| { let absent = |fields: &IndexSlice<FieldIdx, F>| {
let uninhabited = fields.iter().any(|f| f.abi().is_uninhabited()); let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
// We cannot ignore alignment; that might lead us to entirely discard a variant and // We cannot ignore alignment; that might lead us to entirely discard a variant and
// produce an enum that is less aligned than it should be! // produce an enum that is less aligned than it should be!
let is_1zst = fields.iter().all(|f| f.0.is_1zst()); let is_1zst = fields.iter().all(|f| f.is_1zst());
uninhabited && is_1zst uninhabited && is_1zst
}; };
let (present_first, present_second) = { let (present_first, present_second) = {
@ -278,12 +284,12 @@ pub trait LayoutCalculator {
// variant layouts, so we can't store them in the // variant layouts, so we can't store them in the
// overall LayoutS. Store the overall LayoutS // overall LayoutS. Store the overall LayoutS
// and the variant LayoutSs here until then. // and the variant LayoutSs here until then.
struct TmpLayout { struct TmpLayout<FieldIdx: Idx> {
layout: LayoutS, layout: LayoutS<FieldIdx>,
variants: IndexVec<VariantIdx, LayoutS>, variants: IndexVec<VariantIdx, LayoutS<FieldIdx>>,
} }
let calculate_niche_filling_layout = || -> Option<TmpLayout> { let calculate_niche_filling_layout = || -> Option<TmpLayout<FieldIdx>> {
if dont_niche_optimize_enum { if dont_niche_optimize_enum {
return None; return None;
} }
@ -327,7 +333,7 @@ pub trait LayoutCalculator {
let (field_index, niche, (niche_start, niche_scalar)) = variants[largest_variant_index] let (field_index, niche, (niche_start, niche_scalar)) = variants[largest_variant_index]
.iter() .iter()
.enumerate() .enumerate()
.filter_map(|(j, field)| Some((j, field.largest_niche()?))) .filter_map(|(j, field)| Some((j, field.largest_niche?)))
.max_by_key(|(_, niche)| niche.available(dl)) .max_by_key(|(_, niche)| niche.available(dl))
.and_then(|(j, niche)| Some((j, niche, niche.reserve(dl, count)?)))?; .and_then(|(j, niche)| Some((j, niche, niche.reserve(dl, count)?)))?;
let niche_offset = let niche_offset =
@ -442,7 +448,7 @@ pub trait LayoutCalculator {
let discr_type = repr.discr_type(); let discr_type = repr.discr_type();
let bits = Integer::from_attr(dl, discr_type).size().bits(); let bits = Integer::from_attr(dl, discr_type).size().bits();
for (i, mut val) in discriminants { for (i, mut val) in discriminants {
if variants[i].iter().any(|f| f.abi().is_uninhabited()) { if variants[i].iter().any(|f| f.abi.is_uninhabited()) {
continue; continue;
} }
if discr_type.is_signed() { if discr_type.is_signed() {
@ -483,7 +489,7 @@ pub trait LayoutCalculator {
if repr.c() { if repr.c() {
for fields in variants { for fields in variants {
for field in fields { for field in fields {
prefix_align = prefix_align.max(field.align().abi); prefix_align = prefix_align.max(field.align.abi);
} }
} }
} }
@ -502,9 +508,9 @@ pub trait LayoutCalculator {
// Find the first field we can't move later // Find the first field we can't move later
// to make room for a larger discriminant. // to make room for a larger discriminant.
for field_idx in st.fields.index_by_increasing_offset() { for field_idx in st.fields.index_by_increasing_offset() {
let field = &field_layouts[FieldIdx::from_usize(field_idx)]; let field = &field_layouts[FieldIdx::new(field_idx)];
if !field.0.is_1zst() { if !field.is_1zst() {
start_align = start_align.min(field.align().abi); start_align = start_align.min(field.align.abi);
break; break;
} }
} }
@ -611,7 +617,7 @@ pub trait LayoutCalculator {
}; };
// We skip *all* ZST here and later check if we are good in terms of alignment. // We skip *all* ZST here and later check if we are good in terms of alignment.
// This lets us handle some cases involving aligned ZST. // This lets us handle some cases involving aligned ZST.
let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.0.is_zst()); let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst());
let (field, offset) = match (fields.next(), fields.next()) { let (field, offset) = match (fields.next(), fields.next()) {
(None, None) => { (None, None) => {
common_prim_initialized_in_all_variants = false; common_prim_initialized_in_all_variants = false;
@ -623,7 +629,7 @@ pub trait LayoutCalculator {
break; break;
} }
}; };
let prim = match field.abi() { let prim = match field.abi {
Abi::Scalar(scalar) => { Abi::Scalar(scalar) => {
common_prim_initialized_in_all_variants &= common_prim_initialized_in_all_variants &=
matches!(scalar, Scalar::Initialized { .. }); matches!(scalar, Scalar::Initialized { .. });
@ -662,8 +668,8 @@ pub trait LayoutCalculator {
} }
_ => panic!(), _ => panic!(),
}; };
if pair_offsets[FieldIdx::from_u32(0)] == Size::ZERO if pair_offsets[FieldIdx::new(0)] == Size::ZERO
&& pair_offsets[FieldIdx::from_u32(1)] == *offset && pair_offsets[FieldIdx::new(1)] == *offset
&& align == pair.align && align == pair.align
&& size == pair.size && size == pair.size
{ {
@ -720,8 +726,9 @@ pub trait LayoutCalculator {
// pick the layout with the larger niche; otherwise, // pick the layout with the larger niche; otherwise,
// pick tagged as it has simpler codegen. // pick tagged as it has simpler codegen.
use cmp::Ordering::*; use cmp::Ordering::*;
let niche_size = let niche_size = |tmp_l: &TmpLayout<FieldIdx>| {
|tmp_l: &TmpLayout| tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)); tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl))
};
match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) { match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) {
(Greater, _) => nl, (Greater, _) => nl,
(Equal, Less) => nl, (Equal, Less) => nl,
@ -741,11 +748,11 @@ pub trait LayoutCalculator {
Some(best_layout.layout) Some(best_layout.layout)
} }
fn layout_of_union( fn layout_of_union<'a, FieldIdx: Idx, F: Deref<Target = &'a LayoutS<FieldIdx>> + fmt::Debug>(
&self, &self,
repr: &ReprOptions, repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, Layout<'_>>>, variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
) -> Option<LayoutS> { ) -> Option<LayoutS<FieldIdx>> {
let dl = self.current_data_layout(); let dl = self.current_data_layout();
let dl = dl.borrow(); let dl = dl.borrow();
let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align };
@ -764,22 +771,22 @@ pub trait LayoutCalculator {
let mut size = Size::ZERO; let mut size = Size::ZERO;
let only_variant = &variants[FIRST_VARIANT]; let only_variant = &variants[FIRST_VARIANT];
for field in only_variant { for field in only_variant {
if field.0.is_unsized() { if field.is_unsized() {
self.delay_bug("unsized field in union".to_string()); self.delay_bug("unsized field in union".to_string());
} }
align = align.max(field.align()); align = align.max(field.align);
max_repr_align = max_repr_align.max(field.max_repr_align()); max_repr_align = max_repr_align.max(field.max_repr_align);
size = cmp::max(size, field.size()); size = cmp::max(size, field.size);
if field.0.is_zst() { if field.is_zst() {
// Nothing more to do for ZST fields // Nothing more to do for ZST fields
continue; continue;
} }
if let Ok(common) = common_non_zst_abi_and_align { if let Ok(common) = common_non_zst_abi_and_align {
// Discard valid range information and allow undef // Discard valid range information and allow undef
let field_abi = field.abi().to_union(); let field_abi = field.abi.to_union();
if let Some((common_abi, common_align)) = common { if let Some((common_abi, common_align)) = common {
if common_abi != field_abi { if common_abi != field_abi {
@ -790,15 +797,14 @@ pub trait LayoutCalculator {
// have the same alignment // have the same alignment
if !matches!(common_abi, Abi::Aggregate { .. }) { if !matches!(common_abi, Abi::Aggregate { .. }) {
assert_eq!( assert_eq!(
common_align, common_align, field.align.abi,
field.align().abi,
"non-Aggregate field with matching ABI but differing alignment" "non-Aggregate field with matching ABI but differing alignment"
); );
} }
} }
} else { } else {
// First non-ZST field: record its ABI and alignment // First non-ZST field: record its ABI and alignment
common_non_zst_abi_and_align = Ok(Some((field_abi, field.align().abi))); common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi)));
} }
} }
} }
@ -848,14 +854,14 @@ enum NicheBias {
End, End,
} }
fn univariant( fn univariant<'a, FieldIdx: Idx, F: Deref<Target = &'a LayoutS<FieldIdx>> + fmt::Debug>(
this: &(impl LayoutCalculator + ?Sized), this: &(impl LayoutCalculator + ?Sized),
dl: &TargetDataLayout, dl: &TargetDataLayout,
fields: &IndexSlice<FieldIdx, Layout<'_>>, fields: &IndexSlice<FieldIdx, F>,
repr: &ReprOptions, repr: &ReprOptions,
kind: StructKind, kind: StructKind,
niche_bias: NicheBias, niche_bias: NicheBias,
) -> Option<LayoutS> { ) -> Option<LayoutS<FieldIdx>> {
let pack = repr.pack; let pack = repr.pack;
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
let mut max_repr_align = repr.align; let mut max_repr_align = repr.align;
@ -887,27 +893,27 @@ fn univariant(
// To allow unsizing `&Foo<Type>` -> `&Foo<dyn Trait>`, the layout of the struct must // To allow unsizing `&Foo<Type>` -> `&Foo<dyn Trait>`, the layout of the struct must
// not depend on the layout of the tail. // not depend on the layout of the tail.
let max_field_align = let max_field_align =
fields_excluding_tail.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1); fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1);
let largest_niche_size = fields_excluding_tail 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))
.max() .max()
.unwrap_or(0); .unwrap_or(0);
// Calculates a sort key to group fields by their alignment or possibly some // Calculates a sort key to group fields by their alignment or possibly some
// size-derived pseudo-alignment. // size-derived pseudo-alignment.
let alignment_group_key = |layout: Layout<'_>| { let alignment_group_key = |layout: &F| {
if let Some(pack) = pack { if let Some(pack) = pack {
// Return the packed alignment in bytes. // Return the packed alignment in bytes.
layout.align().abi.min(pack).bytes() layout.align.abi.min(pack).bytes()
} else { } else {
// Returns `log2(effective-align)`. This is ok since `pack` applies to all // Returns `log2(effective-align)`. This is ok since `pack` applies to all
// fields equally. The calculation assumes that size is an integer multiple of // fields equally. The calculation assumes that size is an integer multiple of
// align, except for ZSTs. // align, except for ZSTs.
let align = layout.align().abi.bytes(); let align = layout.align.abi.bytes();
let size = layout.size().bytes(); let size = layout.size.bytes();
let niche_size = layout.largest_niche().map(|n| n.available(dl)).unwrap_or(0); let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0);
// Group [u8; 4] with align-4 or [u8; 6] with align-2 fields. // Group [u8; 4] with align-4 or [u8; 6] with align-2 fields.
let size_as_align = align.max(size).trailing_zeros(); let size_as_align = align.max(size).trailing_zeros();
let size_as_align = if largest_niche_size > 0 { let size_as_align = if largest_niche_size > 0 {
@ -942,9 +948,9 @@ fn univariant(
// u16 to build a 4-byte group so that the u32 can be placed after it without // u16 to build a 4-byte group so that the u32 can be placed after it without
// padding. This kind of packing can't be achieved by sorting. // padding. This kind of packing can't be achieved by sorting.
optimizing.sort_by_key(|&x| { optimizing.sort_by_key(|&x| {
let f = fields[x]; let f = &fields[x];
let field_size = f.size().bytes(); let field_size = f.size.bytes();
let niche_size = f.largest_niche().map_or(0, |n| n.available(dl)); let niche_size = f.largest_niche.map_or(0, |n| n.available(dl));
let niche_size_key = match niche_bias { let niche_size_key = match niche_bias {
// large niche first // large niche first
NicheBias::Start => !niche_size, NicheBias::Start => !niche_size,
@ -952,8 +958,8 @@ fn univariant(
NicheBias::End => niche_size, NicheBias::End => niche_size,
}; };
let inner_niche_offset_key = match niche_bias { let inner_niche_offset_key = match niche_bias {
NicheBias::Start => f.largest_niche().map_or(0, |n| n.offset.bytes()), NicheBias::Start => f.largest_niche.map_or(0, |n| n.offset.bytes()),
NicheBias::End => f.largest_niche().map_or(0, |n| { NicheBias::End => f.largest_niche.map_or(0, |n| {
!(field_size - n.value.size(dl).bytes() - n.offset.bytes()) !(field_size - n.value.size(dl).bytes() - n.offset.bytes())
}), }),
}; };
@ -977,8 +983,8 @@ fn univariant(
// And put the largest niche in an alignment group at the end // And put the largest niche in an alignment group at the end
// so it can be used as discriminant in jagged enums // so it can be used as discriminant in jagged enums
optimizing.sort_by_key(|&x| { optimizing.sort_by_key(|&x| {
let f = fields[x]; let f = &fields[x];
let niche_size = f.largest_niche().map_or(0, |n| n.available(dl)); let niche_size = f.largest_niche.map_or(0, |n| n.available(dl));
(alignment_group_key(f), niche_size) (alignment_group_key(f), niche_size)
}); });
} }
@ -1014,24 +1020,24 @@ fn univariant(
)); ));
} }
if field.0.is_unsized() { if field.is_unsized() {
sized = false; sized = false;
} }
// Invariant: offset < dl.obj_size_bound() <= 1<<61 // Invariant: offset < dl.obj_size_bound() <= 1<<61
let field_align = if let Some(pack) = pack { let field_align = if let Some(pack) = pack {
field.align().min(AbiAndPrefAlign::new(pack)) field.align.min(AbiAndPrefAlign::new(pack))
} else { } else {
field.align() field.align
}; };
offset = offset.align_to(field_align.abi); offset = offset.align_to(field_align.abi);
align = align.max(field_align); align = align.max(field_align);
max_repr_align = max_repr_align.max(field.max_repr_align()); max_repr_align = max_repr_align.max(field.max_repr_align);
debug!("univariant offset: {:?} field: {:#?}", offset, field); debug!("univariant offset: {:?} field: {:#?}", offset, field);
offsets[i] = offset; offsets[i] = offset;
if let Some(mut niche) = field.largest_niche() { if let Some(mut niche) = field.largest_niche {
let available = niche.available(dl); let available = niche.available(dl);
// Pick up larger niches. // Pick up larger niches.
let prefer_new_niche = match niche_bias { let prefer_new_niche = match niche_bias {
@ -1046,7 +1052,7 @@ fn univariant(
} }
} }
offset = offset.checked_add(field.size(), dl)?; offset = offset.checked_add(field.size, dl)?;
} }
// The unadjusted ABI alignment does not include repr(align), but does include repr(pack). // The unadjusted ABI alignment does not include repr(align), but does include repr(pack).
@ -1070,7 +1076,7 @@ fn univariant(
inverse_memory_index.invert_bijective_mapping() inverse_memory_index.invert_bijective_mapping()
} else { } else {
debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices())); debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect() inverse_memory_index.into_iter().map(|it| it.index() as u32).collect()
}; };
let size = min_size.align_to(align.abi); let size = min_size.align_to(align.abi);
let mut layout_of_single_non_zst_field = None; let mut layout_of_single_non_zst_field = None;
@ -1079,7 +1085,7 @@ fn univariant(
if sized && size.bytes() > 0 { if sized && size.bytes() > 0 {
// We skip *all* ZST here and later check if we are good in terms of alignment. // We skip *all* ZST here and later check if we are good in terms of alignment.
// This lets us handle some cases involving aligned ZST. // This lets us handle some cases involving aligned ZST.
let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst()); let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.is_zst());
match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
// We have exactly one non-ZST field. // We have exactly one non-ZST field.
@ -1087,18 +1093,17 @@ fn univariant(
layout_of_single_non_zst_field = Some(field); layout_of_single_non_zst_field = Some(field);
// Field fills the struct and it has a scalar or scalar pair ABI. // Field fills the struct and it has a scalar or scalar pair ABI.
if offsets[i].bytes() == 0 && align.abi == field.align().abi && size == field.size() if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size {
{ match field.abi {
match field.abi() {
// For plain scalars, or vectors of them, we can't unpack // For plain scalars, or vectors of them, we can't unpack
// newtypes for `#[repr(C)]`, as that affects C ABIs. // newtypes for `#[repr(C)]`, as that affects C ABIs.
Abi::Scalar(_) | Abi::Vector { .. } if optimize => { Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
abi = field.abi(); abi = field.abi;
} }
// But scalar pairs are Rust-specific and get // But scalar pairs are Rust-specific and get
// treated as aggregates by C ABIs anyway. // treated as aggregates by C ABIs anyway.
Abi::ScalarPair(..) => { Abi::ScalarPair(..) => {
abi = field.abi(); abi = field.abi;
} }
_ => {} _ => {}
} }
@ -1107,7 +1112,7 @@ fn univariant(
// Two non-ZST fields, and they're both scalars. // Two non-ZST fields, and they're both scalars.
(Some((i, a)), Some((j, b)), None) => { (Some((i, a)), Some((j, b)), None) => {
match (a.abi(), b.abi()) { match (a.abi, b.abi) {
(Abi::Scalar(a), Abi::Scalar(b)) => { (Abi::Scalar(a), Abi::Scalar(b)) => {
// Order by the memory placement, not source order. // Order by the memory placement, not source order.
let ((i, a), (j, b)) = if offsets[i] < offsets[j] { let ((i, a), (j, b)) = if offsets[i] < offsets[j] {
@ -1123,8 +1128,8 @@ fn univariant(
} }
_ => panic!(), _ => panic!(),
}; };
if offsets[i] == pair_offsets[FieldIdx::from_usize(0)] if offsets[i] == pair_offsets[FieldIdx::new(0)]
&& offsets[j] == pair_offsets[FieldIdx::from_usize(1)] && offsets[j] == pair_offsets[FieldIdx::new(1)]
&& align == pair.align && align == pair.align
&& size == pair.size && size == pair.size
{ {
@ -1140,13 +1145,13 @@ fn univariant(
_ => {} _ => {}
} }
} }
if fields.iter().any(|f| f.abi().is_uninhabited()) { if fields.iter().any(|f| f.abi.is_uninhabited()) {
abi = Abi::Uninhabited; abi = Abi::Uninhabited;
} }
let unadjusted_abi_align = if repr.transparent() { let unadjusted_abi_align = if repr.transparent() {
match layout_of_single_non_zst_field { match layout_of_single_non_zst_field {
Some(l) => l.unadjusted_abi_align(), Some(l) => l.unadjusted_abi_align,
None => { None => {
// `repr(transparent)` with all ZST fields. // `repr(transparent)` with all ZST fields.
align.abi align.abi
@ -1168,17 +1173,17 @@ fn univariant(
}) })
} }
fn format_field_niches( fn format_field_niches<'a, FieldIdx: Idx, F: Deref<Target = &'a LayoutS<FieldIdx>> + fmt::Debug>(
layout: &LayoutS, layout: &LayoutS<FieldIdx>,
fields: &IndexSlice<FieldIdx, Layout<'_>>, fields: &IndexSlice<FieldIdx, F>,
dl: &TargetDataLayout, dl: &TargetDataLayout,
) -> String { ) -> String {
let mut s = String::new(); let mut s = String::new();
for i in layout.fields.index_by_increasing_offset() { for i in layout.fields.index_by_increasing_offset() {
let offset = layout.fields.offset(i); let offset = layout.fields.offset(i);
let f = fields[i.into()]; let f = &fields[FieldIdx::new(i)];
write!(s, "[o{}a{}s{}", offset.bytes(), f.align().abi.bytes(), f.size().bytes()).unwrap(); write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap();
if let Some(n) = f.largest_niche() { if let Some(n) = f.largest_niche {
write!( write!(
s, s,
" n{}b{}s{}", " n{}b{}s{}",

View file

@ -15,7 +15,7 @@ use rustc_data_structures::intern::Interned;
use rustc_data_structures::stable_hasher::Hash64; use rustc_data_structures::stable_hasher::Hash64;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::StableOrd; use rustc_data_structures::stable_hasher::StableOrd;
use rustc_index::{IndexSlice, IndexVec}; use rustc_index::{Idx, IndexSlice, IndexVec};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
@ -1134,7 +1134,7 @@ rustc_index::newtype_index! {
/// Describes how the fields of a type are located in memory. /// Describes how the fields of a type are located in memory.
#[derive(PartialEq, Eq, Hash, Clone, Debug)] #[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
pub enum FieldsShape { pub enum FieldsShape<FieldIdx: Idx> {
/// Scalar primitives and `!`, which never have fields. /// Scalar primitives and `!`, which never have fields.
Primitive, Primitive,
@ -1174,7 +1174,7 @@ pub enum FieldsShape {
}, },
} }
impl FieldsShape { impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
#[inline] #[inline]
pub fn count(&self) -> usize { pub fn count(&self) -> usize {
match *self { match *self {
@ -1200,7 +1200,7 @@ impl FieldsShape {
assert!(i < count, "tried to access field {i} of array with {count} fields"); assert!(i < count, "tried to access field {i} of array with {count} fields");
stride * i stride * i
} }
FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::from_usize(i)], FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::new(i)],
} }
} }
@ -1212,7 +1212,7 @@ impl FieldsShape {
} }
FieldsShape::Union(_) | FieldsShape::Array { .. } => i, FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
FieldsShape::Arbitrary { ref memory_index, .. } => { FieldsShape::Arbitrary { ref memory_index, .. } => {
memory_index[FieldIdx::from_usize(i)].try_into().unwrap() memory_index[FieldIdx::new(i)].try_into().unwrap()
} }
} }
} }
@ -1228,7 +1228,7 @@ impl FieldsShape {
if let FieldsShape::Arbitrary { ref memory_index, .. } = *self { if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
if use_small { if use_small {
for (field_idx, &mem_idx) in memory_index.iter_enumerated() { for (field_idx, &mem_idx) in memory_index.iter_enumerated() {
inverse_small[mem_idx as usize] = field_idx.as_u32() as u8; inverse_small[mem_idx as usize] = field_idx.index() as u8;
} }
} else { } else {
inverse_big = memory_index.invert_bijective_mapping(); inverse_big = memory_index.invert_bijective_mapping();
@ -1241,7 +1241,7 @@ impl FieldsShape {
if use_small { if use_small {
inverse_small[i] as usize inverse_small[i] as usize
} else { } else {
inverse_big[i as u32].as_usize() inverse_big[i as u32].index()
} }
} }
}) })
@ -1386,7 +1386,7 @@ impl Abi {
#[derive(PartialEq, Eq, Hash, Clone, Debug)] #[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
pub enum Variants { pub enum Variants<FieldIdx: Idx> {
/// Single enum variants, structs/tuples, unions, and all non-ADTs. /// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single { index: VariantIdx }, Single { index: VariantIdx },
@ -1400,7 +1400,7 @@ pub enum Variants {
tag: Scalar, tag: Scalar,
tag_encoding: TagEncoding, tag_encoding: TagEncoding,
tag_field: usize, tag_field: usize,
variants: IndexVec<VariantIdx, LayoutS>, variants: IndexVec<VariantIdx, LayoutS<FieldIdx>>,
}, },
} }
@ -1534,9 +1534,9 @@ rustc_index::newtype_index! {
#[derive(PartialEq, Eq, Hash, Clone)] #[derive(PartialEq, Eq, Hash, Clone)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
pub struct LayoutS { pub struct LayoutS<FieldIdx: Idx> {
/// Says where the fields are located within the layout. /// Says where the fields are located within the layout.
pub fields: FieldsShape, pub fields: FieldsShape<FieldIdx>,
/// Encodes information about multi-variant layouts. /// Encodes information about multi-variant layouts.
/// Even with `Multiple` variants, a layout still has its own fields! Those are then /// Even with `Multiple` variants, a layout still has its own fields! Those are then
@ -1545,7 +1545,7 @@ pub struct LayoutS {
/// ///
/// To access all fields of this layout, both `fields` and the fields of the active variant /// To access all fields of this layout, both `fields` and the fields of the active variant
/// must be taken into account. /// must be taken into account.
pub variants: Variants, pub variants: Variants<FieldIdx>,
/// The `abi` defines how this data is passed between functions, and it defines /// The `abi` defines how this data is passed between functions, and it defines
/// value restrictions via `valid_range`. /// value restrictions via `valid_range`.
@ -1574,7 +1574,7 @@ pub struct LayoutS {
pub unadjusted_abi_align: Align, pub unadjusted_abi_align: Align,
} }
impl LayoutS { impl<FieldIdx: Idx> LayoutS<FieldIdx> {
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self { pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
let size = scalar.size(cx); let size = scalar.size(cx);
@ -1592,7 +1592,11 @@ impl LayoutS {
} }
} }
impl fmt::Debug for LayoutS { impl<FieldIdx: Idx> fmt::Debug for LayoutS<FieldIdx>
where
FieldsShape<FieldIdx>: fmt::Debug,
Variants<FieldIdx>: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// This is how `Layout` used to print before it become // This is how `Layout` used to print before it become
// `Interned<LayoutS>`. We print it like this to avoid having to update // `Interned<LayoutS>`. We print it like this to avoid having to update
@ -1622,7 +1626,7 @@ impl fmt::Debug for LayoutS {
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
#[rustc_pass_by_value] #[rustc_pass_by_value]
pub struct Layout<'a>(pub Interned<'a, LayoutS>); pub struct Layout<'a>(pub Interned<'a, LayoutS<FieldIdx>>);
impl<'a> fmt::Debug for Layout<'a> { impl<'a> fmt::Debug for Layout<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -1632,11 +1636,11 @@ impl<'a> fmt::Debug for Layout<'a> {
} }
impl<'a> Layout<'a> { impl<'a> Layout<'a> {
pub fn fields(self) -> &'a FieldsShape { pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
&self.0.0.fields &self.0.0.fields
} }
pub fn variants(self) -> &'a Variants { pub fn variants(self) -> &'a Variants<FieldIdx> {
&self.0.0.variants &self.0.0.variants
} }
@ -1694,7 +1698,7 @@ pub struct PointeeInfo {
pub safe: Option<PointerKind>, pub safe: Option<PointerKind>,
} }
impl LayoutS { impl<FieldIdx: Idx> LayoutS<FieldIdx> {
/// Returns `true` if the layout corresponds to an unsized type. /// Returns `true` if the layout corresponds to an unsized type.
#[inline] #[inline]
pub fn is_unsized(&self) -> bool { pub fn is_unsized(&self) -> bool {

View file

@ -42,8 +42,8 @@ impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
} }
impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
type Target = &'a LayoutS; type Target = &'a LayoutS<FieldIdx>;
fn deref(&self) -> &&'a LayoutS { fn deref(&self) -> &&'a LayoutS<FieldIdx> {
&self.layout.0.0 &self.layout.0.0
} }
} }