Skip to main content

rustc_middle/ty/
layout.rs

1use std::ops::Bound;
2use std::{cmp, fmt};
3
4use rustc_abi::{
5    AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
6    PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
7    TyAbiInterface, VariantIdx, Variants,
8};
9use rustc_error_messages::DiagMessage;
10use rustc_errors::{
11    Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
12    inline_fluent,
13};
14use rustc_hir::LangItem;
15use rustc_hir::def_id::DefId;
16use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
17use rustc_session::config::OptLevel;
18use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
19use rustc_target::callconv::FnAbi;
20use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
21use tracing::debug;
22use {rustc_abi as abi, rustc_hir as hir};
23
24use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
25use crate::query::TyCtxtAt;
26use crate::traits::ObligationCause;
27use crate::ty::normalize_erasing_regions::NormalizationError;
28use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt};
29
30impl IntegerExt for abi::Integer {
    #[inline]
    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
        use abi::Integer::{I8, I16, I32, I64, I128};
        match (*self, signed) {
            (I8, false) => tcx.types.u8,
            (I16, false) => tcx.types.u16,
            (I32, false) => tcx.types.u32,
            (I64, false) => tcx.types.u64,
            (I128, false) => tcx.types.u128,
            (I8, true) => tcx.types.i8,
            (I16, true) => tcx.types.i16,
            (I32, true) => tcx.types.i32,
            (I64, true) => tcx.types.i64,
            (I128, true) => tcx.types.i128,
        }
    }
    fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> abi::Integer {
        use abi::Integer::{I8, I16, I32, I64, I128};
        match ity {
            ty::IntTy::I8 => I8,
            ty::IntTy::I16 => I16,
            ty::IntTy::I32 => I32,
            ty::IntTy::I64 => I64,
            ty::IntTy::I128 => I128,
            ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
        }
    }
    fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy)
        -> abi::Integer {
        use abi::Integer::{I8, I16, I32, I64, I128};
        match ity {
            ty::UintTy::U8 => I8,
            ty::UintTy::U16 => I16,
            ty::UintTy::U32 => I32,
            ty::UintTy::U64 => I64,
            ty::UintTy::U128 => I128,
            ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
        }
    }
    #[doc =
    " Finds the appropriate Integer type and signedness for the given"]
    #[doc = " signed discriminant range and `#[repr]` attribute."]
    #[doc =
    " N.B.: `u128` values above `i128::MAX` will be treated as signed, but"]
    #[doc = " that shouldn\'t affect anything, other than maybe debuginfo."]
    #[doc = ""]
    #[doc =
    " This is the basis for computing the type of the *tag* of an enum (which can be smaller than"]
    #[doc =
    " the type of the *discriminant*, which is determined by [`ReprOptions::discr_type`])."]
    fn discr_range_of_repr<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>,
        repr: &ReprOptions, min: i128, max: i128) -> (abi::Integer, bool) {
        let unsigned_fit =
            abi::Integer::fit_unsigned(cmp::max(min as u128, max as u128));
        let signed_fit =
            cmp::max(abi::Integer::fit_signed(min),
                abi::Integer::fit_signed(max));
        if let Some(ity) = repr.int {
            let discr = abi::Integer::from_attr(&tcx, ity);
            let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
            if discr < fit {
                crate::util::bug::bug_fmt(format_args!("Integer::repr_discr: `#[repr]` hint too small for discriminant range of enum `{0}`",
                        ty))
            }
            return (discr, ity.is_signed());
        }
        let at_least =
            if repr.c() {
                tcx.data_layout().c_enum_min_size
            } else { abi::Integer::I8 };
        if unsigned_fit <= signed_fit {
            (cmp::max(unsigned_fit, at_least), false)
        } else { (cmp::max(signed_fit, at_least), true) }
    }
}#[extension(pub trait IntegerExt)]
31impl abi::Integer {
32    #[inline]
33    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
34        use abi::Integer::{I8, I16, I32, I64, I128};
35        match (*self, signed) {
36            (I8, false) => tcx.types.u8,
37            (I16, false) => tcx.types.u16,
38            (I32, false) => tcx.types.u32,
39            (I64, false) => tcx.types.u64,
40            (I128, false) => tcx.types.u128,
41            (I8, true) => tcx.types.i8,
42            (I16, true) => tcx.types.i16,
43            (I32, true) => tcx.types.i32,
44            (I64, true) => tcx.types.i64,
45            (I128, true) => tcx.types.i128,
46        }
47    }
48
49    fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> abi::Integer {
50        use abi::Integer::{I8, I16, I32, I64, I128};
51        match ity {
52            ty::IntTy::I8 => I8,
53            ty::IntTy::I16 => I16,
54            ty::IntTy::I32 => I32,
55            ty::IntTy::I64 => I64,
56            ty::IntTy::I128 => I128,
57            ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
58        }
59    }
60    fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> abi::Integer {
61        use abi::Integer::{I8, I16, I32, I64, I128};
62        match ity {
63            ty::UintTy::U8 => I8,
64            ty::UintTy::U16 => I16,
65            ty::UintTy::U32 => I32,
66            ty::UintTy::U64 => I64,
67            ty::UintTy::U128 => I128,
68            ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
69        }
70    }
71
72    /// Finds the appropriate Integer type and signedness for the given
73    /// signed discriminant range and `#[repr]` attribute.
74    /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
75    /// that shouldn't affect anything, other than maybe debuginfo.
76    ///
77    /// This is the basis for computing the type of the *tag* of an enum (which can be smaller than
78    /// the type of the *discriminant*, which is determined by [`ReprOptions::discr_type`]).
79    fn discr_range_of_repr<'tcx>(
80        tcx: TyCtxt<'tcx>,
81        ty: Ty<'tcx>,
82        repr: &ReprOptions,
83        min: i128,
84        max: i128,
85    ) -> (abi::Integer, bool) {
86        // Theoretically, negative values could be larger in unsigned representation
87        // than the unsigned representation of the signed minimum. However, if there
88        // are any negative values, the only valid unsigned representation is u128
89        // which can fit all i128 values, so the result remains unaffected.
90        let unsigned_fit = abi::Integer::fit_unsigned(cmp::max(min as u128, max as u128));
91        let signed_fit = cmp::max(abi::Integer::fit_signed(min), abi::Integer::fit_signed(max));
92
93        if let Some(ity) = repr.int {
94            let discr = abi::Integer::from_attr(&tcx, ity);
95            let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
96            if discr < fit {
97                bug!(
98                    "Integer::repr_discr: `#[repr]` hint too small for \
99                      discriminant range of enum `{}`",
100                    ty
101                )
102            }
103            return (discr, ity.is_signed());
104        }
105
106        let at_least = if repr.c() {
107            // This is usually I32, however it can be different on some platforms,
108            // notably hexagon and arm-none/thumb-none
109            tcx.data_layout().c_enum_min_size
110        } else {
111            // repr(Rust) enums try to be as small as possible
112            abi::Integer::I8
113        };
114
115        // Pick the smallest fit. Prefer unsigned; that matches clang in cases where this makes a
116        // difference (https://godbolt.org/z/h4xEasW1d) so it is crucial for repr(C).
117        if unsigned_fit <= signed_fit {
118            (cmp::max(unsigned_fit, at_least), false)
119        } else {
120            (cmp::max(signed_fit, at_least), true)
121        }
122    }
123}
124
125impl FloatExt for abi::Float {
    #[inline]
    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
        use abi::Float::*;
        match *self {
            F16 => tcx.types.f16,
            F32 => tcx.types.f32,
            F64 => tcx.types.f64,
            F128 => tcx.types.f128,
        }
    }
    fn from_float_ty(fty: ty::FloatTy) -> Self {
        use abi::Float::*;
        match fty {
            ty::FloatTy::F16 => F16,
            ty::FloatTy::F32 => F32,
            ty::FloatTy::F64 => F64,
            ty::FloatTy::F128 => F128,
        }
    }
}#[extension(pub trait FloatExt)]
126impl abi::Float {
127    #[inline]
128    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
129        use abi::Float::*;
130        match *self {
131            F16 => tcx.types.f16,
132            F32 => tcx.types.f32,
133            F64 => tcx.types.f64,
134            F128 => tcx.types.f128,
135        }
136    }
137
138    fn from_float_ty(fty: ty::FloatTy) -> Self {
139        use abi::Float::*;
140        match fty {
141            ty::FloatTy::F16 => F16,
142            ty::FloatTy::F32 => F32,
143            ty::FloatTy::F64 => F64,
144            ty::FloatTy::F128 => F128,
145        }
146    }
147}
148
149impl PrimitiveExt for Primitive {
    #[inline]
    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
        match *self {
            Primitive::Int(i, signed) => i.to_ty(tcx, signed),
            Primitive::Float(f) => f.to_ty(tcx),
            Primitive::Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit),
        }
    }
    #[doc = " Return an *integer* type matching this primitive."]
    #[doc = " Useful in particular when dealing with enum discriminants."]
    #[inline]
    fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
        match *self {
            Primitive::Int(i, signed) => i.to_ty(tcx, signed),
            Primitive::Pointer(_) => {
                let signed = false;
                tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
            }
            Primitive::Float(_) =>
                crate::util::bug::bug_fmt(format_args!("floats do not have an int type")),
        }
    }
}#[extension(pub trait PrimitiveExt)]
150impl Primitive {
151    #[inline]
152    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
153        match *self {
154            Primitive::Int(i, signed) => i.to_ty(tcx, signed),
155            Primitive::Float(f) => f.to_ty(tcx),
156            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
157            Primitive::Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit),
158        }
159    }
160
161    /// Return an *integer* type matching this primitive.
162    /// Useful in particular when dealing with enum discriminants.
163    #[inline]
164    fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
165        match *self {
166            Primitive::Int(i, signed) => i.to_ty(tcx, signed),
167            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
168            Primitive::Pointer(_) => {
169                let signed = false;
170                tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
171            }
172            Primitive::Float(_) => bug!("floats do not have an int type"),
173        }
174    }
175}
176
177/// The first half of a wide pointer.
178///
179/// - For a trait object, this is the address of the box.
180/// - For a slice, this is the base address.
181pub const WIDE_PTR_ADDR: usize = 0;
182
183/// The second half of a wide pointer.
184///
185/// - For a trait object, this is the address of the vtable.
186/// - For a slice, this is the length.
187pub const WIDE_PTR_EXTRA: usize = 1;
188
189pub const MAX_SIMD_LANES: u64 = rustc_abi::MAX_SIMD_LANES;
190
191/// Used in `check_validity_requirement` to indicate the kind of initialization
192/// that is checked to be valid
193#[derive(#[automatically_derived]
impl ::core::marker::Copy for ValidityRequirement { }Copy, #[automatically_derived]
impl ::core::clone::Clone for ValidityRequirement {
    #[inline]
    fn clone(&self) -> ValidityRequirement { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for ValidityRequirement {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                ValidityRequirement::Inhabited => "Inhabited",
                ValidityRequirement::Zero => "Zero",
                ValidityRequirement::UninitMitigated0x01Fill =>
                    "UninitMitigated0x01Fill",
                ValidityRequirement::Uninit => "Uninit",
            })
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for ValidityRequirement {
    #[inline]
    fn eq(&self, other: &ValidityRequirement) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ValidityRequirement {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for ValidityRequirement {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash, const _: () =
    {
        impl<'__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            for ValidityRequirement {
            #[inline]
            fn hash_stable(&self,
                __hcx:
                    &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
                match *self {
                    ValidityRequirement::Inhabited => {}
                    ValidityRequirement::Zero => {}
                    ValidityRequirement::UninitMitigated0x01Fill => {}
                    ValidityRequirement::Uninit => {}
                }
            }
        }
    };HashStable)]
194pub enum ValidityRequirement {
195    Inhabited,
196    Zero,
197    /// The return value of mem::uninitialized, 0x01
198    /// (unless -Zstrict-init-checks is on, in which case it's the same as Uninit).
199    UninitMitigated0x01Fill,
200    /// True uninitialized memory.
201    Uninit,
202}
203
204impl ValidityRequirement {
205    pub fn from_intrinsic(intrinsic: Symbol) -> Option<Self> {
206        match intrinsic {
207            sym::assert_inhabited => Some(Self::Inhabited),
208            sym::assert_zero_valid => Some(Self::Zero),
209            sym::assert_mem_uninitialized_valid => Some(Self::UninitMitigated0x01Fill),
210            _ => None,
211        }
212    }
213}
214
215impl fmt::Display for ValidityRequirement {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        match self {
218            Self::Inhabited => f.write_str("is inhabited"),
219            Self::Zero => f.write_str("allows being left zeroed"),
220            Self::UninitMitigated0x01Fill => f.write_str("allows being filled with 0x01"),
221            Self::Uninit => f.write_str("allows being left uninitialized"),
222        }
223    }
224}
225
226#[derive(#[automatically_derived]
impl ::core::marker::Copy for SimdLayoutError { }Copy, #[automatically_derived]
impl ::core::clone::Clone for SimdLayoutError {
    #[inline]
    fn clone(&self) -> SimdLayoutError {
        let _: ::core::clone::AssertParamIsClone<u64>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for SimdLayoutError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            SimdLayoutError::ZeroLength =>
                ::core::fmt::Formatter::write_str(f, "ZeroLength"),
            SimdLayoutError::TooManyLanes(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "TooManyLanes", &__self_0),
        }
    }
}Debug, const _: () =
    {
        impl<'__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            for SimdLayoutError {
            #[inline]
            fn hash_stable(&self,
                __hcx:
                    &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
                match *self {
                    SimdLayoutError::ZeroLength => {}
                    SimdLayoutError::TooManyLanes(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for SimdLayoutError {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        SimdLayoutError::ZeroLength => { 0usize }
                        SimdLayoutError::TooManyLanes(ref __binding_0) => { 1usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    SimdLayoutError::ZeroLength => {}
                    SimdLayoutError::TooManyLanes(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for SimdLayoutError {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => { SimdLayoutError::ZeroLength }
                    1usize => {
                        SimdLayoutError::TooManyLanes(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `SimdLayoutError`, expected 0..2, actual {0}",
                                n));
                    }
                }
            }
        }
    };TyDecodable)]
227pub enum SimdLayoutError {
228    /// The vector has 0 lanes.
229    ZeroLength,
230    /// The vector has more lanes than supported or permitted by
231    /// #\[rustc_simd_monomorphize_lane_limit\].
232    TooManyLanes(u64),
233}
234
235#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for LayoutError<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for LayoutError<'tcx> {
    #[inline]
    fn clone(&self) -> LayoutError<'tcx> {
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<SimdLayoutError>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<NormalizationError<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<ErrorGuaranteed>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for LayoutError<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            LayoutError::Unknown(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Unknown", &__self_0),
            LayoutError::SizeOverflow(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "SizeOverflow", &__self_0),
            LayoutError::InvalidSimd { ty: __self_0, kind: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "InvalidSimd", "ty", __self_0, "kind", &__self_1),
            LayoutError::TooGeneric(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "TooGeneric", &__self_0),
            LayoutError::NormalizationFailure(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "NormalizationFailure", __self_0, &__self_1),
            LayoutError::ReferencesError(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ReferencesError", &__self_0),
            LayoutError::Cycle(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Cycle",
                    &__self_0),
        }
    }
}Debug, const _: () =
    {
        impl<'tcx, '__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            for LayoutError<'tcx> {
            #[inline]
            fn hash_stable(&self,
                __hcx:
                    &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
                match *self {
                    LayoutError::Unknown(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                    LayoutError::SizeOverflow(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                    LayoutError::InvalidSimd {
                        ty: ref __binding_0, kind: ref __binding_1 } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                    LayoutError::TooGeneric(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                    LayoutError::NormalizationFailure(ref __binding_0,
                        ref __binding_1) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                    LayoutError::ReferencesError(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                    LayoutError::Cycle(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for LayoutError<'tcx> {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        LayoutError::Unknown(ref __binding_0) => { 0usize }
                        LayoutError::SizeOverflow(ref __binding_0) => { 1usize }
                        LayoutError::InvalidSimd {
                            ty: ref __binding_0, kind: ref __binding_1 } => {
                            2usize
                        }
                        LayoutError::TooGeneric(ref __binding_0) => { 3usize }
                        LayoutError::NormalizationFailure(ref __binding_0,
                            ref __binding_1) => {
                            4usize
                        }
                        LayoutError::ReferencesError(ref __binding_0) => { 5usize }
                        LayoutError::Cycle(ref __binding_0) => { 6usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    LayoutError::Unknown(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    LayoutError::SizeOverflow(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    LayoutError::InvalidSimd {
                        ty: ref __binding_0, kind: ref __binding_1 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                    LayoutError::TooGeneric(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    LayoutError::NormalizationFailure(ref __binding_0,
                        ref __binding_1) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                    LayoutError::ReferencesError(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    LayoutError::Cycle(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for LayoutError<'tcx> {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        LayoutError::Unknown(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        LayoutError::SizeOverflow(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    2usize => {
                        LayoutError::InvalidSimd {
                            ty: ::rustc_serialize::Decodable::decode(__decoder),
                            kind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    3usize => {
                        LayoutError::TooGeneric(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    4usize => {
                        LayoutError::NormalizationFailure(::rustc_serialize::Decodable::decode(__decoder),
                            ::rustc_serialize::Decodable::decode(__decoder))
                    }
                    5usize => {
                        LayoutError::ReferencesError(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    6usize => {
                        LayoutError::Cycle(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `LayoutError`, expected 0..7, actual {0}",
                                n));
                    }
                }
            }
        }
    };TyDecodable)]
236pub enum LayoutError<'tcx> {
237    /// A type doesn't have a sensible layout.
238    ///
239    /// This variant is used for layout errors that don't necessarily cause
240    /// compile errors.
241    ///
242    /// For example, this can happen if a struct contains an unsized type in a
243    /// non-tail field, but has an unsatisfiable bound like `str: Sized`.
244    Unknown(Ty<'tcx>),
245    /// The size of a type exceeds [`TargetDataLayout::obj_size_bound`].
246    SizeOverflow(Ty<'tcx>),
247    /// A SIMD vector has invalid layout, such as zero-length or too many lanes.
248    InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError },
249    /// The layout can vary due to a generic parameter.
250    ///
251    /// Unlike `Unknown`, this variant is a "soft" error and indicates that the layout
252    /// may become computable after further instantiating the generic parameter(s).
253    TooGeneric(Ty<'tcx>),
254    /// An alias failed to normalize.
255    ///
256    /// This variant is necessary, because, due to trait solver incompleteness, it is
257    /// possible than an alias that was rigid during analysis fails to normalize after
258    /// revealing opaque types.
259    ///
260    /// See `tests/ui/layout/normalization-failure.rs` for an example.
261    NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
262    /// A non-layout error is reported elsewhere.
263    ReferencesError(ErrorGuaranteed),
264    /// A type has cyclic layout, i.e. the type contains itself without indirection.
265    Cycle(ErrorGuaranteed),
266}
267
268impl<'tcx> LayoutError<'tcx> {
269    pub fn diagnostic_message(&self) -> DiagMessage {
270        use LayoutError::*;
271
272        match self {
273            Unknown(_) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the type `{$ty}` has an unknown layout"))inline_fluent!("the type `{$ty}` has an unknown layout"),
274            SizeOverflow(_) => {
275                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("values of the type `{$ty}` are too big for the target architecture"))inline_fluent!("values of the type `{$ty}` are too big for the target architecture")
276            }
277            InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => {
278                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the SIMD type `{$ty}` has more elements than the limit {$max_lanes}"))inline_fluent!(
279                    "the SIMD type `{$ty}` has more elements than the limit {$max_lanes}"
280                )
281            }
282            InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => {
283                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the SIMD type `{$ty}` has zero elements"))inline_fluent!("the SIMD type `{$ty}` has zero elements")
284            }
285            TooGeneric(_) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the type `{$ty}` does not have a fixed layout"))inline_fluent!("the type `{$ty}` does not have a fixed layout"),
286            NormalizationFailure(_, _) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized"))inline_fluent!(
287                "unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized"
288            ),
289            Cycle(_) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("a cycle occurred during layout computation"))inline_fluent!("a cycle occurred during layout computation"),
290            ReferencesError(_) => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the type has an unknown layout"))inline_fluent!("the type has an unknown layout"),
291        }
292    }
293
294    pub fn into_diagnostic(self) -> crate::error::LayoutError<'tcx> {
295        use LayoutError::*;
296
297        use crate::error::LayoutError as E;
298        match self {
299            Unknown(ty) => E::Unknown { ty },
300            SizeOverflow(ty) => E::Overflow { ty },
301            InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
302                E::SimdTooManyLanes { ty, max_lanes }
303            }
304            InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty },
305            TooGeneric(ty) => E::TooGeneric { ty },
306            NormalizationFailure(ty, e) => {
307                E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
308            }
309            Cycle(_) => E::Cycle,
310            ReferencesError(_) => E::ReferencesError,
311        }
312    }
313}
314
315// FIXME: Once the other errors that embed this error have been converted to translatable
316// diagnostics, this Display impl should be removed.
317impl<'tcx> fmt::Display for LayoutError<'tcx> {
318    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319        match *self {
320            LayoutError::Unknown(ty) => f.write_fmt(format_args!("the type `{0}` has an unknown layout", ty))write!(f, "the type `{ty}` has an unknown layout"),
321            LayoutError::TooGeneric(ty) => {
322                f.write_fmt(format_args!("the type `{0}` does not have a fixed layout", ty))write!(f, "the type `{ty}` does not have a fixed layout")
323            }
324            LayoutError::SizeOverflow(ty) => {
325                f.write_fmt(format_args!("values of the type `{0}` are too big for the target architecture",
        ty))write!(f, "values of the type `{ty}` are too big for the target architecture")
326            }
327            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
328                f.write_fmt(format_args!("the SIMD type `{0}` has more elements than the limit {1}",
        ty, max_lanes))write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}")
329            }
330            LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => {
331                f.write_fmt(format_args!("the SIMD type `{0}` has zero elements", ty))write!(f, "the SIMD type `{ty}` has zero elements")
332            }
333            LayoutError::NormalizationFailure(t, e) => f.write_fmt(format_args!("unable to determine layout for `{0}` because `{1}` cannot be normalized",
        t, e.get_type_for_failure()))write!(
334                f,
335                "unable to determine layout for `{}` because `{}` cannot be normalized",
336                t,
337                e.get_type_for_failure()
338            ),
339            LayoutError::Cycle(_) => f.write_fmt(format_args!("a cycle occurred during layout computation"))write!(f, "a cycle occurred during layout computation"),
340            LayoutError::ReferencesError(_) => f.write_fmt(format_args!("the type has an unknown layout"))write!(f, "the type has an unknown layout"),
341        }
342    }
343}
344
345impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
346    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
347        self.to_string().into_diag_arg(&mut None)
348    }
349}
350
351#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for LayoutCx<'tcx> {
    #[inline]
    fn clone(&self) -> LayoutCx<'tcx> {
        let _:
                ::core::clone::AssertParamIsClone<abi::LayoutCalculator<TyCtxt<'tcx>>>;
        let _: ::core::clone::AssertParamIsClone<ty::TypingEnv<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for LayoutCx<'tcx> { }Copy)]
352pub struct LayoutCx<'tcx> {
353    pub calc: abi::LayoutCalculator<TyCtxt<'tcx>>,
354    pub typing_env: ty::TypingEnv<'tcx>,
355}
356
357impl<'tcx> LayoutCx<'tcx> {
358    pub fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self {
359        Self { calc: abi::LayoutCalculator::new(tcx), typing_env }
360    }
361}
362
363/// Type size "skeleton", i.e., the only information determining a type's size.
364/// While this is conservative, (aside from constant sizes, only pointers,
365/// newtypes thereof and null pointer optimized enums are allowed), it is
366/// enough to statically check common use cases of transmute.
367#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for SizeSkeleton<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for SizeSkeleton<'tcx> {
    #[inline]
    fn clone(&self) -> SizeSkeleton<'tcx> {
        let _: ::core::clone::AssertParamIsClone<Size>;
        let _: ::core::clone::AssertParamIsClone<Option<Align>>;
        let _: ::core::clone::AssertParamIsClone<ty::Const<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for SizeSkeleton<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            SizeSkeleton::Known(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Known",
                    __self_0, &__self_1),
            SizeSkeleton::Generic(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Generic", &__self_0),
            SizeSkeleton::Pointer { non_zero: __self_0, tail: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Pointer", "non_zero", __self_0, "tail", &__self_1),
        }
    }
}Debug)]
368pub enum SizeSkeleton<'tcx> {
369    /// Any statically computable Layout.
370    /// Alignment can be `None` if unknown.
371    Known(Size, Option<Align>),
372
373    /// This is a generic const expression (i.e. N * 2), which may contain some parameters.
374    /// It must be of type usize, and represents the size of a type in bytes.
375    /// It is not required to be evaluatable to a concrete value, but can be used to check
376    /// that another SizeSkeleton is of equal size.
377    Generic(ty::Const<'tcx>),
378
379    /// A potentially-wide pointer.
380    Pointer {
381        /// If true, this pointer is never null.
382        non_zero: bool,
383        /// The type which determines the unsized metadata, if any,
384        /// of this pointer. Either a type parameter or a projection
385        /// depending on one, with regions erased.
386        tail: Ty<'tcx>,
387    },
388}
389
390impl<'tcx> SizeSkeleton<'tcx> {
391    pub fn compute(
392        ty: Ty<'tcx>,
393        tcx: TyCtxt<'tcx>,
394        typing_env: ty::TypingEnv<'tcx>,
395    ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> {
396        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());
397
398        // First try computing a static layout.
399        let err = match tcx.layout_of(typing_env.as_query_input(ty)) {
400            Ok(layout) => {
401                if layout.is_sized() {
402                    return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
403                } else {
404                    // Just to be safe, don't claim a known layout for unsized types.
405                    return Err(tcx.arena.alloc(LayoutError::Unknown(ty)));
406                }
407            }
408            Err(err @ LayoutError::TooGeneric(_)) => err,
409            // We can't extract SizeSkeleton info from other layout errors
410            Err(
411                e @ LayoutError::Cycle(_)
412                | e @ LayoutError::Unknown(_)
413                | e @ LayoutError::SizeOverflow(_)
414                | e @ LayoutError::InvalidSimd { .. }
415                | e @ LayoutError::NormalizationFailure(..)
416                | e @ LayoutError::ReferencesError(_),
417            ) => return Err(e),
418        };
419
420        match *ty.kind() {
421            ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
422                let non_zero = !ty.is_raw_ptr();
423
424                let tail = tcx.struct_tail_raw(
425                    pointee,
426                    &ObligationCause::dummy(),
427                    |ty| match tcx.try_normalize_erasing_regions(typing_env, ty) {
428                        Ok(ty) => ty,
429                        Err(e) => Ty::new_error_with_message(
430                            tcx,
431                            DUMMY_SP,
432                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("normalization failed for {0} but no errors reported",
                e.get_type_for_failure()))
    })format!(
433                                "normalization failed for {} but no errors reported",
434                                e.get_type_for_failure()
435                            ),
436                        ),
437                    },
438                    || {},
439                );
440
441                match tail.kind() {
442                    ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
443                        if true {
    if !tail.has_non_region_param() {
        ::core::panicking::panic("assertion failed: tail.has_non_region_param()")
    };
};debug_assert!(tail.has_non_region_param());
444                        Ok(SizeSkeleton::Pointer {
445                            non_zero,
446                            tail: tcx.erase_and_anonymize_regions(tail),
447                        })
448                    }
449                    ty::Error(guar) => {
450                        // Fixes ICE #124031
451                        return Err(tcx.arena.alloc(LayoutError::ReferencesError(*guar)));
452                    }
453                    _ => crate::util::bug::bug_fmt(format_args!("SizeSkeleton::compute({0}): layout errored ({1:?}), yet tail `{2}` is not a type parameter or a projection",
        ty, err, tail))bug!(
454                        "SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \
455                              tail `{tail}` is not a type parameter or a projection",
456                    ),
457                }
458            }
459            ty::Array(inner, len) if tcx.features().transmute_generic_consts() => {
460                let len_eval = len.try_to_target_usize(tcx);
461                if len_eval == Some(0) {
462                    return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));
463                }
464
465                match SizeSkeleton::compute(inner, tcx, typing_env)? {
466                    // This may succeed because the multiplication of two types may overflow
467                    // but a single size of a nested array will not.
468                    SizeSkeleton::Known(s, a) => {
469                        if let Some(c) = len_eval {
470                            let size = s
471                                .bytes()
472                                .checked_mul(c)
473                                .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
474                            // Alignment is unchanged by arrays.
475                            return Ok(SizeSkeleton::Known(Size::from_bytes(size), a));
476                        }
477                        Err(err)
478                    }
479                    SizeSkeleton::Pointer { .. } | SizeSkeleton::Generic(_) => Err(err),
480                }
481            }
482
483            ty::Adt(def, args) => {
484                // Only newtypes and enums w/ nullable pointer optimization.
485                if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
486                    return Err(err);
487                }
488
489                // Get a zero-sized variant or a pointer newtype.
490                let zero_or_ptr_variant = |i| {
491                    let i = VariantIdx::from_usize(i);
492                    let fields =
493                        def.variant(i).fields.iter().map(|field| {
494                            SizeSkeleton::compute(field.ty(tcx, args), tcx, typing_env)
495                        });
496                    let mut ptr = None;
497                    for field in fields {
498                        let field = field?;
499                        match field {
500                            SizeSkeleton::Known(size, align) => {
501                                let is_1zst = size.bytes() == 0
502                                    && align.is_some_and(|align| align.bytes() == 1);
503                                if !is_1zst {
504                                    return Err(err);
505                                }
506                            }
507                            SizeSkeleton::Pointer { .. } => {
508                                if ptr.is_some() {
509                                    return Err(err);
510                                }
511                                ptr = Some(field);
512                            }
513                            SizeSkeleton::Generic(_) => {
514                                return Err(err);
515                            }
516                        }
517                    }
518                    Ok(ptr)
519                };
520
521                let v0 = zero_or_ptr_variant(0)?;
522                // Newtype.
523                if def.variants().len() == 1 {
524                    if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
525                        return Ok(SizeSkeleton::Pointer {
526                            non_zero: non_zero
527                                || match tcx.layout_scalar_valid_range(def.did()) {
528                                    (Bound::Included(start), Bound::Unbounded) => start > 0,
529                                    (Bound::Included(start), Bound::Included(end)) => {
530                                        0 < start && start < end
531                                    }
532                                    _ => false,
533                                },
534                            tail,
535                        });
536                    } else {
537                        return Err(err);
538                    }
539                }
540
541                let v1 = zero_or_ptr_variant(1)?;
542                // Nullable pointer enum optimization.
543                match (v0, v1) {
544                    (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
545                    | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
546                        Ok(SizeSkeleton::Pointer { non_zero: false, tail })
547                    }
548                    _ => Err(err),
549                }
550            }
551
552            ty::Alias(..) => {
553                let normalized = tcx.normalize_erasing_regions(typing_env, ty);
554                if ty == normalized {
555                    Err(err)
556                } else {
557                    SizeSkeleton::compute(normalized, tcx, typing_env)
558                }
559            }
560
561            // Pattern types are always the same size as their base.
562            ty::Pat(base, _) => SizeSkeleton::compute(base, tcx, typing_env),
563
564            _ => Err(err),
565        }
566    }
567
568    pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
569        match (self, other) {
570            (SizeSkeleton::Known(a, _), SizeSkeleton::Known(b, _)) => a == b,
571            (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
572                a == b
573            }
574            // constants are always pre-normalized into a canonical form so this
575            // only needs to check if their pointers are identical.
576            (SizeSkeleton::Generic(a), SizeSkeleton::Generic(b)) => a == b,
577            _ => false,
578        }
579    }
580}
581
582pub trait HasTyCtxt<'tcx>: HasDataLayout {
583    fn tcx(&self) -> TyCtxt<'tcx>;
584}
585
586pub trait HasTypingEnv<'tcx> {
587    fn typing_env(&self) -> ty::TypingEnv<'tcx>;
588
589    /// FIXME(#132279): This method should not be used as in the future
590    /// everything should take a `TypingEnv` instead. Remove it as that point.
591    fn param_env(&self) -> ty::ParamEnv<'tcx> {
592        self.typing_env().param_env
593    }
594}
595
596impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
597    #[inline]
598    fn data_layout(&self) -> &TargetDataLayout {
599        &self.data_layout
600    }
601}
602
603impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
604    fn target_spec(&self) -> &Target {
605        &self.sess.target
606    }
607}
608
609impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
610    fn x86_abi_opt(&self) -> X86Abi {
611        X86Abi {
612            regparm: self.sess.opts.unstable_opts.regparm,
613            reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return,
614        }
615    }
616}
617
618impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
619    #[inline]
620    fn tcx(&self) -> TyCtxt<'tcx> {
621        *self
622    }
623}
624
625impl<'tcx> HasDataLayout for TyCtxtAt<'tcx> {
626    #[inline]
627    fn data_layout(&self) -> &TargetDataLayout {
628        &self.data_layout
629    }
630}
631
632impl<'tcx> HasTargetSpec for TyCtxtAt<'tcx> {
633    fn target_spec(&self) -> &Target {
634        &self.sess.target
635    }
636}
637
638impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
639    #[inline]
640    fn tcx(&self) -> TyCtxt<'tcx> {
641        **self
642    }
643}
644
645impl<'tcx> HasTypingEnv<'tcx> for LayoutCx<'tcx> {
646    fn typing_env(&self) -> ty::TypingEnv<'tcx> {
647        self.typing_env
648    }
649}
650
651impl<'tcx> HasDataLayout for LayoutCx<'tcx> {
652    fn data_layout(&self) -> &TargetDataLayout {
653        self.calc.cx.data_layout()
654    }
655}
656
657impl<'tcx> HasTargetSpec for LayoutCx<'tcx> {
658    fn target_spec(&self) -> &Target {
659        self.calc.cx.target_spec()
660    }
661}
662
663impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> {
664    fn x86_abi_opt(&self) -> X86Abi {
665        self.calc.cx.x86_abi_opt()
666    }
667}
668
669impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
670    fn tcx(&self) -> TyCtxt<'tcx> {
671        self.calc.cx
672    }
673}
674
675pub trait MaybeResult<T> {
676    type Error;
677
678    fn from(x: Result<T, Self::Error>) -> Self;
679    fn to_result(self) -> Result<T, Self::Error>;
680}
681
682impl<T> MaybeResult<T> for T {
683    type Error = !;
684
685    fn from(Ok(x): Result<T, Self::Error>) -> Self {
686        x
687    }
688    fn to_result(self) -> Result<T, Self::Error> {
689        Ok(self)
690    }
691}
692
693impl<T, E> MaybeResult<T> for Result<T, E> {
694    type Error = E;
695
696    fn from(x: Result<T, Self::Error>) -> Self {
697        x
698    }
699    fn to_result(self) -> Result<T, Self::Error> {
700        self
701    }
702}
703
704pub type TyAndLayout<'tcx> = rustc_abi::TyAndLayout<'tcx, Ty<'tcx>>;
705
706/// Trait for contexts that want to be able to compute layouts of types.
707/// This automatically gives access to `LayoutOf`, through a blanket `impl`.
708pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> {
709    /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
710    /// returned from `layout_of` (see also `handle_layout_err`).
711    type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>> = TyAndLayout<'tcx>;
712
713    /// `Span` to use for `tcx.at(span)`, from `layout_of`.
714    // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better?
715    #[inline]
716    fn layout_tcx_at_span(&self) -> Span {
717        DUMMY_SP
718    }
719
720    /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
721    /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
722    ///
723    /// Most `impl`s, which propagate `LayoutError`s, should simply return `err`,
724    /// but this hook allows e.g. codegen to return only `TyAndLayout` from its
725    /// `cx.layout_of(...)`, without any `Result<...>` around it to deal with
726    /// (and any `LayoutError`s are turned into fatal errors or ICEs).
727    fn handle_layout_err(
728        &self,
729        err: LayoutError<'tcx>,
730        span: Span,
731        ty: Ty<'tcx>,
732    ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
733}
734
735/// Blanket extension trait for contexts that can compute layouts of types.
736pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
737    /// Computes the layout of a type. Note that this implicitly
738    /// executes in `TypingMode::PostAnalysis`, and will normalize the input type.
739    #[inline]
740    fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
741        self.spanned_layout_of(ty, DUMMY_SP)
742    }
743
744    /// Computes the layout of a type, at `span`. Note that this implicitly
745    /// executes in `TypingMode::PostAnalysis`, and will normalize the input type.
746    // FIXME(eddyb) avoid passing information like this, and instead add more
747    // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
748    #[inline]
749    fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
750        let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
751        let tcx = self.tcx().at(span);
752
753        MaybeResult::from(
754            tcx.layout_of(self.typing_env().as_query_input(ty))
755                .map_err(|err| self.handle_layout_err(*err, span, ty)),
756        )
757    }
758}
759
760impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
761
762impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
763    type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
764
765    #[inline]
766    fn handle_layout_err(
767        &self,
768        err: LayoutError<'tcx>,
769        _: Span,
770        _: Ty<'tcx>,
771    ) -> &'tcx LayoutError<'tcx> {
772        self.tcx().arena.alloc(err)
773    }
774}
775
776impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
777where
778    C: HasTyCtxt<'tcx> + HasTypingEnv<'tcx>,
779{
780    fn ty_and_layout_for_variant(
781        this: TyAndLayout<'tcx>,
782        cx: &C,
783        variant_index: VariantIdx,
784    ) -> TyAndLayout<'tcx> {
785        let layout = match this.variants {
786            // If all variants but one are uninhabited, the variant layout is the enum layout.
787            Variants::Single { index } if index == variant_index => {
788                return this;
789            }
790
791            Variants::Single { .. } | Variants::Empty => {
792                // Single-variant and no-variant enums *can* have other variants, but those are
793                // uninhabited. Produce a layout that has the right fields for that variant, so that
794                // the rest of the compiler can project fields etc as usual.
795
796                let tcx = cx.tcx();
797                let typing_env = cx.typing_env();
798
799                // Deny calling for_variant more than once for non-Single enums.
800                if let Ok(original_layout) = tcx.layout_of(typing_env.as_query_input(this.ty)) {
801                    match (&original_layout.variants, &this.variants) {
    (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!(original_layout.variants, this.variants);
802                }
803
804                let fields = match this.ty.kind() {
805                    ty::Adt(def, _) if def.variants().is_empty() => {
806                        crate::util::bug::bug_fmt(format_args!("for_variant called on zero-variant enum {0}",
        this.ty))bug!("for_variant called on zero-variant enum {}", this.ty)
807                    }
808                    ty::Adt(def, _) => def.variant(variant_index).fields.len(),
809                    _ => crate::util::bug::bug_fmt(format_args!("`ty_and_layout_for_variant` on unexpected type {0}",
        this.ty))bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
810                };
811                tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields))
812            }
813
814            Variants::Multiple { ref variants, .. } => {
815                cx.tcx().mk_layout(variants[variant_index].clone())
816            }
817        };
818
819        match (&*layout.variants(), &Variants::Single { index: variant_index }) {
    (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.variants(), Variants::Single { index: variant_index });
820
821        TyAndLayout { ty: this.ty, layout }
822    }
823
824    fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
825        enum TyMaybeWithLayout<'tcx> {
826            Ty(Ty<'tcx>),
827            TyAndLayout(TyAndLayout<'tcx>),
828        }
829
830        fn field_ty_or_layout<'tcx>(
831            this: TyAndLayout<'tcx>,
832            cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>),
833            i: usize,
834        ) -> TyMaybeWithLayout<'tcx> {
835            let tcx = cx.tcx();
836            let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
837                TyAndLayout {
838                    layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
839                    ty: tag.primitive().to_ty(tcx),
840                }
841            };
842
843            match *this.ty.kind() {
844                ty::Bool
845                | ty::Char
846                | ty::Int(_)
847                | ty::Uint(_)
848                | ty::Float(_)
849                | ty::FnPtr(..)
850                | ty::Never
851                | ty::FnDef(..)
852                | ty::CoroutineWitness(..)
853                | ty::Foreign(..)
854                | ty::Dynamic(_, _) => {
855                    crate::util::bug::bug_fmt(format_args!("TyAndLayout::field({0:?}): not applicable",
        this))bug!("TyAndLayout::field({:?}): not applicable", this)
856                }
857
858                ty::Pat(base, _) => {
859                    match (&i, &0) {
    (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!(i, 0);
860                    TyMaybeWithLayout::Ty(base)
861                }
862
863                ty::UnsafeBinder(bound_ty) => {
864                    let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
865                    field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i)
866                }
867
868                // Potentially-wide pointers.
869                ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
870                    if !(i < this.fields.count()) {
    ::core::panicking::panic("assertion failed: i < this.fields.count()")
};assert!(i < this.fields.count());
871
872                    // Reuse the wide `*T` type as its own thin pointer data field.
873                    // This provides information about, e.g., DST struct pointees
874                    // (which may have no non-DST form), and will work as long
875                    // as the `Abi` or `FieldsShape` is checked by users.
876                    if i == 0 {
877                        let nil = tcx.types.unit;
878                        let unit_ptr_ty = if this.ty.is_raw_ptr() {
879                            Ty::new_mut_ptr(tcx, nil)
880                        } else {
881                            Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil)
882                        };
883
884                        // NOTE: using an fully monomorphized typing env and `unwrap`-ing
885                        // the `Result` should always work because the type is always either
886                        // `*mut ()` or `&'static mut ()`.
887                        let typing_env = ty::TypingEnv::fully_monomorphized();
888                        return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
889                            ty: this.ty,
890                            ..tcx.layout_of(typing_env.as_query_input(unit_ptr_ty)).unwrap()
891                        });
892                    }
893
894                    let mk_dyn_vtable = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
895                        let min_count = ty::vtable_min_entries(
896                            tcx,
897                            principal.map(|principal| {
898                                tcx.instantiate_bound_regions_with_erased(principal)
899                            }),
900                        );
901                        Ty::new_imm_ref(
902                            tcx,
903                            tcx.lifetimes.re_static,
904                            // FIXME: properly type (e.g. usize and fn pointers) the fields.
905                            Ty::new_array(tcx, tcx.types.usize, min_count.try_into().unwrap()),
906                        )
907                    };
908
909                    let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
910                        // Projection eagerly bails out when the pointee references errors,
911                        // fall back to structurally deducing metadata.
912                        && !pointee.references_error()
913                    {
914                        let metadata = tcx.normalize_erasing_regions(
915                            cx.typing_env(),
916                            Ty::new_projection(tcx, metadata_def_id, [pointee]),
917                        );
918
919                        // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
920                        // offers better information than `std::ptr::metadata::VTable`,
921                        // and we rely on this layout information to trigger a panic in
922                        // `std::mem::uninitialized::<&dyn Trait>()`, for example.
923                        if let ty::Adt(def, args) = metadata.kind()
924                            && tcx.is_lang_item(def.did(), LangItem::DynMetadata)
925                            && let ty::Dynamic(data, _) = args.type_at(0).kind()
926                        {
927                            mk_dyn_vtable(data.principal())
928                        } else {
929                            metadata
930                        }
931                    } else {
932                        match tcx.struct_tail_for_codegen(pointee, cx.typing_env()).kind() {
933                            ty::Slice(_) | ty::Str => tcx.types.usize,
934                            ty::Dynamic(data, _) => mk_dyn_vtable(data.principal()),
935                            _ => crate::util::bug::bug_fmt(format_args!("TyAndLayout::field({0:?}): not applicable",
        this))bug!("TyAndLayout::field({:?}): not applicable", this),
936                        }
937                    };
938
939                    TyMaybeWithLayout::Ty(metadata)
940                }
941
942                // Arrays and slices.
943                ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
944                ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
945
946                // Tuples, coroutines and closures.
947                ty::Closure(_, args) => field_ty_or_layout(
948                    TyAndLayout { ty: args.as_closure().tupled_upvars_ty(), ..this },
949                    cx,
950                    i,
951                ),
952
953                ty::CoroutineClosure(_, args) => field_ty_or_layout(
954                    TyAndLayout { ty: args.as_coroutine_closure().tupled_upvars_ty(), ..this },
955                    cx,
956                    i,
957                ),
958
959                ty::Coroutine(def_id, args) => match this.variants {
960                    Variants::Empty => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
961                    Variants::Single { index } => TyMaybeWithLayout::Ty(
962                        args.as_coroutine()
963                            .state_tys(def_id, tcx)
964                            .nth(index.as_usize())
965                            .unwrap()
966                            .nth(i)
967                            .unwrap(),
968                    ),
969                    Variants::Multiple { tag, tag_field, .. } => {
970                        if FieldIdx::from_usize(i) == tag_field {
971                            return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
972                        }
973                        TyMaybeWithLayout::Ty(args.as_coroutine().prefix_tys()[i])
974                    }
975                },
976
977                ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
978
979                // ADTs.
980                ty::Adt(def, args) => {
981                    match this.variants {
982                        Variants::Single { index } => {
983                            let field = &def.variant(index).fields[FieldIdx::from_usize(i)];
984                            TyMaybeWithLayout::Ty(field.ty(tcx, args))
985                        }
986                        Variants::Empty => {
    ::core::panicking::panic_fmt(format_args!("there is no field in Variants::Empty types"));
}panic!("there is no field in Variants::Empty types"),
987
988                        // Discriminant field for enums (where applicable).
989                        Variants::Multiple { tag, .. } => {
990                            match (&i, &0) {
    (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!(i, 0);
991                            return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
992                        }
993                    }
994                }
995
996                ty::Alias(..)
997                | ty::Bound(..)
998                | ty::Placeholder(..)
999                | ty::Param(_)
1000                | ty::Infer(_)
1001                | ty::Error(_) => crate::util::bug::bug_fmt(format_args!("TyAndLayout::field: unexpected type `{0}`",
        this.ty))bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
1002            }
1003        }
1004
1005        match field_ty_or_layout(this, cx, i) {
1006            TyMaybeWithLayout::Ty(field_ty) => {
1007                cx.tcx().layout_of(cx.typing_env().as_query_input(field_ty)).unwrap_or_else(|e| {
1008                    crate::util::bug::bug_fmt(format_args!("failed to get layout for `{0}`: {1:?},\ndespite it being a field (#{2}) of an existing layout: {3:#?}",
        field_ty, e, i, this))bug!(
1009                        "failed to get layout for `{field_ty}`: {e:?},\n\
1010                         despite it being a field (#{i}) of an existing layout: {this:#?}",
1011                    )
1012                })
1013            }
1014            TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
1015        }
1016    }
1017
1018    /// Compute the information for the pointer stored at the given offset inside this type.
1019    /// This will recurse into fields of ADTs to find the inner pointer.
1020    fn ty_and_layout_pointee_info_at(
1021        this: TyAndLayout<'tcx>,
1022        cx: &C,
1023        offset: Size,
1024    ) -> Option<PointeeInfo> {
1025        let tcx = cx.tcx();
1026        let typing_env = cx.typing_env();
1027
1028        let pointee_info = match *this.ty.kind() {
1029            ty::RawPtr(p_ty, _) if offset.bytes() == 0 => {
1030                tcx.layout_of(typing_env.as_query_input(p_ty)).ok().map(|layout| PointeeInfo {
1031                    size: layout.size,
1032                    align: layout.align.abi,
1033                    safe: None,
1034                })
1035            }
1036            ty::FnPtr(..) if offset.bytes() == 0 => {
1037                tcx.layout_of(typing_env.as_query_input(this.ty)).ok().map(|layout| PointeeInfo {
1038                    size: layout.size,
1039                    align: layout.align.abi,
1040                    safe: None,
1041                })
1042            }
1043            ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
1044                // Use conservative pointer kind if not optimizing. This saves us the
1045                // Freeze/Unpin queries, and can save time in the codegen backend (noalias
1046                // attributes in LLVM have compile-time cost even in unoptimized builds).
1047                let optimize = tcx.sess.opts.optimize != OptLevel::No;
1048                let kind = match mt {
1049                    hir::Mutability::Not => {
1050                        PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) }
1051                    }
1052                    hir::Mutability::Mut => {
1053                        PointerKind::MutableRef { unpin: optimize && ty.is_unpin(tcx, typing_env) }
1054                    }
1055                };
1056
1057                tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo {
1058                    size: layout.size,
1059                    align: layout.align.abi,
1060                    safe: Some(kind),
1061                })
1062            }
1063
1064            _ => {
1065                let mut data_variant = match &this.variants {
1066                    // Within the discriminant field, only the niche itself is
1067                    // always initialized, so we only check for a pointer at its
1068                    // offset.
1069                    //
1070                    // Our goal here is to check whether this represents a
1071                    // "dereferenceable or null" pointer, so we need to ensure
1072                    // that there is only one other variant, and it must be null.
1073                    // Below, we will then check whether the pointer is indeed
1074                    // dereferenceable.
1075                    Variants::Multiple {
1076                        tag_encoding:
1077                            TagEncoding::Niche { untagged_variant, niche_variants, niche_start },
1078                        tag_field,
1079                        variants,
1080                        ..
1081                    } if variants.len() == 2
1082                        && this.fields.offset(tag_field.as_usize()) == offset =>
1083                    {
1084                        let tagged_variant = if *untagged_variant == VariantIdx::ZERO {
1085                            VariantIdx::from_u32(1)
1086                        } else {
1087                            VariantIdx::from_u32(0)
1088                        };
1089                        match (&tagged_variant, &*niche_variants.start()) {
    (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!(tagged_variant, *niche_variants.start());
1090                        if *niche_start == 0 {
1091                            // The other variant is encoded as "null", so we can recurse searching for
1092                            // a pointer here. This relies on the fact that the codegen backend
1093                            // only adds "dereferenceable" if there's also a "nonnull" proof,
1094                            // and that null is aligned for all alignments so it's okay to forward
1095                            // the pointer's alignment.
1096                            Some(this.for_variant(cx, *untagged_variant))
1097                        } else {
1098                            None
1099                        }
1100                    }
1101                    Variants::Multiple { .. } => None,
1102                    _ => Some(this),
1103                };
1104
1105                if let Some(variant) = data_variant
1106                    // We're not interested in any unions.
1107                    && let FieldsShape::Union(_) = variant.fields
1108                {
1109                    data_variant = None;
1110                }
1111
1112                let mut result = None;
1113
1114                if let Some(variant) = data_variant {
1115                    // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
1116                    // (requires passing in the expected address space from the caller)
1117                    let ptr_end = offset + Primitive::Pointer(AddressSpace::ZERO).size(cx);
1118                    for i in 0..variant.fields.count() {
1119                        let field_start = variant.fields.offset(i);
1120                        if field_start <= offset {
1121                            let field = variant.field(cx, i);
1122                            result = field.to_result().ok().and_then(|field| {
1123                                if ptr_end <= field_start + field.size {
1124                                    // We found the right field, look inside it.
1125                                    let field_info =
1126                                        field.pointee_info_at(cx, offset - field_start);
1127                                    field_info
1128                                } else {
1129                                    None
1130                                }
1131                            });
1132                            if result.is_some() {
1133                                break;
1134                            }
1135                        }
1136                    }
1137                }
1138
1139                // Fixup info for the first field of a `Box`. Recursive traversal will have found
1140                // the raw pointer, so size and align are set to the boxed type, but `pointee.safe`
1141                // will still be `None`.
1142                if let Some(ref mut pointee) = result {
1143                    if offset.bytes() == 0
1144                        && let Some(boxed_ty) = this.ty.boxed_ty()
1145                    {
1146                        if true {
    if !pointee.safe.is_none() {
        ::core::panicking::panic("assertion failed: pointee.safe.is_none()")
    };
};debug_assert!(pointee.safe.is_none());
1147                        let optimize = tcx.sess.opts.optimize != OptLevel::No;
1148                        pointee.safe = Some(PointerKind::Box {
1149                            unpin: optimize && boxed_ty.is_unpin(tcx, typing_env),
1150                            global: this.ty.is_box_global(tcx),
1151                        });
1152                    }
1153                }
1154
1155                result
1156            }
1157        };
1158
1159        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/ty/layout.rs:1159",
                        "rustc_middle::ty::layout", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/layout.rs"),
                        ::tracing_core::__macro_support::Option::Some(1159u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::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!("pointee_info_at (offset={0:?}, type kind: {1:?}) => {2:?}",
                                                    offset, this.ty.kind(), pointee_info) as &dyn Value))])
            });
    } else { ; }
};debug!(
1160            "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
1161            offset,
1162            this.ty.kind(),
1163            pointee_info
1164        );
1165
1166        pointee_info
1167    }
1168
1169    fn is_adt(this: TyAndLayout<'tcx>) -> bool {
1170        #[allow(non_exhaustive_omitted_patterns)] match this.ty.kind() {
    ty::Adt(..) => true,
    _ => false,
}matches!(this.ty.kind(), ty::Adt(..))
1171    }
1172
1173    fn is_never(this: TyAndLayout<'tcx>) -> bool {
1174        #[allow(non_exhaustive_omitted_patterns)] match this.ty.kind() {
    ty::Never => true,
    _ => false,
}matches!(this.ty.kind(), ty::Never)
1175    }
1176
1177    fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
1178        #[allow(non_exhaustive_omitted_patterns)] match this.ty.kind() {
    ty::Tuple(..) => true,
    _ => false,
}matches!(this.ty.kind(), ty::Tuple(..))
1179    }
1180
1181    fn is_unit(this: TyAndLayout<'tcx>) -> bool {
1182        #[allow(non_exhaustive_omitted_patterns)] match this.ty.kind() {
    ty::Tuple(list) if list.len() == 0 => true,
    _ => false,
}matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
1183    }
1184
1185    fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
1186        #[allow(non_exhaustive_omitted_patterns)] match this.ty.kind() {
    ty::Adt(def, _) if def.repr().transparent() => true,
    _ => false,
}matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
1187    }
1188
1189    fn is_scalable_vector(this: TyAndLayout<'tcx>) -> bool {
1190        this.ty.is_scalable_vector()
1191    }
1192
1193    /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
1194    fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
1195        #[allow(non_exhaustive_omitted_patterns)] match this.ty.kind() {
    ty::Adt(def, _) if
        def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS)
        => true,
    _ => false,
}matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
1196    }
1197}
1198
1199/// Calculates whether a function's ABI can unwind or not.
1200///
1201/// This takes two primary parameters:
1202///
1203/// * `fn_def_id` - the `DefId` of the function. If this is provided then we can
1204///   determine more precisely if the function can unwind. If this is not provided
1205///   then we will only infer whether the function can unwind or not based on the
1206///   ABI of the function. For example, a function marked with `#[rustc_nounwind]`
1207///   is known to not unwind even if it's using Rust ABI.
1208///
1209/// * `abi` - this is the ABI that the function is defined with. This is the
1210///   primary factor for determining whether a function can unwind or not.
1211///
1212/// Note that in this case unwinding is not necessarily panicking in Rust. Rust
1213/// panics are implemented with unwinds on most platform (when
1214/// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
1215/// Notably unwinding is disallowed for more non-Rust ABIs unless it's
1216/// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
1217/// defined for each ABI individually, but it always corresponds to some form of
1218/// stack-based unwinding (the exact mechanism of which varies
1219/// platform-by-platform).
1220///
1221/// Rust functions are classified whether or not they can unwind based on the
1222/// active "panic strategy". In other words Rust functions are considered to
1223/// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
1224/// Note that Rust supports intermingling panic=abort and panic=unwind code, but
1225/// only if the final panic mode is panic=abort. In this scenario any code
1226/// previously compiled assuming that a function can unwind is still correct, it
1227/// just never happens to actually unwind at runtime.
1228///
1229/// This function's answer to whether or not a function can unwind is quite
1230/// impactful throughout the compiler. This affects things like:
1231///
1232/// * Calling a function which can't unwind means codegen simply ignores any
1233///   associated unwinding cleanup.
1234/// * Calling a function which can unwind from a function which can't unwind
1235///   causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
1236///   aborts the process.
1237/// * This affects whether functions have the LLVM `nounwind` attribute, which
1238///   affects various optimizations and codegen.
1239#[inline]
1240#[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("fn_can_unwind",
                                    "rustc_middle::ty::layout", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/layout.rs"),
                                    ::tracing_core::__macro_support::Option::Some(1240u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::layout"),
                                    ::tracing_core::field::FieldSet::new(&["fn_def_id", "abi"],
                                        ::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,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&fn_def_id)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&abi)
                                                            as &dyn Value))])
                            })
                } 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: bool = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if let Some(did) = fn_def_id {
                if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND)
                    {
                    return false;
                }
                if !tcx.sess.panic_strategy().unwinds() &&
                        !tcx.is_foreign_item(did) {
                    return false;
                }
                if !tcx.sess.opts.unstable_opts.panic_in_drop.unwinds() &&
                        tcx.is_lang_item(did, LangItem::DropInPlace) {
                    return false;
                }
            }
            use ExternAbi::*;
            match abi {
                C { unwind } | System { unwind } | Cdecl { unwind } |
                    Stdcall { unwind } | Fastcall { unwind } | Vectorcall {
                    unwind } | Thiscall { unwind } | Aapcs { unwind } | Win64 {
                    unwind } | SysV64 { unwind } => unwind,
                PtxKernel | Msp430Interrupt | X86Interrupt | GpuKernel |
                    EfiApi | AvrInterrupt | AvrNonBlockingInterrupt |
                    CmseNonSecureCall | CmseNonSecureEntry | Custom |
                    RiscvInterruptM | RiscvInterruptS | RustInvalid | Unadjusted
                    => false,
                Rust | RustCall | RustCold | RustPreserveNone =>
                    tcx.sess.panic_strategy().unwinds(),
            }
        }
    }
}#[tracing::instrument(level = "debug", skip(tcx))]
1241pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) -> bool {
1242    if let Some(did) = fn_def_id {
1243        // Special attribute for functions which can't unwind.
1244        if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
1245            return false;
1246        }
1247
1248        // With `-C panic=abort`, all non-FFI functions are required to not unwind.
1249        //
1250        // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
1251        // function defined in Rust is also required to abort.
1252        if !tcx.sess.panic_strategy().unwinds() && !tcx.is_foreign_item(did) {
1253            return false;
1254        }
1255
1256        // With -Z panic-in-drop=abort, drop_in_place never unwinds.
1257        //
1258        // This is not part of `codegen_fn_attrs` as it can differ between crates
1259        // and therefore cannot be computed in core.
1260        if !tcx.sess.opts.unstable_opts.panic_in_drop.unwinds()
1261            && tcx.is_lang_item(did, LangItem::DropInPlace)
1262        {
1263            return false;
1264        }
1265    }
1266
1267    // Otherwise if this isn't special then unwinding is generally determined by
1268    // the ABI of the itself. ABIs like `C` have variants which also
1269    // specifically allow unwinding (`C-unwind`), but not all platform-specific
1270    // ABIs have such an option. Otherwise the only other thing here is Rust
1271    // itself, and those ABIs are determined by the panic strategy configured
1272    // for this compilation.
1273    use ExternAbi::*;
1274    match abi {
1275        C { unwind }
1276        | System { unwind }
1277        | Cdecl { unwind }
1278        | Stdcall { unwind }
1279        | Fastcall { unwind }
1280        | Vectorcall { unwind }
1281        | Thiscall { unwind }
1282        | Aapcs { unwind }
1283        | Win64 { unwind }
1284        | SysV64 { unwind } => unwind,
1285        PtxKernel
1286        | Msp430Interrupt
1287        | X86Interrupt
1288        | GpuKernel
1289        | EfiApi
1290        | AvrInterrupt
1291        | AvrNonBlockingInterrupt
1292        | CmseNonSecureCall
1293        | CmseNonSecureEntry
1294        | Custom
1295        | RiscvInterruptM
1296        | RiscvInterruptS
1297        | RustInvalid
1298        | Unadjusted => false,
1299        Rust | RustCall | RustCold | RustPreserveNone => tcx.sess.panic_strategy().unwinds(),
1300    }
1301}
1302
1303/// Error produced by attempting to compute or adjust a `FnAbi`.
1304#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for FnAbiError<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for FnAbiError<'tcx> {
    #[inline]
    fn clone(&self) -> FnAbiError<'tcx> {
        let _: ::core::clone::AssertParamIsClone<LayoutError<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for FnAbiError<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            FnAbiError::Layout(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Layout",
                    &__self_0),
        }
    }
}Debug, const _: () =
    {
        impl<'tcx, '__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_query_system::ich::StableHashingContext<'__ctx>>
            for FnAbiError<'tcx> {
            #[inline]
            fn hash_stable(&self,
                __hcx:
                    &mut ::rustc_query_system::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
                match *self {
                    FnAbiError::Layout(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable)]
1305pub enum FnAbiError<'tcx> {
1306    /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
1307    Layout(LayoutError<'tcx>),
1308}
1309
1310impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> {
1311    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
1312        match self {
1313            Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level),
1314        }
1315    }
1316}
1317
1318// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
1319// just for error handling.
1320#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for FnAbiRequest<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            FnAbiRequest::OfFnPtr { sig: __self_0, extra_args: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "OfFnPtr", "sig", __self_0, "extra_args", &__self_1),
            FnAbiRequest::OfInstance {
                instance: __self_0, extra_args: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "OfInstance", "instance", __self_0, "extra_args",
                    &__self_1),
        }
    }
}Debug)]
1321pub enum FnAbiRequest<'tcx> {
1322    OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1323    OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1324}
1325
1326/// Trait for contexts that want to be able to compute `FnAbi`s.
1327/// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
1328pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
1329    /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
1330    /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
1331    type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>> = &'tcx FnAbi<'tcx, Ty<'tcx>>;
1332
1333    /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
1334    /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
1335    ///
1336    /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
1337    /// but this hook allows e.g. codegen to return only `&FnAbi` from its
1338    /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
1339    /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
1340    fn handle_fn_abi_err(
1341        &self,
1342        err: FnAbiError<'tcx>,
1343        span: Span,
1344        fn_abi_request: FnAbiRequest<'tcx>,
1345    ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
1346}
1347
1348/// Blanket extension trait for contexts that can compute `FnAbi`s.
1349pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
1350    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
1351    ///
1352    /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
1353    /// instead, where the instance is an `InstanceKind::Virtual`.
1354    #[inline]
1355    fn fn_abi_of_fn_ptr(
1356        &self,
1357        sig: ty::PolyFnSig<'tcx>,
1358        extra_args: &'tcx ty::List<Ty<'tcx>>,
1359    ) -> Self::FnAbiOfResult {
1360        // FIXME(eddyb) get a better `span` here.
1361        let span = self.layout_tcx_at_span();
1362        let tcx = self.tcx().at(span);
1363
1364        MaybeResult::from(
1365            tcx.fn_abi_of_fn_ptr(self.typing_env().as_query_input((sig, extra_args))).map_err(
1366                |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
1367            ),
1368        )
1369    }
1370
1371    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1372    /// direct calls to an `fn`.
1373    ///
1374    /// NB: that includes virtual calls, which are represented by "direct calls"
1375    /// to an `InstanceKind::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1376    #[inline]
1377    #[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("fn_abi_of_instance",
                                    "rustc_middle::ty::layout", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/ty/layout.rs"),
                                    ::tracing_core::__macro_support::Option::Some(1377u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_middle::ty::layout"),
                                    ::tracing_core::field::FieldSet::new(&["instance",
                                                    "extra_args"],
                                        ::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,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&instance)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&extra_args)
                                                            as &dyn Value))])
                            })
                } 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: Self::FnAbiOfResult = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let span = self.layout_tcx_at_span();
            let tcx = self.tcx().at(span);
            MaybeResult::from(tcx.fn_abi_of_instance(self.typing_env().as_query_input((instance,
                                extra_args))).map_err(|err|
                        {
                            let span =
                                if !span.is_dummy() {
                                    span
                                } else { tcx.def_span(instance.def_id()) };
                            self.handle_fn_abi_err(*err, span,
                                FnAbiRequest::OfInstance { instance, extra_args })
                        }))
        }
    }
}#[tracing::instrument(level = "debug", skip(self))]
1378    fn fn_abi_of_instance(
1379        &self,
1380        instance: ty::Instance<'tcx>,
1381        extra_args: &'tcx ty::List<Ty<'tcx>>,
1382    ) -> Self::FnAbiOfResult {
1383        // FIXME(eddyb) get a better `span` here.
1384        let span = self.layout_tcx_at_span();
1385        let tcx = self.tcx().at(span);
1386
1387        MaybeResult::from(
1388            tcx.fn_abi_of_instance(self.typing_env().as_query_input((instance, extra_args)))
1389                .map_err(|err| {
1390                    // HACK(eddyb) at least for definitions of/calls to `Instance`s,
1391                    // we can get some kind of span even if one wasn't provided.
1392                    // However, we don't do this early in order to avoid calling
1393                    // `def_span` unconditionally (which may have a perf penalty).
1394                    let span =
1395                        if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1396                    self.handle_fn_abi_err(
1397                        *err,
1398                        span,
1399                        FnAbiRequest::OfInstance { instance, extra_args },
1400                    )
1401                }),
1402        )
1403    }
1404}
1405
1406impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}