rustc_middle/ty/
layout.rs

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