Skip to content

Commit 8facfb2

Browse files
Extract fn layout_of_struct
1 parent b525f76 commit 8facfb2

File tree

1 file changed

+130
-102
lines changed

1 file changed

+130
-102
lines changed

compiler/rustc_abi/src/layout.rs

+130-102
Original file line numberDiff line numberDiff line change
@@ -197,109 +197,37 @@ pub trait LayoutCalculator {
197197
None => VariantIdx::new(0),
198198
};
199199

200-
let is_struct = !is_enum ||
201-
// Only one variant is present.
202-
(present_second.is_none() &&
203-
// Representation optimizations are allowed.
204-
!repr.inhibit_enum_layout_opt());
205-
if is_struct {
206-
// Struct, or univariant enum equivalent to a struct.
207-
// (Typechecking will reject discriminant-sizing attrs.)
208-
209-
let v = present_first;
210-
let kind = if is_enum || variants[v].is_empty() || always_sized {
211-
StructKind::AlwaysSized
212-
} else {
213-
StructKind::MaybeUnsized
214-
};
215-
216-
let mut st = self.univariant(dl, &variants[v], repr, kind)?;
217-
st.variants = Variants::Single { index: v };
218-
219-
if is_unsafe_cell {
220-
let hide_niches = |scalar: &mut _| match scalar {
221-
Scalar::Initialized { value, valid_range } => {
222-
*valid_range = WrappingRange::full(value.size(dl))
223-
}
224-
// Already doesn't have any niches
225-
Scalar::Union { .. } => {}
226-
};
227-
match &mut st.abi {
228-
Abi::Uninhabited => {}
229-
Abi::Scalar(scalar) => hide_niches(scalar),
230-
Abi::ScalarPair(a, b) => {
231-
hide_niches(a);
232-
hide_niches(b);
233-
}
234-
Abi::Vector { element, count: _ } => hide_niches(element),
235-
Abi::Aggregate { sized: _ } => {}
236-
}
237-
st.largest_niche = None;
238-
return Some(st);
239-
}
240-
241-
let (start, end) = scalar_valid_range;
242-
match st.abi {
243-
Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
244-
// Enlarging validity ranges would result in missed
245-
// optimizations, *not* wrongly assuming the inner
246-
// value is valid. e.g. unions already enlarge validity ranges,
247-
// because the values may be uninitialized.
248-
//
249-
// Because of that we only check that the start and end
250-
// of the range is representable with this scalar type.
251-
252-
let max_value = scalar.size(dl).unsigned_int_max();
253-
if let Bound::Included(start) = start {
254-
// FIXME(eddyb) this might be incorrect - it doesn't
255-
// account for wrap-around (end < start) ranges.
256-
assert!(start <= max_value, "{start} > {max_value}");
257-
scalar.valid_range_mut().start = start;
258-
}
259-
if let Bound::Included(end) = end {
260-
// FIXME(eddyb) this might be incorrect - it doesn't
261-
// account for wrap-around (end < start) ranges.
262-
assert!(end <= max_value, "{end} > {max_value}");
263-
scalar.valid_range_mut().end = end;
264-
}
265-
266-
// Update `largest_niche` if we have introduced a larger niche.
267-
let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
268-
if let Some(niche) = niche {
269-
match st.largest_niche {
270-
Some(largest_niche) => {
271-
// Replace the existing niche even if they're equal,
272-
// because this one is at a lower offset.
273-
if largest_niche.available(dl) <= niche.available(dl) {
274-
st.largest_niche = Some(niche);
275-
}
276-
}
277-
None => st.largest_niche = Some(niche),
278-
}
279-
}
280-
}
281-
_ => assert!(
282-
start == Bound::Unbounded && end == Bound::Unbounded,
283-
"nonscalar layout for layout_scalar_valid_range type: {st:#?}",
284-
),
285-
}
286-
287-
return Some(st);
200+
// take the struct path if it is an actual struct
201+
if !is_enum ||
202+
// or for optimizing univariant enums
203+
(present_second.is_none() && !repr.inhibit_enum_layout_opt())
204+
{
205+
layout_of_struct(
206+
self,
207+
repr,
208+
variants,
209+
is_enum,
210+
is_unsafe_cell,
211+
scalar_valid_range,
212+
always_sized,
213+
dl,
214+
present_first,
215+
)
216+
} else {
217+
// At this point, we have handled all unions and
218+
// structs. (We have also handled univariant enums
219+
// that allow representation optimization.)
220+
assert!(is_enum);
221+
layout_of_enum(
222+
self,
223+
repr,
224+
variants,
225+
discr_range_of_repr,
226+
discriminants,
227+
dont_niche_optimize_enum,
228+
dl,
229+
)
288230
}
289-
290-
// At this point, we have handled all unions and
291-
// structs. (We have also handled univariant enums
292-
// that allow representation optimization.)
293-
assert!(is_enum);
294-
layout_of_enum(
295-
self,
296-
repr,
297-
variants,
298-
discr_range_of_repr,
299-
discriminants,
300-
dont_niche_optimize_enum,
301-
dl,
302-
)
303231
}
304232

