Skip to content

Commit 9917173

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 cdd8af2 commit 9917173

File tree

6 files changed

+228
-267
lines changed

6 files changed

+228
-267
lines changed

compiler/rustc_abi/src/layout.rs

+23-52
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use crate::{
1212
Variants, WrappingRange,
1313
};
1414

15+
mod simple;
16+
1517
#[cfg(feature = "nightly")]
1618
mod ty;
1719

@@ -102,41 +104,27 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
102104
Self { cx }
103105
}
104106

105-
pub fn scalar_pair<FieldIdx: Idx, VariantIdx: Idx>(
107+
pub fn array_like<FieldIdx: Idx, VariantIdx: Idx, F>(
106108
&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());
109+
element: &LayoutData<FieldIdx, VariantIdx>,
110+
count_if_sized: Option<u64>, // None for slices
111+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
112+
let count = count_if_sized.unwrap_or(0);
113+
let size =
114+
element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?;
124115

125-
LayoutData {
116+
Ok(LayoutData {
126117
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,
118+
fields: FieldsShape::Array { stride: element.size, count },
119+
backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() },
120+
largest_niche: element.largest_niche.filter(|_| count != 0),
121+
uninhabited: element.uninhabited && count != 0,
122+
align: element.align,
135123
size,
136124
max_repr_align: None,
137-
unadjusted_abi_align: align.abi,
138-
randomization_seed: Hash64::new(combined_seed),
139-
}
125+
unadjusted_abi_align: element.align.abi,
126+
randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)),
127+
})
140128
}
141129

142130
pub fn univariant<
@@ -214,25 +202,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
214202
layout
215203
}
216204

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-
236205
pub fn layout_of_struct_or_enum<
237206
'a,
238207
FieldIdx: Idx,
@@ -260,7 +229,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
260229
Some(present_first) => present_first,
261230
// Uninhabited because it has no variants, or only absent ones.
262231
None if is_enum => {
263-
return Ok(self.layout_of_never_type());
232+
return Ok(LayoutData::never_type(&self.cx));
264233
}
265234
// If it's a struct, still compute a layout so that we can still compute the
266235
// field offsets.
@@ -949,7 +918,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
949918
// Common prim might be uninit.
950919
Scalar::Union { value: prim }
951920
};
952-
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(tag, prim_scalar);
921+
let pair =
922+
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, tag, prim_scalar);
953923
let pair_offsets = match pair.fields {
954924
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
955925
assert_eq!(memory_index.raw, [0, 1]);
@@ -1341,7 +1311,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13411311
} else {
13421312
((j, b), (i, a))
13431313
};
1344-
let pair = self.scalar_pair::<FieldIdx, VariantIdx>(a, b);
1314+
let pair =
1315+
LayoutData::<FieldIdx, VariantIdx>::scalar_pair(&self.cx, a, b);
13451316
let pair_offsets = match pair.fields {
13461317
FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
13471318
assert_eq!(memory_index.raw, [0, 1]);
+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use std::num::NonZero;
2+
3+
use rustc_hashes::Hash64;
4+
use rustc_index::{Idx, IndexVec};
5+
6+
use crate::{
7+
BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants,
8+
};
9+
10+
/// "Simple" layout constructors that cannot fail.
11+
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
12+
pub fn unit<C: HasDataLayout>(cx: &C, sized: bool) -> Self {
13+
let dl = cx.data_layout();
14+
LayoutData {
15+
variants: Variants::Single { index: VariantIdx::new(0) },
16+
fields: FieldsShape::Arbitrary {
17+
offsets: IndexVec::new(),
18+
memory_index: IndexVec::new(),
19+
},
20+
backend_repr: BackendRepr::Memory { sized },
21+
largest_niche: None,
22+
uninhabited: false,
23+
align: dl.i8_align,
24+
size: Size::ZERO,
25+
max_repr_align: None,
26+
unadjusted_abi_align: dl.i8_align.abi,
27+
randomization_seed: Hash64::new(0),
28+
}
29+
}
30+
31+
pub fn never_type<C: HasDataLayout>(cx: &C) -> Self {
32+
let dl = cx.data_layout();
33+
// This is also used for uninhabited enums, so we use `Variants::Empty`.
34+
LayoutData {
35+
variants: Variants::Empty,
36+
fields: FieldsShape::Primitive,
37+
backend_repr: BackendRepr::Memory { sized: true },
38+
largest_niche: None,
39+
uninhabited: true,
40+
align: dl.i8_align,
41+
size: Size::ZERO,
42+
max_repr_align: None,
43+
unadjusted_abi_align: dl.i8_align.abi,
44+
randomization_seed: Hash64::ZERO,
45+
}
46+
}
47+
48+
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
49+
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
50+
let size = scalar.size(cx);
51+
let align = scalar.align(cx);
52+
53+
let range = scalar.valid_range(cx);
54+
55+
// All primitive types for which we don't have subtype coercions should get a distinct seed,
56+
// so that types wrapping them can use randomization to arrive at distinct layouts.
57+
//
58+
// Some type information is already lost at this point, so as an approximation we derive
59+
// the seed from what remains. For example on 64-bit targets usize and u64 can no longer
60+
// be distinguished.
61+
let randomization_seed = size
62+
.bytes()
63+
.wrapping_add(
64+
match scalar.primitive() {
65+
Primitive::Int(_, true) => 1,
66+
Primitive::Int(_, false) => 2,
67+
Primitive::Float(_) => 3,
68+
Primitive::Pointer(_) => 4,
69+
} << 32,
70+
)
71+
// distinguishes references from pointers
72+
.wrapping_add((range.start as u64).rotate_right(16))
73+
// distinguishes char from u32 and bool from u8
74+
.wrapping_add((range.end as u64).rotate_right(16));
75+
76+
LayoutData {
77+
variants: Variants::Single { index: VariantIdx::new(0) },
78+
fields: FieldsShape::Primitive,
79+
backend_repr: BackendRepr::Scalar(scalar),
80+
largest_niche,
81+
uninhabited: false,
82+
size,
83+
align,
84+
max_repr_align: None,
85+
unadjusted_abi_align: align.abi,
86+
randomization_seed: Hash64::new(randomization_seed),
87+
}
88+
}
89+
90+
pub fn scalar_pair<C: HasDataLayout>(cx: &C, a: Scalar, b: Scalar) -> Self {
91+
let dl = cx.data_layout();
92+
let b_align = b.align(dl);
93+
let align = a.align(dl).max(b_align).max(dl.aggregate_align);
94+
let b_offset = a.size(dl).align_to(b_align.abi);
95+
let size = (b_offset + b.size(dl)).align_to(align.abi);
96+
97+
// HACK(nox): We iter on `b` and then `a` because `max_by_key`
98+
// returns the last maximum.
99+
let largest_niche = Niche::from_scalar(dl, b_offset, b)
100+
.into_iter()
101+
.chain(Niche::from_scalar(dl, Size::ZERO, a))
102+
.max_by_key(|niche| niche.available(dl));
103+
104+
let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes());
105+
106+
LayoutData {
107+
variants: Variants::Single { index: VariantIdx::new(0) },
108+
fields: FieldsShape::Arbitrary {
109+
offsets: [Size::ZERO, b_offset].into(),
110+
memory_index: [0, 1].into(),
111+
},
112+
backend_repr: BackendRepr::ScalarPair(a, b),
113+
largest_niche,
114+
uninhabited: false,
115+
align,
116+
size,
117+
max_repr_align: None,
118+
unadjusted_abi_align: align.abi,
119+
randomization_seed: Hash64::new(combined_seed),
120+
}
121+
}
122+
123+
/// Returns a dummy layout for an uninhabited variant.
124+
///
125+
/// Uninhabited variants get pruned as part of the layout calculation,
126+
/// so this can be used after the fact to reconstitute a layout.
127+
pub fn uninhabited_variant<C: HasDataLayout>(cx: &C, index: VariantIdx, fields: usize) -> Self {
128+
let dl = cx.data_layout();
129+
LayoutData {
130+
variants: Variants::Single { index },
131+
fields: match NonZero::new(fields) {
132+
Some(fields) => FieldsShape::Union(fields),
133+
None => FieldsShape::Arbitrary {
134+
offsets: IndexVec::new(),
135+
memory_index: IndexVec::new(),
136+
},
137+
},
138+
backend_repr: BackendRepr::Memory { sized: true },
139+
largest_niche: None,
140+
uninhabited: true,
141+
align: dl.i8_align,
142+
size: Size::ZERO,
143+
max_repr_align: None,
144+
unadjusted_abi_align: dl.i8_align.abi,
145+
randomization_seed: Hash64::ZERO,
146+
}
147+
}
148+
}

