rustc_middle/ty/
layout.rs

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