Skip to content

Commit cc7593a

Browse files
committed
Remove most manual LayoutData creations and move them to rustc_abi
...either as: - methods on LayoutCalculator, for faillible operations; - constructors on LayoutData, for infaillible ones.
1 parent 91a0e16 commit cc7593a

File tree

5 files changed

+172
-224
lines changed

5 files changed

+172
-224
lines changed

compiler/rustc_abi/src/layout.rs

+21-52
Original file line numberDiff line numberDiff line change
@@ -102,41 +102,27 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
102102
Self { cx }
103103
}
104104

105-
pub fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(
105+
pub fn array<FieldIdx: Idx, VariantIdx: Idx, F>(
106106
&self,
107-
a: Scalar,
108-
b: Scalar,
109-
) -> LayoutData<FieldIdx, VariantIdx> {
110-
let dl = self.cx.data_layout();
111-
let b_align = b.align(dl);
112-
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
113-
let b_offset = a.size(dl).align_to(b_align.abi);
114-
let size = (b_offset + b.size(dl)).align_to(align.abi);
115-
116-
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
117-
// returns the last maximum.
118-
let largest_niche = Niche::from_scalar(dl, b_offset, b)
119-
.into_iter()
120-
.chain(Niche::from_scalar(dl, Size::ZERO, a))
121-
.max_by_key(|niche| niche.available(dl));
122-
123-
let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes());
107+
element: &LayoutData<FieldIdx, VariantIdx>,
108+
count_if_sized: Option<u64>, // None for slices
109+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
110+
let count = count_if_sized.unwrap_or(0);
111+
let size =
112+
element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?;
124113

125-
LayoutData {
114+
Ok(LayoutData {
126115
variants: Variants::Single { index: VariantIdx::new(0) },
127-
fields: FieldsShape::Arbitrary {
128-
offsets: [Size::ZERO, b_offset].into(),
129-
memory_index: [0, 1].into(),
130-
},
131-
backend_repr: BackendRepr::ScalarPair(a, b),
132-
largest_niche,
133-
uninhabited: false,
134-
align,
116+
fields: FieldsShape::Array { stride: element.size, count },
117+
backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() },
118+
largest_niche: element.largest_niche.filter(|_| count != 0),
119+
uninhabited: element.uninhabited && count != 0,
120+
align: element.align,
135121
size,
136122
max_repr_align: None,
137-
unadjusted_abi_align: align.abi,
138-
randomization_seed: Hash64::new(combined_seed),
139-
}
123+
unadjusted_abi_align: element.align.abi,
124+
randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)),
125+
})
140126
}
141127

142128
pub fn univariant<
@@ -214,25 +200,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
214200
layout
215201
}
216202

217-
pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>(
218-
&self,
219-
) -> LayoutData<FieldIdx, VariantIdx> {
220-
let dl = self.cx.data_layout();
221-
// This is also used for uninhabited enums, so we use `Variants::Empty`.
222-
LayoutData {
223-
variants: Variants::Empty,
224-
fields: FieldsShape::Primitive,
225-
backend_repr: BackendRepr::Memory { sized: true },
226-
largest_niche: None,
227-
uninhabited: true,
228-
align: dl.i8_align,
229-
size: Size::ZERO,
230-
max_repr_align: None,
231-
unadjusted_abi_align: dl.i8_align.abi,
232-
randomization_seed: Hash64::ZERO,
233-
}
234-
}
235-
236203
pub fn layout_of_struct_or_enum<
237204
'a,
238205
FieldIdx: Idx,
@@ -260,7 +227,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
260227
Some(present_first) => present_first,
261228
// Uninhabited because it has no variants, or only absent ones.
262229
None if is_enum => {
263-
return Ok(self.layout_of_never_type());
230+
return Ok(LayoutData::never_type(&self.cx));
264231
}
265232
// If it's a struct, still compute a layout so that we can still compute the
266233
// field offsets.
@@ -949,7 +916,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
949916
// Common prim might be uninit.
950917
Scalar::Union { value: prim }
951918
};
952-
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar);
919+
let pair =
920+
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar);
953921
let pair_offsets = match pair.fields {
954922
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
955923
assert_eq!(memory_index.raw, [0, 1]);
@@ -1341,7 +1309,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13411309
} else {
13421310
((j, b), (i, a))
13431311
};
1344-
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(a, b);
1312+
let pair =
1313+
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b);
13451314
let pair_offsets = match pair.fields {
13461315
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
13471316
assert_eq!(memory_index.raw, [0, 1]);

compiler/rustc_abi/src/lib.rs

+95
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,42 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
17451745
self.uninhabited
17461746
}
17471747