305233
fn layout_of_union<
@@ -407,6 +335,106 @@ pub trait LayoutCalculator {
407335
}
408336
}
409337

338+
/// single-variant enums are just structs, if you think about it
339+
fn layout_of_struct<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>(
340+
layout_calc: &LC,
341+
repr: &ReprOptions,
342+
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
343+
is_enum: bool,
344+
is_unsafe_cell: bool,
345+
scalar_valid_range: (Bound<u128>, Bound<u128>),
346+
always_sized: bool,
347+
dl: &TargetDataLayout,
348+
present_first: VariantIdx,
349+
) -> Option<LayoutS<FieldIdx, VariantIdx>>
350+
where
351+
LC: LayoutCalculator + ?Sized,
352+
F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
353+
{
354+
// Struct, or univariant enum equivalent to a struct.
355+
// (Typechecking will reject discriminant-sizing attrs.)
356+
357+
let v = present_first;
358+
let kind = if is_enum || variants[v].is_empty() || always_sized {
359+
StructKind::AlwaysSized
360+
} else {
361+
StructKind::MaybeUnsized
362+
};
363+
364+
let mut st = layout_calc.univariant(dl, &variants[v], repr, kind)?;
365+
st.variants = Variants::Single { index: v };
366+
367+
if is_unsafe_cell {
368+
let hide_niches = |scalar: &mut _| match scalar {
369+
Scalar::Initialized { value, valid_range } => {
370+
*valid_range = WrappingRange::full(value.size(dl))
371+
}
372+
// Already doesn't have any niches
373+
Scalar::Union { .. } => {}
374+
};
375+
match &mut st.abi {
376+
Abi::Uninhabited => {}
377+
Abi::Scalar(scalar) => hide_niches(scalar),
378+
Abi::ScalarPair(a, b) => {
379+
hide_niches(a);
380+
hide_niches(b);
381+
}
382+
Abi::Vector { element, count: _ } => hide_niches(element),
383+
Abi::Aggregate { sized: _ } => {}
384+
}
385+
st.largest_niche = None;
386+
return Some(st);
387+
}
388+
389+
let (start, end) = scalar_valid_range;
390+
match st.abi {
391+
Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
392+
// Enlarging validity ranges would result in missed
393+
// optimizations, *not* wrongly assuming the inner
394+
// value is valid. e.g. unions already enlarge validity ranges,
395+
// because the values may be uninitialized.
396+
//
397+
// Because of that we only check that the start and end
398+
// of the range is representable with this scalar type.
399+
400+
let max_value = scalar.size(dl).unsigned_int_max();
401+
if let Bound::Included(start) = start {
402+
// FIXME(eddyb) this might be incorrect - it doesn't
403+
// account for wrap-around (end < start) ranges.
404+
assert!(start <= max_value, "{start} > {max_value}");
405+
scalar.valid_range_mut().start = start;
406+
}
407+
if let Bound::Included(end) = end {
408+
// FIXME(eddyb) this might be incorrect - it doesn't
409+
// account for wrap-around (end < start) ranges.
410+
assert!(end <= max_value, "{end} > {max_value}");
411+
scalar.valid_range_mut().end = end;
412+
}
413+
414+
// Update `largest_niche` if we have introduced a larger niche.
415+
let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
416+
if let Some(niche) = niche {
417+
match st.largest_niche {
418+
Some(largest_niche) => {
419+
// Replace the existing niche even if they're equal,
420+
// because this one is at a lower offset.
421+
if largest_niche.available(dl) <= niche.available(dl) {
422+
st.largest_niche = Some(niche);
423+
}
424+
}
425+
None => st.largest_niche = Some(niche),
426+
}
427+
}
428+
}
429+
_ => assert!(
430+
start == Bound::Unbounded && end == Bound::Unbounded,
431+
"nonscalar layout for layout_scalar_valid_range type: {st:#?}",
432+
),
433+
}
434+
435+
Some(st)
436+
}
437+
410438
fn layout_of_enum<'a, LC, FieldIdx: Idx, VariantIdx: Idx, F>(
411439
layout_calc: &LC,
412440
repr: &ReprOptions,

0 commit comments

Comments
 (0)