Skip to main content

rustc_ty_utils/
layout.rs

1use hir::def_id::DefId;
2use rustc_abi::Integer::{I8, I32};
3use rustc_abi::Primitive::{self, Float, Int, Pointer};
4use rustc_abi::{
5    AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
6    LayoutCalculatorError, LayoutData, Niche, ReprOptions, ScalableElt, Scalar, Size, StructKind,
7    TagEncoding, VariantIdx, Variants, WrappingRange,
8};
9use rustc_hashes::Hash64;
10use rustc_hir::find_attr;
11use rustc_index::{Idx as _, IndexVec};
12use rustc_middle::bug;
13use rustc_middle::query::Providers;
14use rustc_middle::traits::ObligationCause;
15use rustc_middle::ty::layout::{
16    FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout,
17};
18use rustc_middle::ty::print::with_no_trimmed_paths;
19use rustc_middle::ty::{
20    self, AdtDef, CoroutineArgsExt, EarlyBinder, PseudoCanonicalInput, Ty, TyCtxt, TypeVisitableExt,
21};
22use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
23use rustc_span::{Symbol, sym};
24use tracing::{debug, instrument};
25use {rustc_abi as abi, rustc_hir as hir};
26
27use crate::errors::NonPrimitiveSimdType;
28
29mod invariant;
30
31pub(crate) fn provide(providers: &mut Providers) {
32    *providers = Providers { layout_of, ..*providers };
33}
34
35#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("layout_of",
                                    "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                                    ::tracing_core::__macro_support::Option::Some(35u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                                    ::tracing_core::field::FieldSet::new(&[],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{ meta.fields().value_set(&[]) })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return:
                    Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            let PseudoCanonicalInput { typing_env, value: ty } = query;
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:41",
                                    "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                                    ::tracing_core::__macro_support::Option::Some(41u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                                    ::tracing_core::field::FieldSet::new(&["ty"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::DEBUG <=
                                ::tracing::level_filters::LevelFilter::current() &&
                        {
                            let interest = __CALLSITE.interest();
                            !interest.is_never() &&
                                ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                                    interest)
                        };
                if enabled {
                    (|value_set: ::tracing::field::ValueSet|
                                {
                                    let meta = __CALLSITE.metadata();
                                    ::tracing::Event::dispatch(meta, &value_set);
                                    ;
                                })({
                            #[allow(unused_imports)]
                            use ::tracing::field::{debug, display, Value};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&debug(&ty) as
                                                        &dyn Value))])
                        });
                } else { ; }
            };
            let typing_env = typing_env.with_post_analysis_normalized(tcx);
            let unnormalized_ty = ty;
            let ty =
                match tcx.try_normalize_erasing_regions(typing_env, ty) {
                    Ok(t) => t,
                    Err(normalization_error) => {
                        return Err(tcx.arena.alloc(LayoutError::NormalizationFailure(ty,
                                        normalization_error)));
                    }
                };
            if ty != unnormalized_ty {
                return tcx.layout_of(typing_env.as_query_input(ty));
            }
            let cx = LayoutCx::new(tcx, typing_env);
            let layout = layout_of_uncached(&cx, ty)?;
            let layout = TyAndLayout { ty, layout };
            if cx.tcx().sess.opts.unstable_opts.print_type_sizes {
                record_layout_for_printing(&cx, layout);
            }
            invariant::layout_sanity_check(&cx, &layout);
            Ok(layout)
        }
    }
}#[instrument(skip(tcx, query), level = "debug")]
36fn layout_of<'tcx>(
37    tcx: TyCtxt<'tcx>,
38    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
39) -> Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> {
40    let PseudoCanonicalInput { typing_env, value: ty } = query;
41    debug!(?ty);
42
43    // Optimization: We convert to TypingMode::PostAnalysis and convert opaque types in
44    // the where bounds to their hidden types. This reduces overall uncached invocations
45    // of `layout_of` and is thus a small performance improvement.
46    let typing_env = typing_env.with_post_analysis_normalized(tcx);
47    let unnormalized_ty = ty;
48
49    // FIXME: We might want to have two different versions of `layout_of`:
50    // One that can be called after typecheck has completed and can use
51    // `normalize_erasing_regions` here and another one that can be called
52    // before typecheck has completed and uses `try_normalize_erasing_regions`.
53    let ty = match tcx.try_normalize_erasing_regions(typing_env, ty) {
54        Ok(t) => t,
55        Err(normalization_error) => {
56            return Err(tcx
57                .arena
58                .alloc(LayoutError::NormalizationFailure(ty, normalization_error)));
59        }
60    };
61
62    if ty != unnormalized_ty {
63        // Ensure this layout is also cached for the normalized type.
64        return tcx.layout_of(typing_env.as_query_input(ty));
65    }
66
67    let cx = LayoutCx::new(tcx, typing_env);
68
69    let layout = layout_of_uncached(&cx, ty)?;
70    let layout = TyAndLayout { ty, layout };
71
72    // If we are running with `-Zprint-type-sizes`, maybe record layouts
73    // for dumping later.
74    if cx.tcx().sess.opts.unstable_opts.print_type_sizes {
75        record_layout_for_printing(&cx, layout);
76    }
77
78    invariant::layout_sanity_check(&cx, &layout);
79
80    Ok(layout)
81}
82
83fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> {
84    cx.tcx().arena.alloc(err)
85}
86
87fn map_error<'tcx>(
88    cx: &LayoutCx<'tcx>,
89    ty: Ty<'tcx>,
90    err: LayoutCalculatorError<TyAndLayout<'tcx>>,
91) -> &'tcx LayoutError<'tcx> {
92    let err = match err {
93        LayoutCalculatorError::SizeOverflow => {
94            // This is sometimes not a compile error in `check` builds.
95            // See `tests/ui/limits/huge-enum.rs` for an example.
96            LayoutError::SizeOverflow(ty)
97        }
98        LayoutCalculatorError::UnexpectedUnsized(field) => {
99            // This is sometimes not a compile error if there are trivially false where clauses.
100            // See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
101            if !field.layout.is_unsized() {
    {
        ::core::panicking::panic_fmt(format_args!("invalid layout error {0:#?}",
                err));
    }
};assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
102            if cx.typing_env.param_env.caller_bounds().is_empty() {
103                cx.tcx().dcx().delayed_bug(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("encountered unexpected unsized field in layout of {0:?}: {1:#?}",
                ty, field))
    })format!(
104                    "encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
105                ));
106            }
107            LayoutError::Unknown(ty)
108        }
109        LayoutCalculatorError::EmptyUnion => {
110            // This is always a compile error.
111            let guar =
112                cx.tcx().dcx().delayed_bug(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("computed layout of empty union: {0:?}",
                ty))
    })format!("computed layout of empty union: {ty:?}"));