1748+
pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self {
1749+
let dl = cx.data_layout();
1750+
LayoutData {
1751+
variants: Variants::Single { index: VariantIdx::new(0) },
1752+
fields: FieldsShape::Arbitrary {
1753+
offsets: IndexVec::new(),
1754+
memory_index: IndexVec::new(),
1755+
},
1756+
backend_repr: BackendRepr::Memory { sized },
1757+
largest_niche: None,
1758+
uninhabited: false,
1759+
align: dl.i8_align,
1760+
size: Size::ZERO,
1761+
max_repr_align: None,
1762+
unadjusted_abi_align: dl.i8_align.abi,
1763+
randomization_seed: Hash64::new(0),
1764+
}
1765+
}
1766+
1767+
pub fn never_type<C: HasDataLayout>(cx: &C) -> Self {
1768+
let dl = cx.data_layout();
1769+
// This is also used for uninhabited enums, so we use `Variants::Empty`.
1770+
LayoutData {
1771+
variants: Variants::Empty,
1772+
fields: FieldsShape::Primitive,
1773+
backend_repr: BackendRepr::Memory { sized: true },
1774+
largest_niche: None,
1775+
uninhabited: true,
1776+
align: dl.i8_align,
1777+
size: Size::ZERO,
1778+
max_repr_align: None,
1779+
unadjusted_abi_align: dl.i8_align.abi,
1780+
randomization_seed: Hash64::ZERO,
1781+
}
1782+
}
1783+
17481784
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
17491785
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
17501786
let size = scalar.size(cx);
@@ -1786,6 +1822,65 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
17861822
randomization_seed: Hash64::new(randomization_seed),
17871823
}
17881824
}
1825+
1826+
pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self {
1827+
let dl = cx.data_layout();
1828+
let b_align = b.align(dl);
1829+
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
1830+
let b_offset = a.size(dl).align_to(b_align.abi);
1831+
let size = (b_offset + b.size(dl)).align_to(align.abi);
1832+
1833+
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
1834+
// returns the last maximum.
1835+
let largest_niche = Niche::from_scalar(dl, b_offset, b)
1836+
.into_iter()
1837+
.chain(Niche::from_scalar(dl, Size::ZERO, a))
1838+
.max_by_key(|niche| niche.available(dl));
1839+
1840+
let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes());
1841+
1842+
LayoutData {
1843+
variants: Variants::Single { index: VariantIdx::new(0) },
1844+
fields: FieldsShape::Arbitrary {
1845+
offsets: [Size::ZERO, b_offset].into(),
1846+
memory_index: [0, 1].into(),
1847+
},
1848+
backend_repr: BackendRepr::ScalarPair(a, b),
1849+
largest_niche,
1850+
uninhabited: false,
1851+
align,
1852+
size,
1853+
max_repr_align: None,
1854+
unadjusted_abi_align: align.abi,
1855+
randomization_seed: Hash64::new(combined_seed),
1856+
}
1857+
}
1858+
1859+
/// Returns a dummy layout for an uninhabited variant.
1860+
///
1861+
/// Uninhabited variants get pruned as part of the layout calculation,
1862+
/// so this can be used after the fact to reconstitute a layout.
1863+
pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self {
1864+
let dl = cx.data_layout();
1865+
LayoutData {
1866+
variants: Variants::Single { index },
1867+
fields: match NonZeroUsize::new(fields) {
1868+
Some(fields) => FieldsShape::Union(fields),
1869+
None => FieldsShape::Arbitrary {
1870+
offsets: IndexVec::new(),
1871+
memory_index: IndexVec::new(),
1872+
},
1873+
},
1874+
backend_repr: BackendRepr::Memory { sized: true },
1875+
largest_niche: None,
1876+
uninhabited: true,
1877+
align: dl.i8_align,
1878+
size: Size::ZERO,
1879+
max_repr_align: None,
1880+
unadjusted_abi_align: dl.i8_align.abi,
1881+
randomization_seed: Hash64::ZERO,
1882+
}
1883+
}
17891884
}
17901885

17911886
impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>

compiler/rustc_middle/src/ty/layout.rs

+12-28
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
use std::num::NonZero;
21
use std::ops::Bound;
32
use std::{cmp, fmt};
43

54
use rustc_abi::{
6-
AddressSpace, Align, BackendRepr, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData,
7-
PointeeInfo, PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
5+
AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
6+
PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
87
TyAbiInterface, VariantIdx, Variants,
98
};
109
use rustc_error_messages::DiagMessage;
1110
use rustc_errors::{
1211
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
1312
};
14-
use rustc_hashes::Hash64;
1513
use rustc_hir::LangItem;
1614
use rustc_hir::def_id::DefId;
17-
use rustc_index::IndexVec;
1815
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
1916
use rustc_session::config::OptLevel;
2017
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
@@ -762,11 +759,9 @@ where
762759
variant_index: VariantIdx,
763760
) -> TyAndLayout<'tcx> {
764761
let layout = match this.variants {
765-
Variants::Single { index }
766-
// If all variants but one are uninhabited, the variant layout is the enum layout.
767-
if index == variant_index =>
768-
{
769-
this.layout
762+
// If all variants but one are uninhabited, the variant layout is the enum layout.
763+
Variants::Single { index } if index == variant_index => {
764+
return this;
770765
}
771766

772767
Variants::Single { .. } | Variants::Empty => {
@@ -783,29 +778,18 @@ where
783778
}
784779

785780
let fields = match this.ty.kind() {
786-
ty::Adt(def, _) if def.variants().is_empty() =>
787-
bug!("for_variant called on zero-variant enum {}", this.ty),
781+
ty::Adt(def, _) if def.variants().is_empty() => {
782+
bug!("for_variant called on zero-variant enum {}", this.ty)
783+
}
788784
ty::Adt(def, _) => def.variant(variant_index).fields.len(),
789785
_ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
790786
};
791-
tcx.mk_layout(LayoutData {
792-
variants: Variants::Single { index: variant_index },
793-
fields: match NonZero::new(fields) {
794-
Some(fields) => FieldsShape::Union(fields),
795-
None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() },
796-
},
797-
backend_repr: BackendRepr::Memory { sized: true },
798-
largest_niche: None,
799-
uninhabited: true,
800-
align: tcx.data_layout.i8_align,
801-
size: Size::ZERO,
802-
max_repr_align: None,
803-
unadjusted_abi_align: tcx.data_layout.i8_align.abi,
804-
randomization_seed: Hash64::ZERO,
805-
})
787+
tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields))
806788
}
807789

808-
Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()),
790+
Variants::Multiple { ref variants, .. } => {
791+
cx.tcx().mk_layout(variants[variant_index].clone())
792+
}
809793
};
810794

811795
assert_eq!(*layout.variants(), Variants::Single { index: variant_index });

0 commit comments

Comments
 (0)