Skip to main content

rustc_middle/ty/
layout.rs

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