Skip to main content

rustc_ty_utils/
layout.rs

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