113            LayoutError::ReferencesError(guar)
114        }
115        LayoutCalculatorError::ReprConflict => {
116            // packed enums are the only known trigger of this, but others might arise
117            let guar = cx
118                .tcx()
119                .dcx()
120                .delayed_bug(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("computed impossible repr (packed enum?): {0:?}",
                ty))
    })format!("computed impossible repr (packed enum?): {ty:?}"));
121            LayoutError::ReferencesError(guar)
122        }
123        LayoutCalculatorError::ZeroLengthSimdType => {
124            // Can't be caught in typeck if the array length is generic.
125            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength }
126        }
127        LayoutCalculatorError::OversizedSimdType { max_lanes } => {
128            // Can't be caught in typeck if the array length is generic.
129            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) }
130        }
131        LayoutCalculatorError::NonPrimitiveSimdType(field) => {
132            // This error isn't caught in typeck, e.g., if
133            // the element type of the vector is generic.
134            cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty })
135        }
136    };
137    error(cx, err)
138}
139
140fn extract_const_value<'tcx>(
141    cx: &LayoutCx<'tcx>,
142    ty: Ty<'tcx>,
143    ct: ty::Const<'tcx>,
144) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
145    match ct.kind() {
146        ty::ConstKind::Value(cv) => Ok(cv),
147        ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
148            if !ct.has_param() {
149                ::rustc_middle::util::bug::bug_fmt(format_args!("failed to normalize const, but it is not generic: {0:?}",
        ct));bug!("failed to normalize const, but it is not generic: {ct:?}");
150            }
151            Err(error(cx, LayoutError::TooGeneric(ty)))
152        }
153        ty::ConstKind::Unevaluated(_) => {
154            let err = if ct.has_param() {
155                LayoutError::TooGeneric(ty)
156            } else {
157                // This case is reachable with unsatisfiable predicates and GCE (which will
158                // cause anon consts to inherit the unsatisfiable predicates). For example
159                // if we have an unsatisfiable `u8: Trait` bound, then it's not a compile
160                // error to mention `[u8; <u8 as Trait>::CONST]`, but we can't compute its
161                // layout.
162                LayoutError::Unknown(ty)
163            };
164            Err(error(cx, err))
165        }
166        ty::ConstKind::Infer(_)
167        | ty::ConstKind::Bound(..)
168        | ty::ConstKind::Placeholder(_)
169        | ty::ConstKind::Error(_) => {
170            // `ty::ConstKind::Error` is handled at the top of `layout_of_uncached`
171            // (via `ty.error_reported()`).
172            ::rustc_middle::util::bug::bug_fmt(format_args!("layout_of: unexpected const: {0:?}",
        ct));bug!("layout_of: unexpected const: {ct:?}");
173        }
174    }
175}
176
177fn layout_of_uncached<'tcx>(
178    cx: &LayoutCx<'tcx>,
179    ty: Ty<'tcx>,
180) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
181    // Types that reference `ty::Error` pessimistically don't have a meaningful layout.
182    // The only side-effect of this is possibly worse diagnostics in case the layout
183    // was actually computable (like if the `ty::Error` showed up only in a `PhantomData`).
184    if let Err(guar) = ty.error_reported() {
185        return Err(error(cx, LayoutError::ReferencesError(guar)));
186    }
187
188    let tcx = cx.tcx();
189
190    // layout of `async_drop_in_place<T>::{closure}` in case,
191    // when T is a coroutine, contains this internal coroutine's ref
192
193    let dl = cx.data_layout();
194    let map_layout = |result: Result<_, _>| match result {
195        Ok(layout) => Ok(tcx.mk_layout(layout)),
196        Err(err) => Err(map_error(cx, ty, err)),
197    };
198    let scalar_unit = |value: Primitive| {
199        let size = value.size(dl);
200        if !(size.bits() <= 128) {
    ::core::panicking::panic("assertion failed: size.bits() <= 128")
};assert!(size.bits() <= 128);
201        Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
202    };
203    let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
204
205    let univariant = |tys: &[Ty<'tcx>], kind| {
206        let fields = tys.iter().map(|ty| cx.layout_of(*ty)).try_collect::<IndexVec<_, _>>()?;
207        let repr = ReprOptions::default();
208        map_layout(cx.calc.univariant(&fields, &repr, kind))
209    };
210    if true {
    if !!ty.has_non_region_infer() {
        ::core::panicking::panic("assertion failed: !ty.has_non_region_infer()")
    };
};debug_assert!(!ty.has_non_region_infer());
211
212    Ok(match *ty.kind() {
213        ty::Pat(ty, pat) => {
214            let layout = cx.layout_of(ty)?.layout;
215            let mut layout = LayoutData::clone(&layout.0);
216            match *pat {
217                ty::PatternKind::Range { start, end } => {
218                    if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
219                        scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
220                            .try_to_bits(tcx, cx.typing_env)
221                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
222
223                        scalar.valid_range_mut().end = extract_const_value(cx, ty, end)?
224                            .try_to_bits(tcx, cx.typing_env)
225                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
226
227                        // FIXME(pattern_types): create implied bounds from pattern types in signatures
228                        // that require that the range end is >= the range start so that we can't hit
229                        // this error anymore without first having hit a trait solver error.
230                        // Very fuzzy on the details here, but pattern types are an internal impl detail,
231                        // so we can just go with this for now
232                        if scalar.is_signed() {
233                            let range = scalar.valid_range_mut();
234                            let start = layout.size.sign_extend(range.start);
235                            let end = layout.size.sign_extend(range.end);
236                            if end < start {
237                                let guar = tcx.dcx().err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("pattern type ranges cannot wrap: {0}..={1}",
                start, end))
    })format!(
238                                    "pattern type ranges cannot wrap: {start}..={end}"
239                                ));
240
241                                return Err(error(cx, LayoutError::ReferencesError(guar)));
242                            }
243                        } else {
244                            let range = scalar.valid_range_mut();
245                            if range.end < range.start {
246                                let guar = tcx.dcx().err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("pattern type ranges cannot wrap: {0}..={1}",
                range.start, range.end))
    })format!(
247                                    "pattern type ranges cannot wrap: {}..={}",
248                                    range.start, range.end
249                                ));
250
251                                return Err(error(cx, LayoutError::ReferencesError(guar)));
252                            }
253                        };
254
255                        let niche = Niche {
256                            offset: Size::ZERO,
257                            value: scalar.primitive(),
258                            valid_range: scalar.valid_range(cx),
259                        };
260
261                        layout.largest_niche = Some(niche);
262                    } else {
263                        ::rustc_middle::util::bug::bug_fmt(format_args!("pattern type with range but not scalar layout: {0:?}, {1:?}",
        ty, layout))bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
264                    }
265                }
266                ty::PatternKind::NotNull => {
267                    if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
268                        &mut layout.backend_repr
269                    {
270                        scalar.valid_range_mut().start = 1;
271                        let niche = Niche {
272                            offset: Size::ZERO,
273                            value: scalar.primitive(),
274                            valid_range: scalar.valid_range(cx),
275                        };
276
277                        layout.largest_niche = Some(niche);
278                    } else {
279                        ::rustc_middle::util::bug::bug_fmt(format_args!("pattern type with `!null` pattern but not scalar/pair layout: {0:?}, {1:?}",
        ty, layout))bug!(
280                            "pattern type with `!null` pattern but not scalar/pair layout: {ty:?}, {layout:?}"
281                        )
282                    }
283                }
284
285                ty::PatternKind::Or(variants) => match *variants[0] {
286                    ty::PatternKind::Range { .. } => {
287                        if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
288                            let variants: Result<Vec<_>, _> = variants
289                                .iter()
290                                .map(|pat| match *pat {
291                                    ty::PatternKind::Range { start, end } => Ok((
292                                        extract_const_value(cx, ty, start)
293                                            .unwrap()
294                                            .try_to_bits(tcx, cx.typing_env)
295                                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
296                                        extract_const_value(cx, ty, end)
297                                            .unwrap()
298                                            .try_to_bits(tcx, cx.typing_env)
299                                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
300                                    )),
301                                    ty::PatternKind::NotNull | ty::PatternKind::Or(_) => {
302                                        {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("mixed or patterns are not allowed")));
}unreachable!("mixed or patterns are not allowed")
303                                    }
304                                })
305                                .collect();
306                            let mut variants = variants?;
307                            if !scalar.is_signed() {
308                                let guar = tcx.dcx().err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("only signed integer base types are allowed for or-pattern pattern types at present"))
    })format!(
309                                    "only signed integer base types are allowed for or-pattern pattern types at present"
310                                ));
311
312                                return Err(error(cx, LayoutError::ReferencesError(guar)));
313                            }
314                            variants.sort();
315                            if variants.len() != 2 {
316                                let guar = tcx
317                                .dcx()
318                                .err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("the only or-pattern types allowed are two range patterns that are directly connected at their overflow site"))
    })format!("the only or-pattern types allowed are two range patterns that are directly connected at their overflow site"));
