clean up struct layout code

This commit is contained in:
Lukas Markeffsky 2023-07-02 14:06:56 +02:00
parent 4b6749b21e
commit 478071ba9d
2 changed files with 41 additions and 36 deletions

View File

@ -134,7 +134,7 @@ pub trait LayoutCalculator {
scalar_valid_range: (Bound<u128>, Bound<u128>), scalar_valid_range: (Bound<u128>, Bound<u128>),
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>, discriminants: impl Iterator<Item = (VariantIdx, i128)>,
niche_optimize_enum: bool, dont_niche_optimize_enum: bool,
always_sized: bool, always_sized: bool,
) -> Option<LayoutS> { ) -> Option<LayoutS> {
let dl = self.current_data_layout(); let dl = self.current_data_layout();
@ -183,10 +183,10 @@ pub trait LayoutCalculator {
// (Typechecking will reject discriminant-sizing attrs.) // (Typechecking will reject discriminant-sizing attrs.)
let v = present_first; let v = present_first;
let kind = if is_enum || variants[v].is_empty() { let kind = if is_enum || variants[v].is_empty() || always_sized {
StructKind::AlwaysSized StructKind::AlwaysSized
} else { } else {
if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized } StructKind::MaybeUnsized
}; };
let mut st = self.univariant(dl, &variants[v], repr, kind)?; let mut st = self.univariant(dl, &variants[v], repr, kind)?;
@ -280,7 +280,7 @@ pub trait LayoutCalculator {
} }
let calculate_niche_filling_layout = || -> Option<TmpLayout> { let calculate_niche_filling_layout = || -> Option<TmpLayout> {
if niche_optimize_enum { if dont_niche_optimize_enum {
return None; return None;
} }

View File

@ -463,38 +463,43 @@ fn layout_of_uncached<'tcx>(
)); ));
} }
tcx.mk_layout( let get_discriminant_type =
cx.layout_of_struct_or_enum( |min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max);
&def.repr(),
&variants, let discriminants_iter = || {
def.is_enum(), def.is_enum()
def.is_unsafe_cell(), .then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val as i128)))
tcx.layout_scalar_valid_range(def.did()), .into_iter()
|min, max| Integer::repr_discr(tcx, ty, &def.repr(), min, max), .flatten()
def.is_enum() };
.then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val as i128)))
.into_iter() let dont_niche_optimize_enum = def.repr().inhibit_enum_layout_opt()
.flatten(), || def
def.repr().inhibit_enum_layout_opt() .variants()
|| def .iter_enumerated()
.variants() .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32()));
.iter_enumerated()
.any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32())), let maybe_unsized = def.is_struct()
{ && def.non_enum_variant().fields.raw.last().is_some_and(|last_field| {
let param_env = tcx.param_env(def.did()); let param_env = tcx.param_env(def.did());
def.is_struct() !tcx.type_of(last_field.did).subst_identity().is_sized(tcx, param_env)
&& match def.variants().iter().next().and_then(|x| x.fields.raw.last()) });
{
Some(last_field) => tcx let Some(layout) = cx.layout_of_struct_or_enum(
.type_of(last_field.did) &def.repr(),
.subst_identity() &variants,
.is_sized(tcx, param_env), def.is_enum(),
None => false, def.is_unsafe_cell(),
} tcx.layout_scalar_valid_range(def.did()),
}, get_discriminant_type,
) discriminants_iter(),
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?, dont_niche_optimize_enum,
) !maybe_unsized,
) else {
return Err(error(cx, LayoutError::SizeOverflow(ty)));
};
tcx.mk_layout(layout)
} }
// Types with no meaningful known layout. // Types with no meaningful known layout.