Skip to main content

rustc_ty_utils/
layout.rs

1use hir::def_id::DefId;
2use rustc_abi as abi;
3use rustc_abi::Integer::{I8, I32};
4use rustc_abi::Primitive::{self, Float, Int, Pointer};
5use rustc_abi::{
6    AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
7    LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding,
8    VariantIdx, Variants, WrappingRange,
9};
10use rustc_hashes::Hash64;
11use rustc_hir as hir;
12use rustc_hir::find_attr;
13use rustc_index::{Idx as _, IndexVec};
14use rustc_middle::bug;
15use rustc_middle::query::Providers;
16use rustc_middle::traits::ObligationCause;
17use rustc_middle::ty::layout::{
18    FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout,
19};
20use rustc_middle::ty::print::with_no_trimmed_paths;
21use rustc_middle::ty::{
22    self, AdtDef, CoroutineArgsExt, EarlyBinder, PseudoCanonicalInput, Ty, TyCtxt,
23    TypeVisitableExt, Unnormalized,
24};
25use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
26use rustc_span::{Symbol, sym};
27use tracing::{debug, instrument};
28
29use crate::errors::NonPrimitiveSimdType;
30
31mod invariant;
32
33pub(crate) fn provide(providers: &mut Providers) {
34    *providers = Providers { layout_of, ..*providers };
35}
36
37#[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(37u32),
                                    ::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:43",
                                    "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(43u32),
                                    ::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,
                        Unnormalized::new_wip(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));
            }
            match typing_env.typing_mode() {
                ty::TypingMode::Codegen => {
                    let with_postanalysis =
                        ty::TypingEnv::new(typing_env.param_env,
                            ty::TypingMode::PostAnalysis);
                    let res =
                        tcx.layout_of(with_postanalysis.as_query_input(ty));
                    match res {
                        Err(LayoutError::TooGeneric(_)) => {}
                        _ => return res,
                    };
                }
                ty::TypingMode::Coherence | ty::TypingMode::Analysis { .. } |
                    ty::TypingMode::Borrowck { .. } |
                    ty::TypingMode::PostBorrowckAnalysis { .. } |
                    ty::TypingMode::ErasedNotCoherence(_) |
                    ty::TypingMode::PostAnalysis => {}
            }
            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")]
