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