319
320                                return Err(error(cx, LayoutError::ReferencesError(guar)));
321                            }
322
323                            // first is the one starting at the signed in range min
324                            let mut first = variants[0];
325                            let mut second = variants[1];
326                            if second.0
327                                == layout.size.truncate(layout.size.signed_int_min() as u128)
328                            {
329                                (second, first) = (first, second);
330                            }
331
332                            if layout.size.sign_extend(first.1) >= layout.size.sign_extend(second.0)
333                            {
334                                let guar = tcx.dcx().err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("only non-overlapping pattern type ranges are allowed at present"))
    })format!(
335                                    "only non-overlapping pattern type ranges are allowed at present"
336                                ));
337
338                                return Err(error(cx, LayoutError::ReferencesError(guar)));
339                            }
340                            if layout.size.signed_int_max() as u128 != second.1 {
341                                let guar = tcx.dcx().err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("one pattern needs to end at `{1}::MAX`, but was {0} instead",
                second.1, ty))
    })format!(
342                                    "one pattern needs to end at `{ty}::MAX`, but was {} instead",
343                                    second.1
344                                ));
345
346                                return Err(error(cx, LayoutError::ReferencesError(guar)));
347                            }
348
349                            // Now generate a wrapping range (which aren't allowed in surface syntax).
350                            scalar.valid_range_mut().start = second.0;
351                            scalar.valid_range_mut().end = first.1;
352
353                            let niche = Niche {
354                                offset: Size::ZERO,
355                                value: scalar.primitive(),
356                                valid_range: scalar.valid_range(cx),
357                            };
358
359                            layout.largest_niche = Some(niche);
360                        } else {
361                            ::rustc_middle::util::bug::bug_fmt(format_args!("pattern type with range but not scalar layout: {0:?}, {1:?}",
        ty, layout))bug!(
362                                "pattern type with range but not scalar layout: {ty:?}, {layout:?}"
363                            )
364                        }
365                    }
366                    ty::PatternKind::NotNull => ::rustc_middle::util::bug::bug_fmt(format_args!("or patterns can\'t contain `!null` patterns"))bug!("or patterns can't contain `!null` patterns"),
367                    ty::PatternKind::Or(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("patterns cannot have nested or patterns"))bug!("patterns cannot have nested or patterns"),
368                },
369            }
370            // Pattern types contain their base as their sole field.
371            // This allows the rest of the compiler to process pattern types just like
372            // single field transparent Adts, and only the parts of the compiler that
373            // specifically care about pattern types will have to handle it.
374            layout.fields = FieldsShape::Arbitrary {
375                offsets: [Size::ZERO].into_iter().collect(),
376                in_memory_order: [FieldIdx::new(0)].into_iter().collect(),
377            };
378            tcx.mk_layout(layout)
379        }
380
381        // Basic scalars.
382        ty::Bool => tcx.mk_layout(LayoutData::scalar(
383            cx,
384            Scalar::Initialized {
385                value: Int(I8, false),
386                valid_range: WrappingRange { start: 0, end: 1 },
387            },
388        )),
389        ty::Char => tcx.mk_layout(LayoutData::scalar(
390            cx,
391            Scalar::Initialized {
392                value: Int(I32, false),
393                valid_range: WrappingRange { start: 0, end: 0x10FFFF },
394            },
395        )),
396        ty::Int(ity) => scalar(Int(abi::Integer::from_int_ty(dl, ity), true)),
397        ty::Uint(ity) => scalar(Int(abi::Integer::from_uint_ty(dl, ity), false)),
398        ty::Float(fty) => scalar(Float(abi::Float::from_float_ty(fty))),
399        ty::FnPtr(..) => {
400            let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
401            ptr.valid_range_mut().start = 1;
402            tcx.mk_layout(LayoutData::scalar(cx, ptr))
403        }
404
405        // The never type.
406        ty::Never => tcx.mk_layout(LayoutData::never_type(cx)),
407
408        // Potentially-wide pointers.
409        ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
410            let mut data_ptr = scalar_unit(Pointer(AddressSpace::ZERO));
411            if !ty.is_raw_ptr() {
412                data_ptr.valid_range_mut().start = 1;
413            }
414
415            if pointee.is_sized(tcx, cx.typing_env) {
416                return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
417            }
418
419            let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
420                let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
421                let metadata_ty = match tcx
422                    .try_normalize_erasing_regions(cx.typing_env, pointee_metadata)
423                {
424                    Ok(metadata_ty) => metadata_ty,
425                    Err(mut err) => {
426                        // Usually `<Ty as Pointee>::Metadata` can't be normalized because
427                        // its struct tail cannot be normalized either, so try to get a
428                        // more descriptive layout error here, which will lead to less confusing
429                        // diagnostics.
430                        //
431                        // We use the raw struct tail function here to get the first tail
432                        // that is an alias, which is likely the cause of the normalization
433                        // error.
434                        match tcx.try_normalize_erasing_regions(
435                            cx.typing_env,
436                            tcx.struct_tail_raw(pointee, &ObligationCause::dummy(), |ty| ty, || {}),
437                        ) {
438                            Ok(_) => {}
439                            Err(better_err) => {
440                                err = better_err;
441                            }
442                        }
443                        return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
444                    }
445                };
446
447                let metadata_layout = cx.layout_of(metadata_ty)?;
448                // If the metadata is a 1-zst, then the pointer is thin.
449                if metadata_layout.is_1zst() {
450                    return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
451                }
452
453                let BackendRepr::Scalar(metadata) = metadata_layout.backend_repr else {
454                    return Err(error(cx, LayoutError::Unknown(pointee)));
455                };
456
457                metadata
458            } else {
459                let unsized_part = tcx.struct_tail_for_codegen(pointee, cx.typing_env);
460
461                match unsized_part.kind() {
462                    ty::Foreign(..) => {
463                        return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
464                    }
465                    ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
466                    ty::Dynamic(..) => {
467                        let mut vtable = scalar_unit(Pointer(AddressSpace::ZERO));
468                        vtable.valid_range_mut().start = 1;
469                        vtable
470                    }
471                    _ => {
472                        return Err(error(cx, LayoutError::Unknown(pointee)));
473                    }
474                }
475            };
476
477            // Effectively a (ptr, meta) tuple.
478            tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata))
479        }
480
481        // Arrays and slices.
482        ty::Array(element, count) => {
483            let count = extract_const_value(cx, ty, count)?
484                .try_to_target_usize(tcx)
485                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
486
487            let element = cx.layout_of(element)?;
488            map_layout(cx.calc.array_like(&element, Some(count)))?
489        }
490        ty::Slice(element) => {
491            let element = cx.layout_of(element)?;
492            map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
493                // a randomly chosen value to distinguish slices
494                layout.randomization_seed = Hash64::new(0x2dcba99c39784102);
495                layout
496            }))?
497        }
498        ty::Str => {
499            let element = scalar(Int(I8, false));
500            map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
501                // another random value
502                layout.randomization_seed = Hash64::new(0xc1325f37d127be22);
503                layout
504            }))?
505        }
506
507        // Odd unit types.
508        ty::FnDef(..) | ty::Dynamic(_, _) | ty::Foreign(..) => {
509            let sized = #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::FnDef(..) => true,
    _ => false,
}matches!(ty.kind(), ty::FnDef(..));
510            tcx.mk_layout(LayoutData::unit(cx, sized))
511        }
512
513        ty::Coroutine(def_id, args) => {
514            use rustc_middle::ty::layout::PrimitiveExt as _;
515
516            let info = tcx.coroutine_layout(def_id, args)?;
517
518            let local_layouts = info
519                .field_tys
520                .iter()
521                .map(|local| {
522                    let field_ty = EarlyBinder::bind(local.ty);
523                    let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty.instantiate(tcx, args));
524                    cx.spanned_layout_of(uninit_ty, local.source_info.span)
525                })
526                .try_collect::<IndexVec<_, _>>()?;
527
528            let prefix_layouts = args
529                .as_coroutine()
530                .prefix_tys()
531                .iter()
532                .map(|ty| cx.layout_of(ty))
533                .try_collect::<IndexVec<_, _>>()?;
534
535            let layout = cx
536                .calc
537                .coroutine(
538                    &local_layouts,
539                    prefix_layouts,
540                    &info.variant_fields,
541                    &info.storage_conflicts,
542                    |tag| TyAndLayout {
543                        ty: tag.primitive().to_ty(tcx),
544                        layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
545                    },
546                )
547                .map(|mut layout| {
548                    // this is similar to how ReprOptions populates its field_shuffle_seed
549                    layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash();
550                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:550",
                        "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(550u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("coroutine layout ({0:?}): {1:#?}",
                                                    ty, layout) as &dyn Value))])
            });
    } else { ; }
};debug!("coroutine layout ({:?}): {:#?}", ty, layout);
551                    layout
552                });
553            map_layout(layout)?
554        }
555
556        ty::Closure(_, args) => univariant(args.as_closure().upvar_tys(), StructKind::AlwaysSized)?,
557
558        ty::CoroutineClosure(_, args) => {
559            univariant(args.as_coroutine_closure().upvar_tys(), StructKind::AlwaysSized)?
560        }
561
562        ty::Tuple(tys) => {
563            let kind =
564                if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
565
566            univariant(tys, kind)?
567        }
568
569        // Scalable vector types
570        //
571        // ```rust (ignore, example)
572        // #[rustc_scalable_vector(3)]
573        // struct svuint32_t(u32);
574        // ```
575        ty::Adt(def, args)
576            if #[allow(non_exhaustive_omitted_patterns)] match def.repr().scalable {
    Some(ScalableElt::ElementCount(..)) => true,
    _ => false,
}matches!(def.repr().scalable, Some(ScalableElt::ElementCount(..))) =>
577        {
578            let Some(element_ty) = def
579                .is_struct()
580                .then(|| &def.variant(FIRST_VARIANT).fields)
581                .filter(|fields| fields.len() == 1)
582                .map(|fields| fields[FieldIdx::ZERO].ty(tcx, args))
583            else {
584                let guar = tcx
585                    .dcx()
586                    .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
587                return Err(error(cx, LayoutError::ReferencesError(guar)));
588            };
589            let Some(ScalableElt::ElementCount(element_count)) = def.repr().scalable else {
590                let guar = tcx
591                    .dcx()
592                    .delayed_bug("#[rustc_scalable_vector] was applied to an invalid type");
593                return Err(error(cx, LayoutError::ReferencesError(guar)));
594            };
595
596            let element_layout = cx.layout_of(element_ty)?;
597            map_layout(cx.calc.scalable_vector_type(element_layout, element_count as u64))?
598        }
599
600        // SIMD vector types.
601        ty::Adt(def, args) if def.repr().simd() => {
602            // Supported SIMD vectors are ADTs with a single array field:
603            //
604            // * #[repr(simd)] struct S([T; 4])
605            //
606            // where T is a primitive scalar (integer/float/pointer).
607            let Some(ty::Array(e_ty, e_len)) = def
608                .is_struct()
609                .then(|| &def.variant(FIRST_VARIANT).fields)
610                .filter(|fields| fields.len() == 1)
611                .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).kind())
612            else {
613                // Invalid SIMD types should have been caught by typeck by now.
614                let guar = tcx.dcx().delayed_bug("#[repr(simd)] was applied to an invalid ADT");
615                return Err(error(cx, LayoutError::ReferencesError(guar)));
616            };
617
618            let e_len = extract_const_value(cx, ty, e_len)?
619                .try_to_target_usize(tcx)
620                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
621
622            let e_ly = cx.layout_of(e_ty)?;
623
624            // Check for the rustc_simd_monomorphize_lane_limit attribute and check the lane limit
625            if let Some(limit) = {

    #[allow(deprecated)]
    {
        {
            'done:
                {
                for i in tcx.get_all_attrs(def.did()) {
                    #[allow(unused_imports)]
                    use rustc_hir::attrs::AttributeKind::*;
                    let i: &rustc_hir::Attribute = i;
                    match i {
                        rustc_hir::Attribute::Parsed(RustcSimdMonomorphizeLaneLimit(limit))
                            => {
                            break 'done Some(limit);
                        }
                        rustc_hir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }
}find_attr!(
626                tcx, def.did(),
627                RustcSimdMonomorphizeLaneLimit(limit) => limit
628            ) {
629                if !limit.value_within_limit(e_len as usize) {
630                    return Err(map_error(
631                        &cx,
632                        ty,
633                        rustc_abi::LayoutCalculatorError::OversizedSimdType {
634                            max_lanes: limit.0 as u64,
635                        },
636                    ));
637                }
638            }
639
640            map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
641        }
642
643        // ADTs.
644        ty::Adt(def, args) => {
645            // Cache the field layouts.
646            let variants = def
647                .variants()
648                .iter()
649                .map(|v| {
650                    v.fields
651                        .iter()
652                        .map(|field| cx.layout_of(field.ty(tcx, args)))
653                        .try_collect::<IndexVec<_, _>>()
654                })
655                .try_collect::<IndexVec<VariantIdx, _>>()?;
656
657            if def.is_union() {
658                if def.repr().pack.is_some() && def.repr().align.is_some() {
659                    let guar = tcx.dcx().span_delayed_bug(
660                        tcx.def_span(def.did()),
661                        "union cannot be packed and aligned",
662                    );
663                    return Err(error(cx, LayoutError::ReferencesError(guar)));
664                }
665
666                return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
667            }
668
669            // UnsafeCell and UnsafePinned both disable niche optimizations
670            let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
671
672            let discr_range_of_repr =
673                |min, max| abi::Integer::discr_range_of_repr(tcx, ty, &def.repr(), min, max);
674
675            let discriminants_iter = || {
676                def.is_enum()
677                    .then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val as i128)))
678                    .into_iter()
679                    .flatten()
680            };
681
682            let maybe_unsized = def.is_struct()
683                && def.non_enum_variant().tail_opt().is_some_and(|last_field| {
684                    let typing_env = ty::TypingEnv::post_analysis(tcx, def.did());
685                    !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, typing_env)
686                });
687
688            let layout = cx
689                .calc
690                .layout_of_struct_or_enum(
691                    &def.repr(),
692                    &variants,
693                    def.is_enum(),
694                    is_special_no_niche,
695                    tcx.layout_scalar_valid_range(def.did()),
696                    discr_range_of_repr,
697                    discriminants_iter(),
698                    !maybe_unsized,
699                )
700                .map_err(|err| map_error(cx, ty, err))?;
701
702            if !maybe_unsized && layout.is_unsized() {
703                ::rustc_middle::util::bug::bug_fmt(format_args!("got unsized layout for type that cannot be unsized {0:?}: {1:#?}",
        ty, layout));bug!("got unsized layout for type that cannot be unsized {ty:?}: {layout:#?}");
704            }
705
706            // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
707            if truecfg!(debug_assertions)
708                && maybe_unsized
709                && def.non_enum_variant().tail().ty(tcx, args).is_sized(tcx, cx.typing_env)
710            {
711                let mut variants = variants;
712                let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
713                *variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement;
714
715                let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum(
716                    &def.repr(),
717                    &variants,
718                    def.is_enum(),
719                    is_special_no_niche,
720                    tcx.layout_scalar_valid_range(def.did()),
721                    discr_range_of_repr,
722                    discriminants_iter(),
723                    !maybe_unsized,
724                ) else {
725                    ::rustc_middle::util::bug::bug_fmt(format_args!("failed to compute unsized layout of {0:?}",
        ty));bug!("failed to compute unsized layout of {ty:?}");
726                };
727
728                let FieldsShape::Arbitrary { offsets: sized_offsets, .. } = &layout.fields else {
729                    ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected FieldsShape for sized layout of {1:?}: {0:?}",
        layout.fields, ty));bug!("unexpected FieldsShape for sized layout of {ty:?}: {:?}", layout.fields);
