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