38fn layout_of<'tcx>(
39    tcx: TyCtxt<'tcx>,
40    query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
41) -> Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> {
42    let PseudoCanonicalInput { typing_env, value: ty } = query;
43    debug!(?ty);
44
45    // Optimization: We convert to TypingMode::PostAnalysis and convert opaque types in
46    // the where bounds to their hidden types. This reduces overall uncached invocations
47    // of `layout_of` and is thus a small performance improvement.
48    let typing_env = typing_env.with_post_analysis_normalized(tcx);
49    let unnormalized_ty = ty;
50
51    // FIXME: We might want to have two different versions of `layout_of`:
52    // One that can be called after typecheck has completed and can use
53    // `normalize_erasing_regions` here and another one that can be called
54    // before typecheck has completed and uses `try_normalize_erasing_regions`.
55    let ty = match tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)) {
56        Ok(t) => t,
57        Err(normalization_error) => {
58            return Err(tcx
59                .arena
60                .alloc(LayoutError::NormalizationFailure(ty, normalization_error)));
61        }
62    };
63
64    if ty != unnormalized_ty {
65        // Ensure this layout is also cached for the normalized type.
66        return tcx.layout_of(typing_env.as_query_input(ty));
67    }
68
69    match typing_env.typing_mode() {
70        ty::TypingMode::Codegen => {
71            let with_postanalysis =
72                ty::TypingEnv::new(typing_env.param_env, ty::TypingMode::PostAnalysis);
73            let res = tcx.layout_of(with_postanalysis.as_query_input(ty));
74            match res {
75                Err(LayoutError::TooGeneric(_)) => {}
76                _ => return res,
77            };
78        }
79        ty::TypingMode::Coherence
80        | ty::TypingMode::Analysis { .. }
81        | ty::TypingMode::Borrowck { .. }
82        | ty::TypingMode::PostBorrowckAnalysis { .. }
83        | ty::TypingMode::ErasedNotCoherence(_)
84        | ty::TypingMode::PostAnalysis => {}
85    }
86
87    let cx = LayoutCx::new(tcx, typing_env);
88
89    let layout = layout_of_uncached(&cx, ty)?;
90    let layout = TyAndLayout { ty, layout };
91
92    // If we are running with `-Zprint-type-sizes`, maybe record layouts
93    // for dumping later.
94    if cx.tcx().sess.opts.unstable_opts.print_type_sizes {
95        record_layout_for_printing(&cx, layout);
96    }
97
98    invariant::layout_sanity_check(&cx, &layout);
99
100    Ok(layout)
101}
102
103fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> {
104    cx.tcx().arena.alloc(err)
105}
106
107fn map_error<'tcx>(
108    cx: &LayoutCx<'tcx>,
109    ty: Ty<'tcx>,
110    err: LayoutCalculatorError<TyAndLayout<'tcx>>,
111) -> &'tcx LayoutError<'tcx> {
112    let err = match err {
113        LayoutCalculatorError::SizeOverflow => {
114            // This is sometimes not a compile error in `check` builds.
115            // See `tests/ui/limits/huge-enum.rs` for an example.
116            LayoutError::SizeOverflow(ty)
117        }
118        LayoutCalculatorError::UnexpectedUnsized(field) => {
119            // This is sometimes not a compile error if there are trivially false where clauses.
120            // See `tests/ui/layout/trivial-bounds-sized.rs` for an example.
121            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:#?}");
122            if cx.typing_env.param_env.caller_bounds().is_empty() {
123                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!(
124                    "encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
125                ));
126            }
127            LayoutError::Unknown(ty)
128        }
129        LayoutCalculatorError::EmptyUnion => {
130            // This is always a compile error.
131            let guar =
132                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:?}"));
133            LayoutError::ReferencesError(guar)
134        }
135        LayoutCalculatorError::ReprConflict => {
136            // packed enums are the only known trigger of this, but others might arise
137            let guar = cx
138                .tcx()
139                .dcx()
140                .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:?}"));
141            LayoutError::ReferencesError(guar)
142        }
143        LayoutCalculatorError::ZeroLengthSimdType => {
144            // Can't be caught in typeck if the array length is generic.
145            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength }
146        }
147        LayoutCalculatorError::OversizedSimdType { max_lanes } => {
148            // Can't be caught in typeck if the array length is generic.
149            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) }
150        }
151        LayoutCalculatorError::NonPrimitiveSimdType(field) => {
152            // This error isn't caught in typeck, e.g., if
153            // the element type of the vector is generic.
154            cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty })
155        }
156    };
157    error(cx, err)
158}
159
160fn extract_const_value<'tcx>(
161    cx: &LayoutCx<'tcx>,
162    ty: Ty<'tcx>,
163    ct: ty::Const<'tcx>,
164) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
165    match ct.kind() {
166        ty::ConstKind::Value(cv) => Ok(cv),
167        ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
168            if !ct.has_param() {
169                ::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:?}");
170            }
171            Err(error(cx, LayoutError::TooGeneric(ty)))
172        }
173        ty::ConstKind::Unevaluated(_) => {
174            let err = if ct.has_param() {
175                LayoutError::TooGeneric(ty)
176            } else {
177                // This case is reachable with unsatisfiable predicates and GCE (which will
178                // cause anon consts to inherit the unsatisfiable predicates). For example
179                // if we have an unsatisfiable `u8: Trait` bound, then it's not a compile
180                // error to mention `[u8; <u8 as Trait>::CONST]`, but we can't compute its
181                // layout.
182                LayoutError::Unknown(ty)
183            };
184            Err(error(cx, err))
185        }
186        ty::ConstKind::Infer(_)
187        | ty::ConstKind::Bound(..)
188        | ty::ConstKind::Placeholder(_)
189        | ty::ConstKind::Error(_) => {
190            // `ty::ConstKind::Error` is handled at the top of `layout_of_uncached`
191            // (via `ty.error_reported()`).
192            ::rustc_middle::util::bug::bug_fmt(format_args!("layout_of: unexpected const: {0:?}",
        ct));bug!("layout_of: unexpected const: {ct:?}");
193        }
194    }
195}
196
197fn layout_of_uncached<'tcx>(
198    cx: &LayoutCx<'tcx>,
199    ty: Ty<'tcx>,
200) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
201    // Types that reference `ty::Error` pessimistically don't have a meaningful layout.
202    // The only side-effect of this is possibly worse diagnostics in case the layout
203    // was actually computable (like if the `ty::Error` showed up only in a `PhantomData`).
204    if let Err(guar) = ty.error_reported() {
205        return Err(error(cx, LayoutError::ReferencesError(guar)));
206    }
207
208    let tcx = cx.tcx();
209
210    // layout of `async_drop_in_place<T>::{closure}` in case,
211    // when T is a coroutine, contains this internal coroutine's ref
212
213    let dl = cx.data_layout();
214    let map_layout = |result: Result<_, _>| match result {
215        Ok(layout) => Ok(tcx.mk_layout(layout)),
216        Err(err) => Err(map_error(cx, ty, err)),
217    };
218    let scalar_unit = |value: Primitive| {
219        let size = value.size(dl);
220        if !(size.bits() <= 128) {
    ::core::panicking::panic("assertion failed: size.bits() <= 128")
};assert!(size.bits() <= 128);
221        Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
222    };
223    let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
224
225    let univariant = |tys: &[Ty<'tcx>], kind| {
226        let fields = tys.iter().map(|ty| cx.layout_of(*ty)).try_collect::<IndexVec<_, _>>()?;
227        let repr = ReprOptions::default();
228        map_layout(cx.calc.univariant(&fields, &repr, kind))
229    };
230    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());
231
232    Ok(match *ty.kind() {
233        ty::Pat(ty, pat) => {
234            let layout = cx.layout_of(ty)?.layout;
235            let mut layout = LayoutData::clone(&layout.0);
236            match *pat {
237                ty::PatternKind::Range { start, end } => {
238                    if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
239                        scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
240                            .try_to_bits(tcx, cx.typing_env)
241                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
242
243                        scalar.valid_range_mut().end = extract_const_value(cx, ty, end)?
244                            .try_to_bits(tcx, cx.typing_env)
245                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
246
247                        // FIXME(pattern_types): create implied bounds from pattern types in signatures
248                        // that require that the range end is >= the range start so that we can't hit
249                        // this error anymore without first having hit a trait solver error.
250                        // Very fuzzy on the details here, but pattern types are an internal impl detail,
251                        // so we can just go with this for now
252                        if scalar.is_signed() {
253                            let range = scalar.valid_range_mut();
254                            let start = layout.size.sign_extend(range.start);
255                            let end = layout.size.sign_extend(range.end);
256                            if end < start {
257                                let guar = tcx.dcx().err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("pattern type ranges cannot wrap: {0}..={1}",
                start, end))
    })format!(
258                                    "pattern type ranges cannot wrap: {start}..={end}"
259                                ));
260
261                                return Err(error(cx, LayoutError::ReferencesError(guar)));
262                            }
263                        } else {
264                            let range = scalar.valid_range_mut();
265                            if range.end < range.start {
266                                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!(
267                                    "pattern type ranges cannot wrap: {}..={}",
268                                    range.start, range.end
269                                ));
270
271                                return Err(error(cx, LayoutError::ReferencesError(guar)));
272                            }
273                        };
274
275                        let niche = Niche {
276                            offset: Size::ZERO,
277                            value: scalar.primitive(),
278                            valid_range: scalar.valid_range(cx),
279                        };
280
281                        layout.largest_niche = Some(niche);
282                    } else {
283                        ::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:?}")
284                    }
285                }
286                ty::PatternKind::NotNull => {
287                    if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
288                        &mut layout.backend_repr
289                    {
290                        scalar.valid_range_mut().start = 1;
291                        let niche = Niche {
292                            offset: Size::ZERO,
293                            value: scalar.primitive(),
294                            valid_range: scalar.valid_range(cx),
295                        };
296
297                        layout.largest_niche = Some(niche);
298                    } else {
299                        ::rustc_middle::util::bug::bug_fmt(format_args!("pattern type with `!null` pattern but not scalar/pair layout: {0:?}, {1:?}",
        ty, layout))bug!(
300                            "pattern type with `!null` pattern but not scalar/pair layout: {ty:?}, {layout:?}"
301                        )
302                    }
303                }
304
305                ty::PatternKind::Or(variants) => match *variants[0] {
306                    ty::PatternKind::Range { .. } => {
307                        if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
308                            let variants: Result<Vec<_>, _> = variants
309                                .iter()
310                                .map(|pat| match *pat {
311                                    ty::PatternKind::Range { start, end } => Ok((
312                                        extract_const_value(cx, ty, start)
313                                            .unwrap()
314                                            .try_to_bits(tcx, cx.typing_env)
315                                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
316                                        extract_const_value(cx, ty, end)
317                                            .unwrap()
318                                            .try_to_bits(tcx, cx.typing_env)
319                                            .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
320                                    )),
321                                    ty::PatternKind::NotNull | ty::PatternKind::Or(_) => {
322                                        {
    ::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")
323                                    }
324                                })
325                                .collect();
326                            let mut variants = variants?;
327                            if !scalar.is_signed() {
328                                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!(
329                                    "only signed integer base types are allowed for or-pattern pattern types at present"
330                                ));
331
332                                return Err(error(cx, LayoutError::ReferencesError(guar)));
333                            }
334                            variants.sort();
335                            if variants.len() != 2 {
336                                let guar = tcx
337                                .dcx()
338                                .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"));
339
340                                return Err(error(cx, LayoutError::ReferencesError(guar)));
341                            }
342
343                            // first is the one starting at the signed in range min
344                            let mut first = variants[0];
345                            let mut second = variants[1];
346                            if second.0
347                                == layout.size.truncate(layout.size.signed_int_min() as u128)
348                            {
349                                (second, first) = (first, second);
350                            }
351
352                            if layout.size.sign_extend(first.1) >= layout.size.sign_extend(second.0)
353                            {
354                                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!(
355                                    "only non-overlapping pattern type ranges are allowed at present"
356                                ));
357
358                                return Err(error(cx, LayoutError::ReferencesError(guar)));
359                            }
360                            if layout.size.signed_int_max() as u128 != second.1 {
361                                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!(
362                                    "one pattern needs to end at `{ty}::MAX`, but was {} instead",
363                                    second.1
364                                ));
365
366                                return Err(error(cx, LayoutError::ReferencesError(guar)));
367                            }
368
369                            // Now generate a wrapping range (which aren't allowed in surface syntax).
370                            scalar.valid_range_mut().start = second.0;
371                            scalar.valid_range_mut().end = first.1;
372
373                            let niche = Niche {
374                                offset: Size::ZERO,
375                                value: scalar.primitive(),
376                                valid_range: scalar.valid_range(cx),
377                            };
378
379                            layout.largest_niche = Some(niche);
380                        } else {
381                            ::rustc_middle::util::bug::bug_fmt(format_args!("pattern type with range but not scalar layout: {0:?}, {1:?}",
        ty, layout))bug!(
382                                "pattern type with range but not scalar layout: {ty:?}, {layout:?}"
383                            )
384                        }
385                    }
386                    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"),
387                    ty::PatternKind::Or(..) => ::rustc_middle::util::bug::bug_fmt(format_args!("patterns cannot have nested or patterns"))bug!("patterns cannot have nested or patterns"),
388                },
389            }
390            // Pattern types contain their base as their sole field.
391            // This allows the rest of the compiler to process pattern types just like
392            // single field transparent Adts, and only the parts of the compiler that
393            // specifically care about pattern types will have to handle it.
394            layout.fields = FieldsShape::Arbitrary {
395                offsets: [Size::ZERO].into_iter().collect(),
396                in_memory_order: [FieldIdx::new(0)].into_iter().collect(),
397            };
398            tcx.mk_layout(layout)
399        }
400
401        // Basic scalars.
402        ty::Bool => tcx.mk_layout(LayoutData::scalar(
403            cx,
404            Scalar::Initialized {
405                value: Int(I8, false),
406                valid_range: WrappingRange { start: 0, end: 1 },
407            },
408        )),
409        ty::Char => tcx.mk_layout(LayoutData::scalar(
410            cx,
411            Scalar::Initialized {
412                value: Int(I32, false),
413                valid_range: WrappingRange { start: 0, end: 0x10FFFF },
414            },
415        )),
416        ty::Int(ity) => scalar(Int(abi::Integer::from_int_ty(dl, ity), true)),
417        ty::Uint(ity) => scalar(Int(abi::Integer::from_uint_ty(dl, ity), false)),
418        ty::Float(fty) => scalar(Float(abi::Float::from_float_ty(fty))),
419        ty::FnPtr(..) => {
420            let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
421            ptr.valid_range_mut().start = 1;
422            tcx.mk_layout(LayoutData::scalar(cx, ptr))
423        }
424
425        // The never type.
426        ty::Never => tcx.mk_layout(LayoutData::never_type(cx)),
427
428        // Potentially-wide pointers.
429        ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
430            let mut data_ptr = scalar_unit(Pointer(AddressSpace::ZERO));
431            if !ty.is_raw_ptr() {
432                data_ptr.valid_range_mut().start = 1;
433            }
434
435            if pointee.is_sized(tcx, cx.typing_env) {
436                return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
437            }
438
439            let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
440                let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
441                let metadata_ty = match tcx.try_normalize_erasing_regions(
442                    cx.typing_env,
443                    Unnormalized::new_wip(pointee_metadata),
444                ) {
445                    Ok(metadata_ty) => metadata_ty,
446                    Err(mut err) => {
447                        // Usually `<Ty as Pointee>::Metadata` can't be normalized because
448                        // its struct tail cannot be normalized either, so try to get a
449                        // more descriptive layout error here, which will lead to less confusing
450                        // diagnostics.
451                        //
452                        // We use the raw struct tail function here to get the first tail
453                        // that is an alias, which is likely the cause of the normalization
454                        // error.
455                        match tcx.try_normalize_erasing_regions(
456                            cx.typing_env,
457                            Unnormalized::new_wip(tcx.struct_tail_raw(
458                                pointee,
459                                &ObligationCause::dummy(),
460                                |ty| ty.skip_norm_wip(),
461                                || {},
462                            )),
463                        ) {
464                            Ok(_) => {}
465                            Err(better_err) => {
466                                err = better_err;
467                            }
468                        }
469                        return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
470                    }
471                };
472
473                let metadata_layout = cx.layout_of(metadata_ty)?;
474                // If the metadata is a 1-zst, then the pointer is thin.
475                if metadata_layout.is_1zst() {
476                    return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
477                }
478
479                let BackendRepr::Scalar(metadata) = metadata_layout.backend_repr else {
480                    return Err(error(cx, LayoutError::Unknown(pointee)));
481                };
482
483                metadata
484            } else {
485                let unsized_part = tcx.struct_tail_for_codegen(pointee, cx.typing_env);
486
487                match unsized_part.kind() {
488                    ty::Foreign(..) => {
489                        return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
490                    }
491                    ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
492                    ty::Dynamic(..) => {
493                        let mut vtable = scalar_unit(Pointer(AddressSpace::ZERO));
494                        vtable.valid_range_mut().start = 1;
495                        vtable
496                    }
497                    _ => {
498                        return Err(error(cx, LayoutError::Unknown(pointee)));
499                    }
500                }
501            };
502
503            // Effectively a (ptr, meta) tuple.
504            tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata))
505        }
506
507        // Arrays and slices.
508        ty::Array(element, count) => {
509            let count = extract_const_value(cx, ty, count)?
510                .try_to_target_usize(tcx)
511                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
512
513            let element = cx.layout_of(element)?;
514            map_layout(cx.calc.array_like(&element, Some(count)))?
515        }
516        ty::Slice(element) => {
517            let element = cx.layout_of(element)?;
518            map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
519                // a randomly chosen value to distinguish slices
520                layout.randomization_seed = Hash64::new(0x2dcba99c39784102);
521                layout
522            }))?
523        }
524        ty::Str => {
525            let element = scalar(Int(I8, false));
526            map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
527                // another random value
528                layout.randomization_seed = Hash64::new(0xc1325f37d127be22);
529                layout
530            }))?
531        }
532
533        // Odd unit types.
534        ty::FnDef(..) | ty::Dynamic(_, _) | ty::Foreign(..) => {
535            let sized = #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::FnDef(..) => true,
    _ => false,
}matches!(ty.kind(), ty::FnDef(..));
536            tcx.mk_layout(LayoutData::unit(cx, sized))
537        }
538
539        ty::Coroutine(def_id, args) => {
540            match cx.typing_env.typing_mode() {
541                ty::TypingMode::Codegen => {}
542                ty::TypingMode::Coherence
543                | ty::TypingMode::Analysis { .. }
544                | ty::TypingMode::Borrowck { .. }
545                | ty::TypingMode::PostBorrowckAnalysis { .. }
546                | ty::TypingMode::ErasedNotCoherence(_)
547                | ty::TypingMode::PostAnalysis => {
548                    return Err(error(cx, LayoutError::TooGeneric(ty)));
549                }
550            }
551
552            use rustc_middle::ty::layout::PrimitiveExt as _;
553
554            let info = tcx.coroutine_layout(def_id, args)?;
555
556            let local_layouts = info
557                .field_tys
558                .iter()
559                .map(|local| {
560                    let field_ty = EarlyBinder::bind(local.ty);
561                    let uninit_ty =
562                        Ty::new_maybe_uninit(tcx, field_ty.instantiate(tcx, args).skip_norm_wip());
563                    cx.spanned_layout_of(uninit_ty, local.source_info.span)
564                })
565                .try_collect::<IndexVec<_, _>>()?;
566
567            let prefix_layouts = args
568                .as_coroutine()
569                .prefix_tys()
570                .iter()
571                .map(|ty| cx.layout_of(ty))
572                .try_collect::<IndexVec<_, _>>()?;
573
574            let layout = cx
575                .calc
576                .coroutine(
577                    &local_layouts,
578                    prefix_layouts,
579                    &info.variant_fields,
580                    &info.storage_conflicts,
581                    |tag| TyAndLayout {
582                        ty: tag.primitive().to_ty(tcx),
583                        layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
584                    },
585                )
586                .map(|mut layout| {
587                    // this is similar to how ReprOptions populates its field_shuffle_seed
588                    layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash();
589                    {
    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:589",
                        "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(589u32),
                        ::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);
590                    layout
591                });
592            map_layout(layout)?
593        }
594
595        ty::Closure(_, args) => univariant(args.as_closure().upvar_tys(), StructKind::AlwaysSized)?,
596
597        ty::CoroutineClosure(_, args) => {
598            univariant(args.as_coroutine_closure().upvar_tys(), StructKind::AlwaysSized)?
599        }
600
601        ty::Tuple(tys) => {
602            let kind =
603                if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
604
605            univariant(tys, kind)?
606        }
607
608        // Scalable vector types
609        //
610        // ```rust (ignore, example)
611        // #[rustc_scalable_vector(3)]
612        // struct svuint32_t(u32);
613        //
614        // #[rustc_scalable_vector]
615        // struct svuint32x2_t(svuint32_t, svuint32_t);
616        // ```
617        ty::Adt(def, _args) if def.repr().scalable() => {
618            let Some((element_count, element_ty, number_of_vectors)) =
619                ty.scalable_vector_parts(tcx)
620            else {
621                let guar = tcx
622                    .dcx()
623                    .delayed_bug("`#[rustc_scalable_vector]` was applied to an invalid type");
624                return Err(error(cx, LayoutError::ReferencesError(guar)));
625            };
626
627            let element_layout = cx.layout_of(element_ty)?;
628            map_layout(cx.calc.scalable_vector_type(
629                element_layout,
630                element_count as u64,
631                number_of_vectors,
632            ))?
633        }
634
635        // SIMD vector types.
636        ty::Adt(def, args) if def.repr().simd() => {
637            // Supported SIMD vectors are ADTs with a single array field:
638            //
639            // * #[repr(simd)] struct S([T; 4])
640            //
641            // where T is a primitive scalar (integer/float/pointer).
642            let Some(ty::Array(e_ty, e_len)) = def
643                .is_struct()
644                .then(|| &def.variant(FIRST_VARIANT).fields)
645                .filter(|fields| fields.len() == 1)
646                .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).skip_norm_wip().kind())
647            else {
648                // Invalid SIMD types should have been caught by typeck by now.
649                let guar = tcx.dcx().delayed_bug("#[repr(simd)] was applied to an invalid ADT");
650                return Err(error(cx, LayoutError::ReferencesError(guar)));
651            };
652
653            let e_len = extract_const_value(cx, ty, e_len)?
654                .try_to_target_usize(tcx)
655                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
656
657            let e_ly = cx.layout_of(e_ty)?;
658
659            // Check for the rustc_simd_monomorphize_lane_limit attribute and check the lane limit
660            if let Some(limit) = {
    {
        'done:
            {
            for i in ::rustc_hir::attrs::HasAttrs::get_attrs(def.did(), &tcx)
                {
                #[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!(
661                tcx, def.did(),
662                RustcSimdMonomorphizeLaneLimit(limit) => limit
663            ) {
664                if !limit.value_within_limit(e_len as usize) {
665                    return Err(map_error(
666                        &cx,
667                        ty,
668                        rustc_abi::LayoutCalculatorError::OversizedSimdType {
669                            max_lanes: limit.0 as u64,
670                        },
671                    ));
672                }
673            }
674
675            map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
676        }
677
678        // ADTs.
679        ty::Adt(def, args) => {
680            // Cache the field layouts.
681            let variants = def
682                .variants()
683                .iter()
684                .map(|v| {
685                    v.fields
686                        .iter()
687                        .map(|field| cx.layout_of(field.ty(tcx, args).skip_norm_wip()))
688                        .try_collect::<IndexVec<_, _>>()
689                })
690                .try_collect::<IndexVec<VariantIdx, _>>()?;
691
692            if def.is_union() {
693                if def.repr().pack.is_some() && def.repr().align.is_some() {
694                    let guar = tcx.dcx().span_delayed_bug(
695                        tcx.def_span(def.did()),
696                        "union cannot be packed and aligned",
697                    );
698                    return Err(error(cx, LayoutError::ReferencesError(guar)));
699                }
700
701                return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
702            }
703
704            // UnsafeCell and UnsafePinned both disable niche optimizations
705            let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
706
707            let discr_range_of_repr =
708                |min, max| abi::Integer::discr_range_of_repr(tcx, ty, &def.repr(), min, max);
709
710            let discriminants_iter = || {
711                def.is_enum()
712                    .then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val as i128)))
713                    .into_iter()
714                    .flatten()
715            };
716
717            let maybe_unsized = def.is_struct()
718                && def.non_enum_variant().tail_opt().is_some_and(|last_field| {
719                    let typing_env = ty::TypingEnv::new(
720                        tcx.param_env_normalized_for_post_analysis(def.did()),
721                        cx.typing_env.typing_mode(),
722                    );
723                    !tcx.type_of(last_field.did)
724                        .instantiate_identity()
725                        .skip_norm_wip()
726                        .is_sized(tcx, typing_env)
727                });
728
729            let layout = cx
730                .calc
731                .layout_of_struct_or_enum(
732                    &def.repr(),
733                    &variants,
734                    def.is_enum(),
735                    is_special_no_niche,
736                    discr_range_of_repr,
737                    discriminants_iter(),
738                    !maybe_unsized,
739                )
740                .map_err(|err| map_error(cx, ty, err))?;
741
742            if !maybe_unsized && layout.is_unsized() {
743                ::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:#?}");
744            }
745
746            // If the struct tail is sized and can be unsized, check that unsizing doesn't move the fields around.
747            if truecfg!(debug_assertions)
748                && maybe_unsized
749                && def
750                    .non_enum_variant()
751                    .tail()
752                    .ty(tcx, args)
753                    .skip_norm_wip()
754                    .is_sized(tcx, cx.typing_env)
755            {
756                let mut variants = variants;
757                let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
758                *variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement;
759
760                let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum(
761                    &def.repr(),
762                    &variants,
763                    def.is_enum(),
764                    is_special_no_niche,
765                    discr_range_of_repr,
766                    discriminants_iter(),
767                    !maybe_unsized,
768                ) else {
769                    ::rustc_middle::util::bug::bug_fmt(format_args!("failed to compute unsized layout of {0:?}",
        ty));bug!("failed to compute unsized layout of {ty:?}");
770                };
771
772                let FieldsShape::Arbitrary { offsets: sized_offsets, .. } = &layout.fields else {
773                    ::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);
774                };
775                let FieldsShape::Arbitrary { offsets: unsized_offsets, .. } =
776                    &unsized_layout.fields
777                else {
778                    ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected FieldsShape for unsized layout of {1:?}: {0:?}",
        unsized_layout.fields, ty));bug!(
779                        "unexpected FieldsShape for unsized layout of {ty:?}: {:?}",
780                        unsized_layout.fields
781                    );
782                };
783
784                let (sized_tail, sized_fields) = sized_offsets.raw.split_last().unwrap();
785                let (unsized_tail, unsized_fields) = unsized_offsets.raw.split_last().unwrap();
786
787                if sized_fields != unsized_fields {
788                    ::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:?}");
789                }
790
791                if sized_tail < unsized_tail {
792                    ::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:?}");
793                }
794            }
795
796            tcx.mk_layout(layout)
797        }
798
799        ty::UnsafeBinder(bound_ty) => {
800            let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
801            cx.layout_of(ty)?.layout
802        }
803
804        // Types with no meaningful known layout.
805        ty::Param(_) | ty::Placeholder(..) => {
806            return Err(error(cx, LayoutError::TooGeneric(ty)));
807        }
808
809        ty::Alias(..) => {
810            // In case we're still in a generic context, aliases might be rigid. E.g.
811            // if we've got a `T: Trait` where-bound, `T::Assoc` cannot be normalized
812            // in the current context.
813            //
814            // For some builtin traits, generic aliases can be rigid even in an empty environment,
815            // e.g. `<T as Pointee>::Metadata`.
816            //
817            // Due to trivial bounds, this can even be the case if the alias does not reference
818            // any generic parameters, e.g. a `for<'a> u32: Trait<'a>` where-bound means that
819            // `<u32 as Trait<'static>>::Assoc` is rigid.
820            let err = if ty.has_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
821                LayoutError::TooGeneric(ty)
822            } else {
823                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!(
824                    "unexpected rigid alias in layout_of after normalization: {ty:?}"
825                )))
826            };
827            return Err(error(cx, err));
828        }
829
830        ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => {
831            // `ty::Error` is handled at the top of this function.
832            ::rustc_middle::util::bug::bug_fmt(format_args!("layout_of: unexpected type `{0}`",
        ty))bug!("layout_of: unexpected type `{ty}`")
833        }
834    })
835}
836
837fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) {
838    // Ignore layouts that are done with non-empty environments or
839    // non-monomorphic layouts, as the user only wants to see the stuff
840    // resulting from the final codegen session.
841    if layout.ty.has_non_region_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
842        return;
843    }
844
845    // (delay format until we actually need it)
846    let record = |kind, packed, opt_discr_size, variants| {
847        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));
848        cx.tcx().sess.code_stats.record_type_size(
849            kind,
850            type_desc,
851            layout.align.abi,
852            layout.size,
853            packed,
854            opt_discr_size,
855            variants,
856        );
857    };
858
859    match *layout.ty.kind() {
860        ty::Adt(adt_def, _) => {
861            {
    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:861",
                        "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(861u32),
                        ::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);
862            let adt_kind = adt_def.adt_kind();
863            let adt_packed = adt_def.repr().pack.is_some();
864            let (variant_infos, opt_discr_size) = variant_info_for_adt(cx, layout, adt_def);
865            record(adt_kind.into(), adt_packed, opt_discr_size, variant_infos);
866        }
867
868        ty::Coroutine(def_id, args) => {
869            {
    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:869",
                        "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(869u32),
                        ::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);
870            // Coroutines always have a begin/poisoned/end state with additional suspend points
871            let (variant_infos, opt_discr_size) =
872                variant_info_for_coroutine(cx, layout, def_id, args);
873            record(DataTypeKind::Coroutine, false, opt_discr_size, variant_infos);
874        }
875
876        ty::Closure(..) => {
877            {
    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:877",
                        "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(877u32),
                        ::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);
878            record(DataTypeKind::Closure, false, None, ::alloc::vec::Vec::new()vec![]);
879        }
880
881        _ => {
882            {
    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:882",
                        "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(882u32),
                        ::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);
883        }
884    };
885}
886
887fn variant_info_for_adt<'tcx>(
888    cx: &LayoutCx<'tcx>,
889    layout: TyAndLayout<'tcx>,
890    adt_def: AdtDef<'tcx>,
891) -> (Vec<VariantInfo>, Option<Size>) {
892    let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
893        let mut min_size = Size::ZERO;
894        let field_info: Vec<_> = flds
895            .iter()
896            .enumerate()
897            .map(|(i, &name)| {
898                let field_layout = layout.field(cx, i);
899                let offset = layout.fields.offset(i);
900                min_size = min_size.max(offset + field_layout.size);
901                FieldInfo {
902                    kind: FieldKind::AdtField,
903                    name,
904                    offset: offset.bytes(),
905                    size: field_layout.size.bytes(),
906                    align: field_layout.align.bytes(),
907                    type_name: None,
908                }
909            })
910            .collect();
911
912        VariantInfo {
913            name: n,
914            kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact },
915            align: layout.align.bytes(),
916            size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() },
917            fields: field_info,
918        }
919    };
920
921    match layout.variants {
922        Variants::Empty => (::alloc::vec::Vec::new()vec![], None),
923
924        Variants::Single { index } => {
925            {
    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:925",
                        "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(925u32),
                        ::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);
926            let variant_def = &adt_def.variant(index);
927            let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
928            (::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)
929        }
930
931        Variants::Multiple { tag, ref tag_encoding, .. } => {
932            {
    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:932",
                        "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(932u32),
                        ::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!(
933                "print-type-size `{:#?}` adt general variants def {}",
934                layout.ty,
935                adt_def.variants().len()
936            );
937            let variant_infos: Vec<_> = adt_def
938                .variants()
939                .iter_enumerated()
940                .map(|(i, variant_def)| {
941                    let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
942                    build_variant_info(Some(variant_def.name), &fields, layout.for_variant(cx, i))
943                })
944                .collect();
945
946            (
947                variant_infos,
948                match tag_encoding {
949                    TagEncoding::Direct => Some(tag.size(cx)),
950                    _ => None,
951                },
952            )
953        }
954    }
955}
956
957fn variant_info_for_coroutine<'tcx>(
958    cx: &LayoutCx<'tcx>,
959    layout: TyAndLayout<'tcx>,
960    def_id: DefId,
961    args: ty::GenericArgsRef<'tcx>,
962) -> (Vec<VariantInfo>, Option<Size>) {
963    use itertools::Itertools;
964
965    let Variants::Multiple { tag, ref tag_encoding, tag_field, .. } = layout.variants else {
966        return (::alloc::vec::Vec::new()vec![], None);
967    };
968
969    let coroutine = cx.tcx().coroutine_layout(def_id, args).unwrap();
970    let upvar_names = cx.tcx().closure_saved_names_of_captured_variables(def_id);
971
972    let mut upvars_size = Size::ZERO;
973    let upvar_fields: Vec<_> = args
974        .as_coroutine()
975        .upvar_tys()
976        .iter()
977        .zip_eq(upvar_names)
978        .enumerate()
979        .map(|(field_idx, (_, name))| {
980            let field_layout = layout.field(cx, field_idx);
981            let offset = layout.fields.offset(field_idx);
982            upvars_size = upvars_size.max(offset + field_layout.size);
983            FieldInfo {
984                kind: FieldKind::Upvar,
985                name: *name,
986                offset: offset.bytes(),
987                size: field_layout.size.bytes(),
988                align: field_layout.align.bytes(),
989                type_name: None,
990            }
991        })
992        .collect();
993
994    let mut variant_infos: Vec<_> = coroutine
995        .variant_fields
996        .iter_enumerated()
997        .map(|(variant_idx, variant_def)| {
998            let variant_layout = layout.for_variant(cx, variant_idx);
999            let mut variant_size = Size::ZERO;
1000            let fields = variant_def
1001                .iter()
1002                .enumerate()
1003                .map(|(field_idx, local)| {
1004                    let field_name = coroutine.field_tys[*local].debuginfo_name;
1005                    let field_layout = variant_layout.field(cx, field_idx);
1006                    let offset = variant_layout.fields.offset(field_idx);
1007                    // The struct is as large as the last field's end
1008                    variant_size = variant_size.max(offset + field_layout.size);
1009                    FieldInfo {
1010                        kind: FieldKind::CoroutineLocal,
1011                        name: field_name.unwrap_or_else(|| {
1012                            Symbol::intern(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!(".coroutine_field{0}",
                local.as_usize()))
    })format!(".coroutine_field{}", local.as_usize()))
1013                        }),
1014                        offset: offset.bytes(),
1015                        size: field_layout.size.bytes(),
1016                        align: field_layout.align.bytes(),
1017                        // Include the type name if there is no field name, or if the name is the
1018                        // __awaitee placeholder symbol which means a child future being `.await`ed.
1019                        type_name: (field_name.is_none() || field_name == Some(sym::__awaitee))
1020                            .then(|| Symbol::intern(&field_layout.ty.to_string())),
1021                    }
1022                })
1023                .chain(upvar_fields.iter().copied())
1024                .collect();
1025
1026            // If the variant has no state-specific fields, then it's the size of the upvars.
1027            if variant_size == Size::ZERO {
1028                variant_size = upvars_size;
1029            }
1030
1031            // This `if` deserves some explanation.
1032            //
1033            // The layout code has a choice of where to place the discriminant of this coroutine.
1034            // If the discriminant of the coroutine is placed early in the layout (before the
1035            // variant's own fields), then it'll implicitly be counted towards the size of the
1036            // variant, since we use the maximum offset to calculate size.
1037            //    (side-note: I know this is a bit problematic given upvars placement, etc).
1038            //
1039            // This is important, since the layout printing code always subtracts this discriminant
1040            // size from the variant size if the struct is "enum"-like, so failing to account for it
1041            // will either lead to numerical underflow, or an underreported variant size...
1042            //
1043            // However, if the discriminant is placed past the end of the variant, then we need
1044            // to factor in the size of the discriminant manually. This really should be refactored
1045            // better, but this "works" for now.
1046            if layout.fields.offset(tag_field.as_usize()) >= variant_size {
1047                variant_size += match tag_encoding {
1048                    TagEncoding::Direct => tag.size(cx),
1049                    _ => Size::ZERO,
1050                };
1051            }
1052
1053            VariantInfo {
1054                name: Some(Symbol::intern(&ty::CoroutineArgs::variant_name(variant_idx))),
1055                kind: SizeKind::Exact,
1056                size: variant_size.bytes(),
1057                align: variant_layout.align.bytes(),
1058                fields,
1059            }
1060        })
1061        .collect();
1062
1063    // The first three variants are hardcoded to be `UNRESUMED`, `RETURNED` and `POISONED`.
1064    // We will move the `RETURNED` and `POISONED` elements to the end so we
1065    // are left with a sorting order according to the coroutines yield points:
1066    // First `Unresumed`, then the `SuspendN` followed by `Returned` and `Panicked` (POISONED).
1067    let end_states = variant_infos.drain(1..=2);
1068    let end_states: Vec<_> = end_states.collect();
1069    variant_infos.extend(end_states);
1070
1071    (
1072        variant_infos,
1073        match tag_encoding {
1074            TagEncoding::Direct => Some(tag.size(cx)),
1075            _ => None,
1076        },
1077    )
1078}