730                };
731                let FieldsShape::Arbitrary { offsets: unsized_offsets, .. } =
732                    &unsized_layout.fields
733                else {
734                    ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected FieldsShape for unsized layout of {1:?}: {0:?}",
        unsized_layout.fields, ty));bug!(
735                        "unexpected FieldsShape for unsized layout of {ty:?}: {:?}",
736                        unsized_layout.fields
737                    );
738                };
739
740                let (sized_tail, sized_fields) = sized_offsets.raw.split_last().unwrap();
741                let (unsized_tail, unsized_fields) = unsized_offsets.raw.split_last().unwrap();
742
743                if sized_fields != unsized_fields {
744                    ::rustc_middle::util::bug::bug_fmt(format_args!("unsizing {0:?} changed field order!\n{1:?}\n{2:?}",
        ty, layout, unsized_layout));bug!("unsizing {ty:?} changed field order!\n{layout:?}\n{unsized_layout:?}");
745                }
746
747                if sized_tail < unsized_tail {
748                    ::rustc_middle::util::bug::bug_fmt(format_args!("unsizing {0:?} moved tail backwards!\n{1:?}\n{2:?}",
        ty, layout, unsized_layout));bug!("unsizing {ty:?} moved tail backwards!\n{layout:?}\n{unsized_layout:?}");
749                }
750            }
751
752            tcx.mk_layout(layout)
753        }
754
755        ty::UnsafeBinder(bound_ty) => {
756            let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
757            cx.layout_of(ty)?.layout
758        }
759
760        // Types with no meaningful known layout.
761        ty::Param(_) | ty::Placeholder(..) => {
762            return Err(error(cx, LayoutError::TooGeneric(ty)));
763        }
764
765        ty::Alias(..) => {
766            // In case we're still in a generic context, aliases might be rigid. E.g.
767            // if we've got a `T: Trait` where-bound, `T::Assoc` cannot be normalized
768            // in the current context.
769            //
770            // For some builtin traits, generic aliases can be rigid even in an empty environment,
771            // e.g. `<T as Pointee>::Metadata`.
772            //
773            // Due to trivial bounds, this can even be the case if the alias does not reference
774            // any generic parameters, e.g. a `for<'a> u32: Trait<'a>` where-bound means that
775            // `<u32 as Trait<'static>>::Assoc` is rigid.
776            let err = if ty.has_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
777                LayoutError::TooGeneric(ty)
778            } else {
779                LayoutError::ReferencesError(cx.tcx().dcx().delayed_bug(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("unexpected rigid alias in layout_of after normalization: {0:?}",
                ty))
    })format!(
780                    "unexpected rigid alias in layout_of after normalization: {ty:?}"
781                )))
782            };
783            return Err(error(cx, err));
784        }
785
786        ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => {
787            // `ty::Error` is handled at the top of this function.
788            ::rustc_middle::util::bug::bug_fmt(format_args!("layout_of: unexpected type `{0}`",
        ty))bug!("layout_of: unexpected type `{ty}`")
789        }
790    })
791}
792
793fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) {
794    // Ignore layouts that are done with non-empty environments or
795    // non-monomorphic layouts, as the user only wants to see the stuff
796    // resulting from the final codegen session.
797    if layout.ty.has_non_region_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
798        return;
799    }
800
801    // (delay format until we actually need it)
802    let record = |kind, packed, opt_discr_size, variants| {
803        let type_desc = {
    let _guard = NoTrimmedGuard::new();
    ::alloc::__export::must_use({
            ::alloc::fmt::format(format_args!("{0}", layout.ty))
        })
}with_no_trimmed_paths!(format!("{}", layout.ty));
804        cx.tcx().sess.code_stats.record_type_size(
805            kind,
806            type_desc,
807            layout.align.abi,
808            layout.size,
809            packed,
810            opt_discr_size,
811            variants,
812        );
813    };
814
815    match *layout.ty.kind() {
816        ty::Adt(adt_def, _) => {
817            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:817",
                        "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(817u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("print-type-size t: `{0:?}` process adt",
                                                    layout.ty) as &dyn Value))])
            });
    } else { ; }
};debug!("print-type-size t: `{:?}` process adt", layout.ty);
818            let adt_kind = adt_def.adt_kind();
819            let adt_packed = adt_def.repr().pack.is_some();
820            let (variant_infos, opt_discr_size) = variant_info_for_adt(cx, layout, adt_def);
821            record(adt_kind.into(), adt_packed, opt_discr_size, variant_infos);
822        }
823
824        ty::Coroutine(def_id, args) => {
825            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:825",
                        "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(825u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("print-type-size t: `{0:?}` record coroutine",
                                                    layout.ty) as &dyn Value))])
            });
    } else { ; }
};debug!("print-type-size t: `{:?}` record coroutine", layout.ty);
826            // Coroutines always have a begin/poisoned/end state with additional suspend points
827            let (variant_infos, opt_discr_size) =
828                variant_info_for_coroutine(cx, layout, def_id, args);
829            record(DataTypeKind::Coroutine, false, opt_discr_size, variant_infos);
830        }
831
832        ty::Closure(..) => {
833            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:833",
                        "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(833u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("print-type-size t: `{0:?}` record closure",
                                                    layout.ty) as &dyn Value))])
            });
    } else { ; }
};debug!("print-type-size t: `{:?}` record closure", layout.ty);
834            record(DataTypeKind::Closure, false, None, ::alloc::vec::Vec::new()vec![]);
835        }
836
837        _ => {
838            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:838",
                        "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(838u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("print-type-size t: `{0:?}` skip non-nominal",
                                                    layout.ty) as &dyn Value))])
            });
    } else { ; }
};debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
839        }
840    };
841}
842
843fn variant_info_for_adt<'tcx>(
844    cx: &LayoutCx<'tcx>,
845    layout: TyAndLayout<'tcx>,
846    adt_def: AdtDef<'tcx>,
847) -> (Vec<VariantInfo>, Option<Size>) {
848    let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
849        let mut min_size = Size::ZERO;
850        let field_info: Vec<_> = flds
851            .iter()
852            .enumerate()
853            .map(|(i, &name)| {
854                let field_layout = layout.field(cx, i);
855                let offset = layout.fields.offset(i);
856                min_size = min_size.max(offset + field_layout.size);
857                FieldInfo {
858                    kind: FieldKind::AdtField,
859                    name,
860                    offset: offset.bytes(),
861                    size: field_layout.size.bytes(),
862                    align: field_layout.align.bytes(),
863                    type_name: None,
864                }
865            })
866            .collect();
867
868        VariantInfo {
869            name: n,
870            kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact },
871            align: layout.align.bytes(),
872            size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() },
873            fields: field_info,
874        }
875    };
876
877    match layout.variants {
878        Variants::Empty => (::alloc::vec::Vec::new()vec![], None),
879
880        Variants::Single { index } => {
881            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:881",
                        "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(881u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("print-type-size `{0:#?}` variant {1}",
                                                    layout, adt_def.variant(index).name) as &dyn Value))])
            });
    } else { ; }
};debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variant(index).name);
882            let variant_def = &adt_def.variant(index);
883            let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
884            (::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [build_variant_info(Some(variant_def.name), &fields, layout)]))vec![build_variant_info(Some(variant_def.name), &fields, layout)], None)
885        }
886
887        Variants::Multiple { tag, ref tag_encoding, .. } => {
888            {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_ty_utils/src/layout.rs:888",
                        "rustc_ty_utils::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_ty_utils/src/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(888u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_ty_utils::layout"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("print-type-size `{0:#?}` adt general variants def {1}",
                                                    layout.ty, adt_def.variants().len()) as &dyn Value))])
            });
    } else { ; }
};debug!(
889                "print-type-size `{:#?}` adt general variants def {}",
890                layout.ty,
891                adt_def.variants().len()
892            );
893            let variant_infos: Vec<_> = adt_def
894                .variants()
895                .iter_enumerated()
896                .map(|(i, variant_def)| {
897                    let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
898                    build_variant_info(Some(variant_def.name), &fields, layout.for_variant(cx, i))
899                })
900                .collect();
901
902            (
903                variant_infos,
904                match tag_encoding {
905                    TagEncoding::Direct => Some(tag.size(cx)),
906                    _ => None,
907                },
908            )
909        }
910    }
911}
912
913fn variant_info_for_coroutine<'tcx>(
914    cx: &LayoutCx<'tcx>,
915    layout: TyAndLayout<'tcx>,
916    def_id: DefId,
917    args: ty::GenericArgsRef<'tcx>,
918) -> (Vec<VariantInfo>, Option<Size>) {
919    use itertools::Itertools;
920
921    let Variants::Multiple { tag, ref tag_encoding, tag_field, .. } = layout.variants else {
922        return (::alloc::vec::Vec::new()vec![], None);
923    };
924
925    let coroutine = cx.tcx().coroutine_layout(def_id, args).unwrap();
926    let upvar_names = cx.tcx().closure_saved_names_of_captured_variables(def_id);
927
928    let mut upvars_size = Size::ZERO;
929    let upvar_fields: Vec<_> = args
930        .as_coroutine()
931        .upvar_tys()
932        .iter()
933        .zip_eq(upvar_names)
934        .enumerate()
935        .map(|(field_idx, (_, name))| {
936            let field_layout = layout.field(cx, field_idx);
937            let offset = layout.fields.offset(field_idx);
938            upvars_size = upvars_size.max(offset + field_layout.size);
939            FieldInfo {
940                kind: FieldKind::Upvar,
941                name: *name,
942                offset: offset.bytes(),
943                size: field_layout.size.bytes(),
944                align: field_layout.align.bytes(),
945                type_name: None,
946            }
947        })
948        .collect();
949
950    let mut variant_infos: Vec<_> = coroutine
951        .variant_fields
952        .iter_enumerated()
953        .map(|(variant_idx, variant_def)| {
954            let variant_layout = layout.for_variant(cx, variant_idx);
955            let mut variant_size = Size::ZERO;
956            let fields = variant_def
957                .iter()
958                .enumerate()
959                .map(|(field_idx, local)| {
960                    let field_name = coroutine.field_names[*local];
961                    let field_layout = variant_layout.field(cx, field_idx);
962                    let offset = variant_layout.fields.offset(field_idx);
963                    // The struct is as large as the last field's end
964                    variant_size = variant_size.max(offset + field_layout.size);
965                    FieldInfo {
966                        kind: FieldKind::CoroutineLocal,
967                        name: field_name.unwrap_or_else(|| {
968                            Symbol::intern(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".coroutine_field{0}",
                local.as_usize()))
    })format!(".coroutine_field{}", local.as_usize()))
969                        }),
970                        offset: offset.bytes(),
971                        size: field_layout.size.bytes(),
972                        align: field_layout.align.bytes(),
973                        // Include the type name if there is no field name, or if the name is the
974                        // __awaitee placeholder symbol which means a child future being `.await`ed.
975                        type_name: (field_name.is_none() || field_name == Some(sym::__awaitee))
976                            .then(|| Symbol::intern(&field_layout.ty.to_string())),
977                    }
978                })
979                .chain(upvar_fields.iter().copied())
980                .collect();
981
982            // If the variant has no state-specific fields, then it's the size of the upvars.
983            if variant_size == Size::ZERO {
984                variant_size = upvars_size;
985            }
986
987            // This `if` deserves some explanation.
988            //
989            // The layout code has a choice of where to place the discriminant of this coroutine.
990            // If the discriminant of the coroutine is placed early in the layout (before the
991            // variant's own fields), then it'll implicitly be counted towards the size of the
992            // variant, since we use the maximum offset to calculate size.
993            //    (side-note: I know this is a bit problematic given upvars placement, etc).
994            //
995            // This is important, since the layout printing code always subtracts this discriminant
996            // size from the variant size if the struct is "enum"-like, so failing to account for it
997            // will either lead to numerical underflow, or an underreported variant size...
998            //
999            // However, if the discriminant is placed past the end of the variant, then we need
1000            // to factor in the size of the discriminant manually. This really should be refactored
1001            // better, but this "works" for now.
1002            if layout.fields.offset(tag_field.as_usize()) >= variant_size {
1003                variant_size += match tag_encoding {
1004                    TagEncoding::Direct => tag.size(cx),
1005                    _ => Size::ZERO,
1006                };
1007            }
1008
1009            VariantInfo {
1010                name: Some(Symbol::intern(&ty::CoroutineArgs::variant_name(variant_idx))),
1011                kind: SizeKind::Exact,
1012                size: variant_size.bytes(),
1013                align: variant_layout.align.bytes(),
1014                fields,
1015            }
1016        })
1017        .collect();
1018
1019    // The first three variants are hardcoded to be `UNRESUMED`, `RETURNED` and `POISONED`.
1020    // We will move the `RETURNED` and `POISONED` elements to the end so we
1021    // are left with a sorting order according to the coroutines yield points:
1022    // First `Unresumed`, then the `SuspendN` followed by `Returned` and `Panicked` (POISONED).
1023    let end_states = variant_infos.drain(1..=2);
1024    let end_states: Vec<_> = end_states.collect();
1025    variant_infos.extend(end_states);
1026
1027    (
1028        variant_infos,
1029        match tag_encoding {
1030            TagEncoding::Direct => Some(tag.size(cx)),
1031            _ => None,
1032        },
1033    )
1034}