compiler/rustc_abi/src/lib.rs

-42
Original file line numberDiff line numberDiff line change
@@ -1744,48 +1744,6 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
17441744
pub fn is_uninhabited(&self) -> bool {
17451745
self.uninhabited
17461746
}
1747-
1748-
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
1749-
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
1750-
let size = scalar.size(cx);
1751-
let align = scalar.align(cx);
1752-
1753-
let range = scalar.valid_range(cx);
1754-
1755-
// All primitive types for which we don't have subtype coercions should get a distinct seed,
1756-
// so that types wrapping them can use randomization to arrive at distinct layouts.
1757-
//
1758-
// Some type information is already lost at this point, so as an approximation we derive
1759-
// the seed from what remains. For example on 64-bit targets usize and u64 can no longer
1760-
// be distinguished.
1761-
let randomization_seed = size
1762-
.bytes()
1763-
.wrapping_add(
1764-
match scalar.primitive() {
1765-
Primitive::Int(_, true) => 1,
1766-
Primitive::Int(_, false) => 2,
1767-
Primitive::Float(_) => 3,
1768-
Primitive::Pointer(_) => 4,
1769-
} << 32,
1770-
)
1771-
// distinguishes references from pointers
1772-
.wrapping_add((range.start as u64).rotate_right(16))
1773-
// distinguishes char from u32 and bool from u8
1774-
.wrapping_add((range.end as u64).rotate_right(16));
1775-
1776-
LayoutData {
1777-
variants: Variants::Single { index: VariantIdx::new(0) },
1778-
fields: FieldsShape::Primitive,
1779-
backend_repr: BackendRepr::Scalar(scalar),
1780-
largest_niche,
1781-
uninhabited: false,
1782-
size,
1783-
align,
1784-
max_repr_align: None,
1785-
unadjusted_abi_align: align.abi,
1786-
randomization_seed: Hash64::new(randomization_seed),
1787-
}
1788-
}
17891747
}
17901748

17911749
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)