1use std::fmt;
2use std::ops::{Deref, Range};
34use rustc_data_structures::intern::Interned;
5use rustc_data_structures::range_set::RangeSet;
6use rustc_macros::StableHash;
78use crate::layout::{FieldIdx, VariantIdx};
9use crate::{
10AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche, Numeric,
11PointeeInfo, Primitive, Size, Variants,
12};
1314// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
1516#[derive(#[automatically_derived]impl<'a> ::core::marker::Copy for Layout<'a> { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl<'a>
::core::clone::TrivialClone for Layout<'a> {
}
#[automatically_derived]impl<'a> ::core::clone::Clone for Layout<'a> {
#[inline]
fn clone(&self) -> Self {
let _:
::core::clone::AssertParamIsClone<Interned<'a,
LayoutData<FieldIdx, VariantIdx>>>;
*self
}
}Clone, #[automatically_derived]impl<'a> ::core::marker::StructuralPartialEq for
Layout<'a> {
}
#[automatically_derived]impl<'a> ::core::cmp::PartialEq for Layout<'a> {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]impl<'a> ::core::cmp::Eq for Layout<'a> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _:
::core::cmp::AssertParamIsEq<Interned<'a,
LayoutData<FieldIdx, VariantIdx>>>;
}
}Eq, #[automatically_derived]impl<'a> ::core::hash::Hash for Layout<'a> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash, const _: () =
{
impl<'a> ::rustc_data_structures::stable_hash::StableHash for
Layout<'a> {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
Layout(ref __binding_0) => {
{ __binding_0.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
17#[rustc_pass_by_value]
18pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
1920impl<'a> fmt::Debugfor Layout<'a> {
21fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22// See comment on `<LayoutData as Debug>::fmt` above.
23self.0.0.fmt(f)
24 }
25}
2627impl<'a> Dereffor Layout<'a> {
28type Target = &'a LayoutData<FieldIdx, VariantIdx>;
29fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
30&self.0.0
31}
32}
3334impl<'a> Layout<'a> {
35pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
36&self.0.0.fields
37 }
3839pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
40&self.0.0.variants
41 }
4243pub fn backend_repr(self) -> BackendRepr {
44self.0.0.backend_repr
45 }
4647pub fn largest_niche(self) -> Option<Niche> {
48self.0.0.largest_niche
49 }
5051pub fn align(self) -> AbiAlign {
52self.0.0.align
53 }
5455pub fn size(self) -> Size {
56self.0.0.size
57 }
5859pub fn max_repr_align(self) -> Option<Align> {
60self.0.0.max_repr_align
61 }
6263pub fn unadjusted_abi_align(self) -> Align {
64self.0.0.unadjusted_abi_align
65 }
66}
6768/// The layout of a type, alongside the type itself.
69/// Provides various type traversal APIs (e.g., recursing into fields).
70///
71/// Note that the layout is NOT guaranteed to always be identical
72/// to that obtained from `layout_of(ty)`, as we need to produce
73/// layouts for which Rust types do not exist, such as enum variants
74/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
75#[derive(#[automatically_derived]impl<'a, Ty: ::core::marker::Copy>
::core::marker::Copy for TyAndLayout<'a, Ty> {
}Copy, #[automatically_derived]impl<'a, Ty: ::core::clone::Clone>
::core::clone::Clone for TyAndLayout<'a, Ty> {
#[inline]
fn clone(&self) -> Self {
TyAndLayout {
ty: ::core::clone::Clone::clone(&self.ty),
layout: ::core::clone::Clone::clone(&self.layout),
}
}
}Clone, #[automatically_derived]impl<'a, Ty: ::core::cmp::PartialEq>
::core::marker::StructuralPartialEq for TyAndLayout<'a, Ty> {
}
#[automatically_derived]impl<'a, Ty: ::core::cmp::PartialEq>
::core::cmp::PartialEq for TyAndLayout<'a, Ty> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ty == other.ty && self.layout == other.layout
}
}PartialEq, #[automatically_derived]impl<'a, Ty: ::core::cmp::Eq> ::core::cmp::Eq for
TyAndLayout<'a, Ty> {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<Ty>;
let _: ::core::cmp::AssertParamIsEq<Layout<'a>>;
}
}Eq, #[automatically_derived]impl<'a, Ty: ::core::hash::Hash> ::core::hash::Hash
for TyAndLayout<'a, Ty> {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.ty, state);
::core::hash::Hash::hash(&self.layout, state)
}
}Hash, const _: () =
{
impl<'a, Ty> ::rustc_data_structures::stable_hash::StableHash for
TyAndLayout<'a, Ty> where
Ty: ::rustc_data_structures::stable_hash::StableHash {
#[inline]
fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
__hcx: &mut __Hcx,
__hasher:
&mut ::rustc_data_structures::stable_hash::StableHasher) {
match *self {
TyAndLayout { ty: ref __binding_0, layout: ref __binding_1 }
=> {
{ __binding_0.stable_hash(__hcx, __hasher); }
{ __binding_1.stable_hash(__hcx, __hasher); }
}
}
}
}
};StableHash)]
76pub struct TyAndLayout<'a, Ty> {
77pub ty: Ty,
78pub layout: Layout<'a>,
79}
8081impl<'a, Ty: fmt::Display> fmt::Debugfor TyAndLayout<'a, Ty> {
82fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83// Print the type in a readable way, not its debug representation.
84f.debug_struct("TyAndLayout")
85 .field("ty", &format_args!("{0}", self.ty)format_args!("{}", self.ty))
86 .field("layout", &self.layout)
87 .finish()
88 }
89}
9091impl<'a, Ty> Dereffor TyAndLayout<'a, Ty> {
92type Target = &'a LayoutData<FieldIdx, VariantIdx>;
93fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
94&self.layout.0.0
95}
96}
9798impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
99fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
100&*self.layout.0.0
101}
102}
103104/// Trait that needs to be implemented by the higher-level type representation
105/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
106pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
107fn ty_and_layout_for_variant(
108 this: TyAndLayout<'a, Self>,
109 cx: &C,
110 variant_index: VariantIdx,
111 ) -> TyAndLayout<'a, Self>;
112fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
113fn ty_and_layout_pointee_info_at(
114 this: TyAndLayout<'a, Self>,
115 cx: &C,
116 offset: Size,
117 ) -> Option<PointeeInfo>;
118fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
119fn is_enum(this: TyAndLayout<'a, Self>) -> bool;
120fn is_never(this: TyAndLayout<'a, Self>) -> bool;
121fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
122fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
123fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
124fn is_complex_number_lang_item(this: TyAndLayout<'a, Self>, cx: &C) -> bool;
125fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
126/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
127fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
128}
129130impl<'a, Ty> TyAndLayout<'a, Ty> {
131/// Synthetize a layout representing the variant-specific fields of an enum-like layout.
132 ///
133 /// Note that the resulting layout *does not* fully describes `self.ty` at that specific
134 /// variant: prefix fields (e.g. in coroutines) and tag information are lost.
135 ///
136 /// If you don't need type information about the variant's fields, prefer using
137 /// `self.layout.variants` directly.
138pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
139where
140Ty: TyAbiInterface<'a, C>,
141 {
142 Ty::ty_and_layout_for_variant(self, cx, variant_index)
143 }
144145pub fn field<C>(self, cx: &C, i: usize) -> Self
146where
147Ty: TyAbiInterface<'a, C>,
148 {
149 Ty::ty_and_layout_field(self, cx, i)
150 }
151152pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
153where
154Ty: TyAbiInterface<'a, C>,
155 {
156 Ty::ty_and_layout_pointee_info_at(self, cx, offset)
157 }
158159pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool160where
161Ty: TyAbiInterface<'a, C>,
162 C: HasDataLayout,
163 {
164match self.backend_repr {
165 BackendRepr::SimdVector { .. } => self.size == expected_size,
166 BackendRepr::Memory { .. } => {
167if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
168self.field(cx, 0).is_single_vector_element(cx, expected_size)
169 } else {
170false
171}
172 }
173_ => false,
174 }
175 }
176177pub fn is_adt<C>(self) -> bool178where
179Ty: TyAbiInterface<'a, C>,
180 {
181 Ty::is_adt(self)
182 }
183184pub fn is_enum<C>(self) -> bool185where
186Ty: TyAbiInterface<'a, C>,
187 {
188 Ty::is_enum(self)
189 }
190191pub fn is_never<C>(self) -> bool192where
193Ty: TyAbiInterface<'a, C>,
194 {
195 Ty::is_never(self)
196 }
197198pub fn is_tuple<C>(self) -> bool199where
200Ty: TyAbiInterface<'a, C>,
201 {
202 Ty::is_tuple(self)
203 }
204205pub fn is_unit<C>(self) -> bool206where
207Ty: TyAbiInterface<'a, C>,
208 {
209 Ty::is_unit(self)
210 }
211212pub fn is_transparent<C>(self) -> bool213where
214Ty: TyAbiInterface<'a, C>,
215 {
216 Ty::is_transparent(self)
217 }
218219/// Returns `true` if this type needs to match the ABI of the C `_Complex` type. See
220 /// [`TyAndLayout::complex_number`] for details.
221pub fn is_complex_number<C>(self, cx: &C) -> bool222where
223Ty: TyAbiInterface<'a, C> + Copy,
224 {
225self.complex_number(cx).is_some()
226 }
227228pub fn is_scalable_vector<C>(self) -> bool229where
230Ty: TyAbiInterface<'a, C>,
231 {
232 Ty::is_scalable_vector(self)
233 }
234235/// If this method returns `true`, then this type should always have a `PassMode` of
236 /// `Indirect { mode: IndirectMode::Pointer, .. }` when being used as the argument type of a
237 /// function with a non-Rustic ABI (this is true for structs annotated with the
238 /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute).
239 ///
240 /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike
241 /// C any changes the caller makes to the passed value will not be reflected in the callee, so
242 /// the attribute is only useful for types where observing the value in the caller after the
243 /// function call isn't allowed (a.k.a. `va_list`).
244 ///
245 /// This function handles transparent types automatically.
246pub fn pass_indirectly_in_non_rustic_abis<C>(self, cx: &C) -> bool247where
248Ty: TyAbiInterface<'a, C> + Copy,
249 {
250// FIXME: Peeling the wrappers above would not work correctly if we are a 1-ZST. So we make
251 // `#[rustc_pass_indirectly_in_non_rustic_abis]` a NOP on 1-ZST. In the future,
252 // `non_1zst_field` should become `non_trivial_abi_field` and
253 // `#[rustc_pass_indirectly_in_non_rustic_abis]` should make a type have non-trivial ABI.
254if self.is_1zst() {
255return false;
256 }
257258let base = self.peel_transparent_wrappers_from_non_1zst(cx);
259 Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base)
260 }
261262/// Recursively peel away transparent wrappers, returning the inner value.
263 /// Will not peel anything if `self` is a 1-ZST! Callers need to either check
264 /// that the result is not a 1-ZST, or have separate logic for that.
265 ///
266 /// The return value is not `repr(transparent)` and/or does
267 /// not have a non-1zst field.
268pub fn peel_transparent_wrappers_from_non_1zst<C>(mut self, cx: &C) -> Self
269where
270Ty: TyAbiInterface<'a, C> + Copy,
271 {
272while self.is_transparent()
273 && let Some((_, field)) = self.non_1zst_field(cx)
274 {
275self = field;
276 }
277278self279 }
280281/// Finds the one field that is not a 1-ZST.
282 /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
283pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
284where
285Ty: TyAbiInterface<'a, C> + Copy,
286 {
287let mut found = None;
288for field_idx in 0..self.fields.count() {
289let field = self.field(cx, field_idx);
290if field.is_1zst() {
291continue;
292 }
293if found.is_some() {
294// More than one non-1-ZST field.
295return None;
296 }
297 found = Some((FieldIdx::from_usize(field_idx), field));
298 }
299found300 }
301302/// Finds the one field that is not a ZST.
303 /// Returns `None` if there are multiple non-ZST fields or only ZST-fields.
304 ///
305 /// Note that this function checks for ZSTs, not just 1-ZSTs.
306pub fn non_zst_field_ignore_alignment<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
307where
308Ty: TyAbiInterface<'a, C> + Copy,
309 {
310let mut found = None;
311for field_idx in 0..self.fields.count() {
312let field = self.field(cx, field_idx);
313if field.is_zst() {
314continue;
315 }
316if found.is_some() {
317// More than one non-ZST field.
318return None;
319 }
320 found = Some((FieldIdx::from_usize(field_idx), field));
321 }
322found323 }
324325/// If this type should match the ABI of the C `_Complex` type, returns the primitive that is
326 /// used for its components.
327 ///
328 /// This function only returns `Some(T)` for `core::num::Complex<T>` where `T` is
329 /// either a float or an integer. `repr(transparent)` wrapper types are automatically handled.
330pub fn complex_number<C>(&self, cx: &C) -> Option<Numeric>
331where
332Ty: TyAbiInterface<'a, C> + Copy,
333 {
334// We're checking for scalar repr below which excludes 1-ZST.
335let complex = self.peel_transparent_wrappers_from_non_1zst(cx);
336if !Ty::is_complex_number_lang_item(complex, cx) {
337return None;
338 }
339340let component = complex.field(cx, 0).peel_transparent_wrappers_from_non_1zst(cx);
341342let BackendRepr::Scalar(scalar) = component.backend_repr else {
343return None;
344 };
345346// Only Complex<{ float }> and Complex<{ integer }> have special layout.
347 //
348 // Explicitly spell out all the float types so that any new ones have to be added to
349 // one of the match branches.
350let primitive = scalar.primitive();
351match primitive {
352 Primitive::Int(integer, is_signed) => Some(Numeric::Int(integer, is_signed)),
353 Primitive::Float(
354 float @ (Float::F16 | Float::F32 | Float::F64 | Float::F128 | Float::PpcF128),
355 ) => Some(Numeric::Float(float)),
356 Primitive::Pointer(..) | Primitive::Float(Float::F16B) => None,
357 }
358 }
359360/// Returns `Some` if this type has the ABI of the C `_Complex` type with float components.
361 /// See [`TyAndLayout::complex_number`] for details.
362pub fn complex_float<C>(&self, cx: &C) -> Option<Float>
363where
364Ty: TyAbiInterface<'a, C> + Copy,
365 {
366match self.complex_number(cx) {
367Some(Numeric::Float(float)) => Some(float),
368_ => None,
369 }
370 }
371372/// Whether this type/layout has any padding that is dependent on a variant, i.e. has bytes that
373 /// are padding for some, but not all, valid values of this type.
374pub fn has_variant_dependent_padding<C>(&self, cx: &C) -> bool375where
376Ty: TyAbiInterface<'a, C> + Copy,
377 {
378match self.variants {
379 Variants::Multiple { .. } => true,
380 Variants::Empty => false,
381 Variants::Single { .. } => match &self.fields {
382 FieldsShape::Primitive | FieldsShape::Union(_) => false,
383 FieldsShape::Array { count, .. } => {
384*count > 0 && self.field(cx, 0).has_variant_dependent_padding(cx)
385 }
386 FieldsShape::Arbitrary { offsets, .. } => {
387 (0..offsets.len()).any(|i| self.field(cx, i).has_variant_dependent_padding(cx))
388 }
389 },
390 }
391 }
392393/// The ranges of bytes that are always ignored by the representation relation of this type.
394 ///
395 /// In other words, for any sequence of bytes, if we reset the these padding bytes to uninit,
396 /// then these two sequences of bytes represent the same value (or they are both invalid).
397 /// This is the "guaranteed" padding. There may be more bytes that are padding for some
398 /// but not all variants of this type; those are not included.
399 /// (E.g. `Option<i8>` has no guaranteed padding so the empty range set is returned, but its `None` value still has padding).
400pub fn variant_independent_padding_ranges<C>(&self, cx: &C) -> Vec<Range<Size>>
401where
402Ty: TyAbiInterface<'a, C> + Copy,
403 {
404let mut data = RangeSet::new();
405self.add_data_ranges(cx, Size::ZERO, &mut data);
406407// Find gaps between the data ranges.
408let mut uninit_ranges = Vec::new();
409let mut covered_until = Size::ZERO;
410for &(offset, size) in data.0.iter() {
411if offset > covered_until {
412 uninit_ranges.push(covered_until..offset);
413 }
414 covered_until = Ord::max(covered_until, offset + size);
415 }
416417// Add trailing padding.
418if self.size > covered_until {
419uninit_ranges.push(covered_until..self.size);
420 }
421422uninit_ranges423 }
424425/// The ranges of bytes that are ignored by the representation relation of this variant.
426 ///
427 /// The result does not include variant-independent padding.
428pub fn variant_dependent_padding_ranges<C>(
429&self,
430 cx: &C,
431 variant_index: VariantIdx,
432 ) -> Vec<Range<Size>>
433where
434Ty: TyAbiInterface<'a, C> + Copy,
435 {
436let Variants::Multiple { .. } = self.variants else {
437return Vec::new();
438 };
439440// Bytes that are data in some variant.
441let mut any = RangeSet::new();
442self.add_data_ranges(cx, Size::ZERO, &mut any);
443444// Bytes that are data in this variant.
445let mut this = RangeSet::new();
446447// The variants do not contain e.g. the discriminant or coroutine upvars.
448let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else {
449{
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("a multi-variant layout should have `Arbitrary` fields")));
}unreachable!("a multi-variant layout should have `Arbitrary` fields")450 };
451452// So add them explicitly.
453for (field, &offset) in offsets.iter_enumerated() {
454let field = self.field(cx, field.as_usize());
455 field.add_data_ranges(cx, offset, &mut this);
456 }
457458self.for_variant(cx, variant_index).add_data_ranges(cx, Size::ZERO, &mut this);
459460// Padding specific to this variant: data in some variant, but not in this one.
461any.difference(&this).0.iter().map(|&(offset, size)| offset..offset + size).collect()
462 }
463464/// Extend `out` with all ranges of bytes that *may* carry relevant data for values of this type.
465 /// For enums and unions there are offsets that are initialized for some
466 /// variants but not for others; those offset *will* get added to `out`.
467fn add_data_ranges<C>(self, cx: &C, base_offset: Size, out: &mut RangeSet<Size>)
468where
469Ty: TyAbiInterface<'a, C> + Copy,
470 {
471if self.is_zst() {
472return;
473 }
474475// Visit the fields of this value. For enum values the fields include the discriminant.
476match &self.fields {
477 FieldsShape::Primitive => {
478out.add_range(base_offset, self.size);
479 }
480&FieldsShape::Union(field_count) => {
481for field in 0..field_count.get() {
482let field = self.field(cx, field);
483 field.add_data_ranges(cx, base_offset, out);
484 }
485 }
486&FieldsShape::Array { stride, count } => {
487let elem = self.field(cx, 0);
488489// For scalars we know there is no padding between the elements,
490 // so the entire array is a single big data range.
491if elem.backend_repr.is_scalar() {
492out.add_range(base_offset, elem.size * count);
493 } else {
494// FIXME: this is really inefficient for large arrays.
495for idx in 0..count {
496 elem.add_data_ranges(cx, base_offset + idx * stride, out);
497 }
498 }
499 }
500 FieldsShape::Arbitrary { offsets, in_memory_order: _ } => {
501for (field, &offset) in offsets.iter_enumerated() {
502let field = self.field(cx, field.as_usize());
503 field.add_data_ranges(cx, base_offset + offset, out);
504 }
505 }
506 }
507508// Visit the fields of each variant.
509match &self.variants {
510 Variants::Empty | Variants::Single { index: _ } => { /* done */ }
511 Variants::Multiple { variants, .. } => {
512for variant in variants.indices() {
513let variant = self.for_variant(cx, variant);
514 variant.add_data_ranges(cx, base_offset, out);
515 }
516 }
517 }
518 }
519}