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