1use std::fmt;
2use std::ops::Deref;
3
4use rustc_data_structures::intern::Interned;
5use rustc_macros::HashStable_Generic;
6
7use crate::{
8 AbiAndPrefAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
9 PointeeInfo, Primitive, Scalar, Size, TargetDataLayout, Variants,
10};
11
12rustc_index::newtype_index! {
15 #[derive(HashStable_Generic)]
37 #[encodable]
38 #[orderable]
39 pub struct FieldIdx {}
40}
41
42rustc_index::newtype_index! {
43 #[derive(HashStable_Generic)]
54 #[encodable]
55 #[orderable]
56 pub struct VariantIdx {
57 const FIRST_VARIANT = 0;
59 }
60}
61#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
62#[rustc_pass_by_value]
63pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
64
65impl<'a> fmt::Debug for Layout<'a> {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 self.0.0.fmt(f)
69 }
70}
71
72impl<'a> Deref for Layout<'a> {
73 type Target = &'a LayoutData<FieldIdx, VariantIdx>;
74 fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
75 &self.0.0
76 }
77}
78
79impl<'a> Layout<'a> {
80 pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
81 &self.0.0.fields
82 }
83
84 pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
85 &self.0.0.variants
86 }
87
88 pub fn backend_repr(self) -> BackendRepr {
89 self.0.0.backend_repr
90 }
91
92 pub fn largest_niche(self) -> Option<Niche> {
93 self.0.0.largest_niche
94 }
95
96 pub fn align(self) -> AbiAndPrefAlign {
97 self.0.0.align
98 }
99
100 pub fn size(self) -> Size {
101 self.0.0.size
102 }
103
104 pub fn max_repr_align(self) -> Option<Align> {
105 self.0.0.max_repr_align
106 }
107
108 pub fn unadjusted_abi_align(self) -> Align {
109 self.0.0.unadjusted_abi_align
110 }
111
112 pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
117 self.size() == data_layout.pointer_size
118 && self.align().abi == data_layout.pointer_align.abi
119 && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. }))
120 }
121}
122
123#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
131pub struct TyAndLayout<'a, Ty> {
132 pub ty: Ty,
133 pub layout: Layout<'a>,
134}
135
136impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_struct("TyAndLayout")
140 .field("ty", &format_args!("{}", self.ty))
141 .field("layout", &self.layout)
142 .finish()
143 }
144}
145
146impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
147 type Target = &'a LayoutData<FieldIdx, VariantIdx>;
148 fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
149 &self.layout.0.0
150 }
151}
152
153pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
156 fn ty_and_layout_for_variant(
157 this: TyAndLayout<'a, Self>,
158 cx: &C,
159 variant_index: VariantIdx,
160 ) -> TyAndLayout<'a, Self>;
161 fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
162 fn ty_and_layout_pointee_info_at(
163 this: TyAndLayout<'a, Self>,
164 cx: &C,
165 offset: Size,
166 ) -> Option<PointeeInfo>;
167 fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
168 fn is_never(this: TyAndLayout<'a, Self>) -> bool;
169 fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
170 fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
171 fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
172}
173
174impl<'a, Ty> TyAndLayout<'a, Ty> {
175 pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
176 where
177 Ty: TyAbiInterface<'a, C>,
178 {
179 Ty::ty_and_layout_for_variant(self, cx, variant_index)
180 }
181
182 pub fn field<C>(self, cx: &C, i: usize) -> Self
183 where
184 Ty: TyAbiInterface<'a, C>,
185 {
186 Ty::ty_and_layout_field(self, cx, i)
187 }
188
189 pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
190 where
191 Ty: TyAbiInterface<'a, C>,
192 {
193 Ty::ty_and_layout_pointee_info_at(self, cx, offset)
194 }
195
196 pub fn is_single_fp_element<C>(self, cx: &C) -> bool
197 where
198 Ty: TyAbiInterface<'a, C>,
199 C: HasDataLayout,
200 {
201 match self.backend_repr {
202 BackendRepr::Scalar(scalar) => {
203 matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64))
204 }
205 BackendRepr::Memory { .. } => {
206 if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
207 self.field(cx, 0).is_single_fp_element(cx)
208 } else {
209 false
210 }
211 }
212 _ => false,
213 }
214 }
215
216 pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
217 where
218 Ty: TyAbiInterface<'a, C>,
219 C: HasDataLayout,
220 {
221 match self.backend_repr {
222 BackendRepr::Vector { .. } => self.size == expected_size,
223 BackendRepr::Memory { .. } => {
224 if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
225 self.field(cx, 0).is_single_vector_element(cx, expected_size)
226 } else {
227 false
228 }
229 }
230 _ => false,
231 }
232 }
233
234 pub fn is_adt<C>(self) -> bool
235 where
236 Ty: TyAbiInterface<'a, C>,
237 {
238 Ty::is_adt(self)
239 }
240
241 pub fn is_never<C>(self) -> bool
242 where
243 Ty: TyAbiInterface<'a, C>,
244 {
245 Ty::is_never(self)
246 }
247
248 pub fn is_tuple<C>(self) -> bool
249 where
250 Ty: TyAbiInterface<'a, C>,
251 {
252 Ty::is_tuple(self)
253 }
254
255 pub fn is_unit<C>(self) -> bool
256 where
257 Ty: TyAbiInterface<'a, C>,
258 {
259 Ty::is_unit(self)
260 }
261
262 pub fn is_transparent<C>(self) -> bool
263 where
264 Ty: TyAbiInterface<'a, C>,
265 {
266 Ty::is_transparent(self)
267 }
268
269 pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)>
272 where
273 Ty: TyAbiInterface<'a, C> + Copy,
274 {
275 let mut found = None;
276 for field_idx in 0..self.fields.count() {
277 let field = self.field(cx, field_idx);
278 if field.is_1zst() {
279 continue;
280 }
281 if found.is_some() {
282 return None;
284 }
285 found = Some((field_idx, field));
286 }
287 found
288 }
289}