]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/layout.rs
Rollup merge of #100599 - MatthewPeterKelly:add-E0523-description-and-test, r=compile...
[rust.git] / compiler / rustc_middle / src / ty / layout.rs
1 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2 use crate::ty::normalize_erasing_regions::NormalizationError;
3 use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitable};
4 use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
5 use rustc_hir as hir;
6 use rustc_hir::def_id::DefId;
7 use rustc_index::vec::Idx;
8 use rustc_session::config::OptLevel;
9 use rustc_span::{Span, DUMMY_SP};
10 use rustc_target::abi::call::FnAbi;
11 use rustc_target::abi::*;
12 use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
13
14 use std::cmp::{self};
15 use std::fmt;
16 use std::num::NonZeroUsize;
17 use std::ops::Bound;
18
19 pub trait IntegerExt {
20     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
21     fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer;
22     fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer;
23     fn repr_discr<'tcx>(
24         tcx: TyCtxt<'tcx>,
25         ty: Ty<'tcx>,
26         repr: &ReprOptions,
27         min: i128,
28         max: i128,
29     ) -> (Integer, bool);
30 }
31
32 impl IntegerExt for Integer {
33     #[inline]
34     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
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) -> Integer {
50         match ity {
51             ty::IntTy::I8 => I8,
52             ty::IntTy::I16 => I16,
53             ty::IntTy::I32 => I32,
54             ty::IntTy::I64 => I64,
55             ty::IntTy::I128 => I128,
56             ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
57         }
58     }
59     fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> Integer {
60         match ity {
61             ty::UintTy::U8 => I8,
62             ty::UintTy::U16 => I16,
63             ty::UintTy::U32 => I32,
64             ty::UintTy::U64 => I64,
65             ty::UintTy::U128 => I128,
66             ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
67         }
68     }
69
70     /// Finds the appropriate Integer type and signedness for the given
71     /// signed discriminant range and `#[repr]` attribute.
72     /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
73     /// that shouldn't affect anything, other than maybe debuginfo.
74     fn repr_discr<'tcx>(
75         tcx: TyCtxt<'tcx>,
76         ty: Ty<'tcx>,
77         repr: &ReprOptions,
78         min: i128,
79         max: i128,
80     ) -> (Integer, bool) {
81         // Theoretically, negative values could be larger in unsigned representation
82         // than the unsigned representation of the signed minimum. However, if there
83         // are any negative values, the only valid unsigned representation is u128
84         // which can fit all i128 values, so the result remains unaffected.
85         let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
86         let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
87
88         if let Some(ity) = repr.int {
89             let discr = Integer::from_attr(&tcx, ity);
90             let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
91             if discr < fit {
92                 bug!(
93                     "Integer::repr_discr: `#[repr]` hint too small for \
94                       discriminant range of enum `{}",
95                     ty
96                 )
97             }
98             return (discr, ity.is_signed());
99         }
100
101         let at_least = if repr.c() {
102             // This is usually I32, however it can be different on some platforms,
103             // notably hexagon and arm-none/thumb-none
104             tcx.data_layout().c_enum_min_size
105         } else {
106             // repr(Rust) enums try to be as small as possible
107             I8
108         };
109
110         // If there are no negative values, we can use the unsigned fit.
111         if min >= 0 {
112             (cmp::max(unsigned_fit, at_least), false)
113         } else {
114             (cmp::max(signed_fit, at_least), true)
115         }
116     }
117 }
118
119 pub trait PrimitiveExt {
120     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
121     fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
122 }
123
124 impl PrimitiveExt for Primitive {
125     #[inline]
126     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
127         match *self {
128             Int(i, signed) => i.to_ty(tcx, signed),
129             F32 => tcx.types.f32,
130             F64 => tcx.types.f64,
131             // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
132             Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()),
133         }
134     }
135
136     /// Return an *integer* type matching this primitive.
137     /// Useful in particular when dealing with enum discriminants.
138     #[inline]
139     fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
140         match *self {
141             Int(i, signed) => i.to_ty(tcx, signed),
142             // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
143             Pointer(_) => {
144                 let signed = false;
145                 tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
146             }
147             F32 | F64 => bug!("floats do not have an int type"),
148         }
149     }
150 }
151
152 /// The first half of a fat pointer.
153 ///
154 /// - For a trait object, this is the address of the box.
155 /// - For a slice, this is the base address.
156 pub const FAT_PTR_ADDR: usize = 0;
157
158 /// The second half of a fat pointer.
159 ///
160 /// - For a trait object, this is the address of the vtable.
161 /// - For a slice, this is the length.
162 pub const FAT_PTR_EXTRA: usize = 1;
163
164 /// The maximum supported number of lanes in a SIMD vector.
165 ///
166 /// This value is selected based on backend support:
167 /// * LLVM does not appear to have a vector width limit.
168 /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
169 pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
170
171 #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
172 pub enum LayoutError<'tcx> {
173     Unknown(Ty<'tcx>),
174     SizeOverflow(Ty<'tcx>),
175     NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
176 }
177
178 impl IntoDiagnostic<'_, !> for LayoutError<'_> {
179     fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
180         let mut diag = handler.struct_fatal("");
181
182         match self {
183             LayoutError::Unknown(ty) => {
184                 diag.set_arg("ty", ty);
185                 diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout);
186             }
187             LayoutError::SizeOverflow(ty) => {
188                 diag.set_arg("ty", ty);
189                 diag.set_primary_message(rustc_errors::fluent::middle_values_too_big);
190             }
191             LayoutError::NormalizationFailure(ty, e) => {
192                 diag.set_arg("ty", ty);
193                 diag.set_arg("failure_ty", e.get_type_for_failure());
194                 diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized);
195             }
196         }
197         diag
198     }
199 }
200
201 // FIXME: Once the other errors that embed this error have been converted to translateable
202 // diagnostics, this Display impl should be removed.
203 impl<'tcx> fmt::Display for LayoutError<'tcx> {
204     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205         match *self {
206             LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty),
207             LayoutError::SizeOverflow(ty) => {
208                 write!(f, "values of the type `{}` are too big for the current architecture", ty)
209             }
210             LayoutError::NormalizationFailure(t, e) => write!(
211                 f,
212                 "unable to determine layout for `{}` because `{}` cannot be normalized",
213                 t,
214                 e.get_type_for_failure()
215             ),
216         }
217     }
218 }
219
220 #[derive(Clone, Copy)]
221 pub struct LayoutCx<'tcx, C> {
222     pub tcx: C,
223     pub param_env: ty::ParamEnv<'tcx>,
224 }
225
226 impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> {
227     type TargetDataLayoutRef = &'tcx TargetDataLayout;
228
229     fn delay_bug(&self, txt: &str) {
230         self.tcx.sess.delay_span_bug(DUMMY_SP, txt);
231     }
232
233     fn current_data_layout(&self) -> Self::TargetDataLayoutRef {
234         &self.tcx.data_layout
235     }
236 }
237
238 /// Type size "skeleton", i.e., the only information determining a type's size.
239 /// While this is conservative, (aside from constant sizes, only pointers,
240 /// newtypes thereof and null pointer optimized enums are allowed), it is
241 /// enough to statically check common use cases of transmute.
242 #[derive(Copy, Clone, Debug)]
243 pub enum SizeSkeleton<'tcx> {
244     /// Any statically computable Layout.
245     Known(Size),
246
247     /// A potentially-fat pointer.
248     Pointer {
249         /// If true, this pointer is never null.
250         non_zero: bool,
251         /// The type which determines the unsized metadata, if any,
252         /// of this pointer. Either a type parameter or a projection
253         /// depending on one, with regions erased.
254         tail: Ty<'tcx>,
255     },
256 }
257
258 impl<'tcx> SizeSkeleton<'tcx> {
259     pub fn compute(
260         ty: Ty<'tcx>,
261         tcx: TyCtxt<'tcx>,
262         param_env: ty::ParamEnv<'tcx>,
263     ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
264         debug_assert!(!ty.has_non_region_infer());
265
266         // First try computing a static layout.
267         let err = match tcx.layout_of(param_env.and(ty)) {
268             Ok(layout) => {
269                 return Ok(SizeSkeleton::Known(layout.size));
270             }
271             Err(err) => err,
272         };
273
274         match *ty.kind() {
275             ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
276                 let non_zero = !ty.is_unsafe_ptr();
277                 let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
278                 match tail.kind() {
279                     ty::Param(_) | ty::Alias(ty::Projection, _) => {
280                         debug_assert!(tail.has_non_region_param());
281                         Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
282                     }
283                     _ => bug!(
284                         "SizeSkeleton::compute({}): layout errored ({}), yet \
285                               tail `{}` is not a type parameter or a projection",
286                         ty,
287                         err,
288                         tail
289                     ),
290                 }
291             }
292
293             ty::Adt(def, substs) => {
294                 // Only newtypes and enums w/ nullable pointer optimization.
295                 if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
296                     return Err(err);
297                 }
298
299                 // Get a zero-sized variant or a pointer newtype.
300                 let zero_or_ptr_variant = |i| {
301                     let i = VariantIdx::new(i);
302                     let fields =
303                         def.variant(i).fields.iter().map(|field| {
304                             SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
305                         });
306                     let mut ptr = None;
307                     for field in fields {
308                         let field = field?;
309                         match field {
310                             SizeSkeleton::Known(size) => {
311                                 if size.bytes() > 0 {
312                                     return Err(err);
313                                 }
314                             }
315                             SizeSkeleton::Pointer { .. } => {
316                                 if ptr.is_some() {
317                                     return Err(err);
318                                 }
319                                 ptr = Some(field);
320                             }
321                         }
322                     }
323                     Ok(ptr)
324                 };
325
326                 let v0 = zero_or_ptr_variant(0)?;
327                 // Newtype.
328                 if def.variants().len() == 1 {
329                     if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
330                         return Ok(SizeSkeleton::Pointer {
331                             non_zero: non_zero
332                                 || match tcx.layout_scalar_valid_range(def.did()) {
333                                     (Bound::Included(start), Bound::Unbounded) => start > 0,
334                                     (Bound::Included(start), Bound::Included(end)) => {
335                                         0 < start && start < end
336                                     }
337                                     _ => false,
338                                 },
339                             tail,
340                         });
341                     } else {
342                         return Err(err);
343                     }
344                 }
345
346                 let v1 = zero_or_ptr_variant(1)?;
347                 // Nullable pointer enum optimization.
348                 match (v0, v1) {
349                     (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
350                     | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
351                         Ok(SizeSkeleton::Pointer { non_zero: false, tail })
352                     }
353                     _ => Err(err),
354                 }
355             }
356
357             ty::Alias(..) => {
358                 let normalized = tcx.normalize_erasing_regions(param_env, ty);
359                 if ty == normalized {
360                     Err(err)
361                 } else {
362                     SizeSkeleton::compute(normalized, tcx, param_env)
363                 }
364             }
365
366             _ => Err(err),
367         }
368     }
369
370     pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
371         match (self, other) {
372             (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b,
373             (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
374                 a == b
375             }
376             _ => false,
377         }
378     }
379 }
380
381 pub trait HasTyCtxt<'tcx>: HasDataLayout {
382     fn tcx(&self) -> TyCtxt<'tcx>;
383 }
384
385 pub trait HasParamEnv<'tcx> {
386     fn param_env(&self) -> ty::ParamEnv<'tcx>;
387 }
388
389 impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
390     #[inline]
391     fn data_layout(&self) -> &TargetDataLayout {
392         &self.data_layout
393     }
394 }
395
396 impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
397     fn target_spec(&self) -> &Target {
398         &self.sess.target
399     }
400 }
401
402 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
403     #[inline]
404     fn tcx(&self) -> TyCtxt<'tcx> {
405         *self
406     }
407 }
408
409 impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
410     #[inline]
411     fn data_layout(&self) -> &TargetDataLayout {
412         &self.data_layout
413     }
414 }
415
416 impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
417     fn target_spec(&self) -> &Target {
418         &self.sess.target
419     }
420 }
421
422 impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
423     #[inline]
424     fn tcx(&self) -> TyCtxt<'tcx> {
425         **self
426     }
427 }
428
429 impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
430     fn param_env(&self) -> ty::ParamEnv<'tcx> {
431         self.param_env
432     }
433 }
434
435 impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
436     fn data_layout(&self) -> &TargetDataLayout {
437         self.tcx.data_layout()
438     }
439 }
440
441 impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
442     fn target_spec(&self) -> &Target {
443         self.tcx.target_spec()
444     }
445 }
446
447 impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
448     fn tcx(&self) -> TyCtxt<'tcx> {
449         self.tcx.tcx()
450     }
451 }
452
453 pub trait MaybeResult<T> {
454     type Error;
455
456     fn from(x: Result<T, Self::Error>) -> Self;
457     fn to_result(self) -> Result<T, Self::Error>;
458 }
459
460 impl<T> MaybeResult<T> for T {
461     type Error = !;
462
463     fn from(Ok(x): Result<T, Self::Error>) -> Self {
464         x
465     }
466     fn to_result(self) -> Result<T, Self::Error> {
467         Ok(self)
468     }
469 }
470
471 impl<T, E> MaybeResult<T> for Result<T, E> {
472     type Error = E;
473
474     fn from(x: Result<T, Self::Error>) -> Self {
475         x
476     }
477     fn to_result(self) -> Result<T, Self::Error> {
478         self
479     }
480 }
481
482 pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
483
484 /// Trait for contexts that want to be able to compute layouts of types.
485 /// This automatically gives access to `LayoutOf`, through a blanket `impl`.
486 pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> {
487     /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
488     /// returned from `layout_of` (see also `handle_layout_err`).
489     type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>>;
490
491     /// `Span` to use for `tcx.at(span)`, from `layout_of`.
492     // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better?
493     #[inline]
494     fn layout_tcx_at_span(&self) -> Span {
495         DUMMY_SP
496     }
497
498     /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
499     /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
500     ///
501     /// Most `impl`s, which propagate `LayoutError`s, should simply return `err`,
502     /// but this hook allows e.g. codegen to return only `TyAndLayout` from its
503     /// `cx.layout_of(...)`, without any `Result<...>` around it to deal with
504     /// (and any `LayoutError`s are turned into fatal errors or ICEs).
505     fn handle_layout_err(
506         &self,
507         err: LayoutError<'tcx>,
508         span: Span,
509         ty: Ty<'tcx>,
510     ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
511 }
512
513 /// Blanket extension trait for contexts that can compute layouts of types.
514 pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
515     /// Computes the layout of a type. Note that this implicitly
516     /// executes in "reveal all" mode, and will normalize the input type.
517     #[inline]
518     fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
519         self.spanned_layout_of(ty, DUMMY_SP)
520     }
521
522     /// Computes the layout of a type, at `span`. Note that this implicitly
523     /// executes in "reveal all" mode, and will normalize the input type.
524     // FIXME(eddyb) avoid passing information like this, and instead add more
525     // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
526     #[inline]
527     fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
528         let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
529         let tcx = self.tcx().at(span);
530
531         MaybeResult::from(
532             tcx.layout_of(self.param_env().and(ty))
533                 .map_err(|err| self.handle_layout_err(err, span, ty)),
534         )
535     }
536 }
537
538 impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
539
540 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
541     type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
542
543     #[inline]
544     fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
545         err
546     }
547 }
548
549 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
550     type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
551
552     #[inline]
553     fn layout_tcx_at_span(&self) -> Span {
554         self.tcx.span
555     }
556
557     #[inline]
558     fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
559         err
560     }
561 }
562
563 impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
564 where
565     C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
566 {
567     fn ty_and_layout_for_variant(
568         this: TyAndLayout<'tcx>,
569         cx: &C,
570         variant_index: VariantIdx,
571     ) -> TyAndLayout<'tcx> {
572         let layout = match this.variants {
573             Variants::Single { index }
574                 // If all variants but one are uninhabited, the variant layout is the enum layout.
575                 if index == variant_index &&
576                 // Don't confuse variants of uninhabited enums with the enum itself.
577                 // For more details see https://github.com/rust-lang/rust/issues/69763.
578                 this.fields != FieldsShape::Primitive =>
579             {
580                 this.layout
581             }
582
583             Variants::Single { index } => {
584                 let tcx = cx.tcx();
585                 let param_env = cx.param_env();
586
587                 // Deny calling for_variant more than once for non-Single enums.
588                 if let Ok(original_layout) = tcx.layout_of(param_env.and(this.ty)) {
589                     assert_eq!(original_layout.variants, Variants::Single { index });
590                 }
591
592                 let fields = match this.ty.kind() {
593                     ty::Adt(def, _) if def.variants().is_empty() =>
594                         bug!("for_variant called on zero-variant enum"),
595                     ty::Adt(def, _) => def.variant(variant_index).fields.len(),
596                     _ => bug!(),
597                 };
598                 tcx.intern_layout(LayoutS {
599                     variants: Variants::Single { index: variant_index },
600                     fields: match NonZeroUsize::new(fields) {
601                         Some(fields) => FieldsShape::Union(fields),
602                         None => FieldsShape::Arbitrary { offsets: vec![], memory_index: vec![] },
603                     },
604                     abi: Abi::Uninhabited,
605                     largest_niche: None,
606                     align: tcx.data_layout.i8_align,
607                     size: Size::ZERO,
608                 })
609             }
610
611             Variants::Multiple { ref variants, .. } => cx.tcx().intern_layout(variants[variant_index].clone()),
612         };
613
614         assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
615
616         TyAndLayout { ty: this.ty, layout }
617     }
618
619     fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
620         enum TyMaybeWithLayout<'tcx> {
621             Ty(Ty<'tcx>),
622             TyAndLayout(TyAndLayout<'tcx>),
623         }
624
625         fn field_ty_or_layout<'tcx>(
626             this: TyAndLayout<'tcx>,
627             cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
628             i: usize,
629         ) -> TyMaybeWithLayout<'tcx> {
630             let tcx = cx.tcx();
631             let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
632                 TyAndLayout {
633                     layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
634                     ty: tag.primitive().to_ty(tcx),
635                 }
636             };
637
638             match *this.ty.kind() {
639                 ty::Bool
640                 | ty::Char
641                 | ty::Int(_)
642                 | ty::Uint(_)
643                 | ty::Float(_)
644                 | ty::FnPtr(_)
645                 | ty::Never
646                 | ty::FnDef(..)
647                 | ty::GeneratorWitness(..)
648                 | ty::GeneratorWitnessMIR(..)
649                 | ty::Foreign(..)
650                 | ty::Dynamic(_, _, ty::Dyn) => {
651                     bug!("TyAndLayout::field({:?}): not applicable", this)
652                 }
653
654                 // Potentially-fat pointers.
655                 ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
656                     assert!(i < this.fields.count());
657
658                     // Reuse the fat `*T` type as its own thin pointer data field.
659                     // This provides information about, e.g., DST struct pointees
660                     // (which may have no non-DST form), and will work as long
661                     // as the `Abi` or `FieldsShape` is checked by users.
662                     if i == 0 {
663                         let nil = tcx.mk_unit();
664                         let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
665                             tcx.mk_mut_ptr(nil)
666                         } else {
667                             tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
668                         };
669
670                         // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
671                         // the `Result` should always work because the type is
672                         // always either `*mut ()` or `&'static mut ()`.
673                         return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
674                             ty: this.ty,
675                             ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
676                         });
677                     }
678
679                     let mk_dyn_vtable = || {
680                         tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
681                         /* FIXME: use actual fn pointers
682                         Warning: naively computing the number of entries in the
683                         vtable by counting the methods on the trait + methods on
684                         all parent traits does not work, because some methods can
685                         be not object safe and thus excluded from the vtable.
686                         Increase this counter if you tried to implement this but
687                         failed to do it without duplicating a lot of code from
688                         other places in the compiler: 2
689                         tcx.mk_tup(&[
690                             tcx.mk_array(tcx.types.usize, 3),
691                             tcx.mk_array(Option<fn()>),
692                         ])
693                         */
694                     };
695
696                     let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
697                         let metadata = tcx.normalize_erasing_regions(
698                             cx.param_env(),
699                             tcx.mk_projection(metadata_def_id, [pointee]),
700                         );
701
702                         // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
703                         // offers better information than `std::ptr::metadata::VTable`,
704                         // and we rely on this layout information to trigger a panic in
705                         // `std::mem::uninitialized::<&dyn Trait>()`, for example.
706                         if let ty::Adt(def, substs) = metadata.kind()
707                             && Some(def.did()) == tcx.lang_items().dyn_metadata()
708                             && substs.type_at(0).is_trait()
709                         {
710                             mk_dyn_vtable()
711                         } else {
712                             metadata
713                         }
714                     } else {
715                         match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
716                             ty::Slice(_) | ty::Str => tcx.types.usize,
717                             ty::Dynamic(_, _, ty::Dyn) => mk_dyn_vtable(),
718                             _ => bug!("TyAndLayout::field({:?}): not applicable", this),
719                         }
720                     };
721
722                     TyMaybeWithLayout::Ty(metadata)
723                 }
724
725                 // Arrays and slices.
726                 ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
727                 ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
728
729                 // Tuples, generators and closures.
730                 ty::Closure(_, ref substs) => field_ty_or_layout(
731                     TyAndLayout { ty: substs.as_closure().tupled_upvars_ty(), ..this },
732                     cx,
733                     i,
734                 ),
735
736                 ty::Generator(def_id, ref substs, _) => match this.variants {
737                     Variants::Single { index } => TyMaybeWithLayout::Ty(
738                         substs
739                             .as_generator()
740                             .state_tys(def_id, tcx)
741                             .nth(index.as_usize())
742                             .unwrap()
743                             .nth(i)
744                             .unwrap(),
745                     ),
746                     Variants::Multiple { tag, tag_field, .. } => {
747                         if i == tag_field {
748                             return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
749                         }
750                         TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
751                     }
752                 },
753
754                 ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
755
756                 // ADTs.
757                 ty::Adt(def, substs) => {
758                     match this.variants {
759                         Variants::Single { index } => {
760                             TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs))
761                         }
762
763                         // Discriminant field for enums (where applicable).
764                         Variants::Multiple { tag, .. } => {
765                             assert_eq!(i, 0);
766                             return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
767                         }
768                     }
769                 }
770
771                 ty::Dynamic(_, _, ty::DynStar) => {
772                     if i == 0 {
773                         TyMaybeWithLayout::Ty(tcx.types.usize)
774                     } else if i == 1 {
775                         // FIXME(dyn-star) same FIXME as above applies here too
776                         TyMaybeWithLayout::Ty(
777                             tcx.mk_imm_ref(
778                                 tcx.lifetimes.re_static,
779                                 tcx.mk_array(tcx.types.usize, 3),
780                             ),
781                         )
782                     } else {
783                         bug!("no field {i} on dyn*")
784                     }
785                 }
786
787                 ty::Alias(..)
788                 | ty::Bound(..)
789                 | ty::Placeholder(..)
790                 | ty::Param(_)
791                 | ty::Infer(_)
792                 | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
793             }
794         }
795
796         match field_ty_or_layout(this, cx, i) {
797             TyMaybeWithLayout::Ty(field_ty) => {
798                 cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
799                     bug!(
800                         "failed to get layout for `{}`: {},\n\
801                          despite it being a field (#{}) of an existing layout: {:#?}",
802                         field_ty,
803                         e,
804                         i,
805                         this
806                     )
807                 })
808             }
809             TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
810         }
811     }
812
813     fn ty_and_layout_pointee_info_at(
814         this: TyAndLayout<'tcx>,
815         cx: &C,
816         offset: Size,
817     ) -> Option<PointeeInfo> {
818         let tcx = cx.tcx();
819         let param_env = cx.param_env();
820
821         let pointee_info = match *this.ty.kind() {
822             ty::RawPtr(mt) if offset.bytes() == 0 => {
823                 tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
824                     size: layout.size,
825                     align: layout.align.abi,
826                     safe: None,
827                 })
828             }
829             ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
830                 tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
831                     size: layout.size,
832                     align: layout.align.abi,
833                     safe: None,
834                 })
835             }
836             ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
837                 // Use conservative pointer kind if not optimizing. This saves us the
838                 // Freeze/Unpin queries, and can save time in the codegen backend (noalias
839                 // attributes in LLVM have compile-time cost even in unoptimized builds).
840                 let optimize = tcx.sess.opts.optimize != OptLevel::No;
841                 let kind = match mt {
842                     hir::Mutability::Not => PointerKind::SharedRef {
843                         frozen: optimize && ty.is_freeze(tcx, cx.param_env()),
844                     },
845                     hir::Mutability::Mut => PointerKind::MutableRef {
846                         unpin: optimize && ty.is_unpin(tcx, cx.param_env()),
847                     },
848                 };
849
850                 tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
851                     size: layout.size,
852                     align: layout.align.abi,
853                     safe: Some(kind),
854                 })
855             }
856
857             _ => {
858                 let mut data_variant = match this.variants {
859                     // Within the discriminant field, only the niche itself is
860                     // always initialized, so we only check for a pointer at its
861                     // offset.
862                     //
863                     // If the niche is a pointer, it's either valid (according
864                     // to its type), or null (which the niche field's scalar
865                     // validity range encodes). This allows using
866                     // `dereferenceable_or_null` for e.g., `Option<&T>`, and
867                     // this will continue to work as long as we don't start
868                     // using more niches than just null (e.g., the first page of
869                     // the address space, or unaligned pointers).
870                     Variants::Multiple {
871                         tag_encoding: TagEncoding::Niche { untagged_variant, .. },
872                         tag_field,
873                         ..
874                     } if this.fields.offset(tag_field) == offset => {
875                         Some(this.for_variant(cx, untagged_variant))
876                     }
877                     _ => Some(this),
878                 };
879
880                 if let Some(variant) = data_variant {
881                     // We're not interested in any unions.
882                     if let FieldsShape::Union(_) = variant.fields {
883                         data_variant = None;
884                     }
885                 }
886
887                 let mut result = None;
888
889                 if let Some(variant) = data_variant {
890                     // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
891                     // (requires passing in the expected address space from the caller)
892                     let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
893                     for i in 0..variant.fields.count() {
894                         let field_start = variant.fields.offset(i);
895                         if field_start <= offset {
896                             let field = variant.field(cx, i);
897                             result = field.to_result().ok().and_then(|field| {
898                                 if ptr_end <= field_start + field.size {
899                                     // We found the right field, look inside it.
900                                     let field_info =
901                                         field.pointee_info_at(cx, offset - field_start);
902                                     field_info
903                                 } else {
904                                     None
905                                 }
906                             });
907                             if result.is_some() {
908                                 break;
909                             }
910                         }
911                     }
912                 }
913
914                 // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
915                 if let Some(ref mut pointee) = result {
916                     if let ty::Adt(def, _) = this.ty.kind() {
917                         if def.is_box() && offset.bytes() == 0 {
918                             let optimize = tcx.sess.opts.optimize != OptLevel::No;
919                             pointee.safe = Some(PointerKind::Box {
920                                 unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
921                             });
922                         }
923                     }
924                 }
925
926                 result
927             }
928         };
929
930         debug!(
931             "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
932             offset,
933             this.ty.kind(),
934             pointee_info
935         );
936
937         pointee_info
938     }
939
940     fn is_adt(this: TyAndLayout<'tcx>) -> bool {
941         matches!(this.ty.kind(), ty::Adt(..))
942     }
943
944     fn is_never(this: TyAndLayout<'tcx>) -> bool {
945         this.ty.kind() == &ty::Never
946     }
947
948     fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
949         matches!(this.ty.kind(), ty::Tuple(..))
950     }
951
952     fn is_unit(this: TyAndLayout<'tcx>) -> bool {
953         matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
954     }
955 }
956
957 /// Calculates whether a function's ABI can unwind or not.
958 ///
959 /// This takes two primary parameters:
960 ///
961 /// * `codegen_fn_attr_flags` - these are flags calculated as part of the
962 ///   codegen attrs for a defined function. For function pointers this set of
963 ///   flags is the empty set. This is only applicable for Rust-defined
964 ///   functions, and generally isn't needed except for small optimizations where
965 ///   we try to say a function which otherwise might look like it could unwind
966 ///   doesn't actually unwind (such as for intrinsics and such).
967 ///
968 /// * `abi` - this is the ABI that the function is defined with. This is the
969 ///   primary factor for determining whether a function can unwind or not.
970 ///
971 /// Note that in this case unwinding is not necessarily panicking in Rust. Rust
972 /// panics are implemented with unwinds on most platform (when
973 /// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
974 /// Notably unwinding is disallowed for more non-Rust ABIs unless it's
975 /// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
976 /// defined for each ABI individually, but it always corresponds to some form of
977 /// stack-based unwinding (the exact mechanism of which varies
978 /// platform-by-platform).
979 ///
980 /// Rust functions are classified whether or not they can unwind based on the
981 /// active "panic strategy". In other words Rust functions are considered to
982 /// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
983 /// Note that Rust supports intermingling panic=abort and panic=unwind code, but
984 /// only if the final panic mode is panic=abort. In this scenario any code
985 /// previously compiled assuming that a function can unwind is still correct, it
986 /// just never happens to actually unwind at runtime.
987 ///
988 /// This function's answer to whether or not a function can unwind is quite
989 /// impactful throughout the compiler. This affects things like:
990 ///
991 /// * Calling a function which can't unwind means codegen simply ignores any
992 ///   associated unwinding cleanup.
993 /// * Calling a function which can unwind from a function which can't unwind
994 ///   causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
995 ///   aborts the process.
996 /// * This affects whether functions have the LLVM `nounwind` attribute, which
997 ///   affects various optimizations and codegen.
998 ///
999 /// FIXME: this is actually buggy with respect to Rust functions. Rust functions
1000 /// compiled with `-Cpanic=unwind` and referenced from another crate compiled
1001 /// with `-Cpanic=abort` will look like they can't unwind when in fact they
1002 /// might (from a foreign exception or similar).
1003 #[inline]
1004 #[tracing::instrument(level = "debug", skip(tcx))]
1005 pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
1006     if let Some(did) = fn_def_id {
1007         // Special attribute for functions which can't unwind.
1008         if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
1009             return false;
1010         }
1011
1012         // With `-C panic=abort`, all non-FFI functions are required to not unwind.
1013         //
1014         // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
1015         // function defined in Rust is also required to abort.
1016         if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
1017             return false;
1018         }
1019
1020         // With -Z panic-in-drop=abort, drop_in_place never unwinds.
1021         //
1022         // This is not part of `codegen_fn_attrs` as it can differ between crates
1023         // and therefore cannot be computed in core.
1024         if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort {
1025             if Some(did) == tcx.lang_items().drop_in_place_fn() {
1026                 return false;
1027             }
1028         }
1029     }
1030
1031     // Otherwise if this isn't special then unwinding is generally determined by
1032     // the ABI of the itself. ABIs like `C` have variants which also
1033     // specifically allow unwinding (`C-unwind`), but not all platform-specific
1034     // ABIs have such an option. Otherwise the only other thing here is Rust
1035     // itself, and those ABIs are determined by the panic strategy configured
1036     // for this compilation.
1037     //
1038     // Unfortunately at this time there's also another caveat. Rust [RFC
1039     // 2945][rfc] has been accepted and is in the process of being implemented
1040     // and stabilized. In this interim state we need to deal with historical
1041     // rustc behavior as well as plan for future rustc behavior.
1042     //
1043     // Historically functions declared with `extern "C"` were marked at the
1044     // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
1045     // or not. This is UB for functions in `panic=unwind` mode that then
1046     // actually panic and unwind. Note that this behavior is true for both
1047     // externally declared functions as well as Rust-defined function.
1048     //
1049     // To fix this UB rustc would like to change in the future to catch unwinds
1050     // from function calls that may unwind within a Rust-defined `extern "C"`
1051     // function and forcibly abort the process, thereby respecting the
1052     // `nounwind` attribute emitted for `extern "C"`. This behavior change isn't
1053     // ready to roll out, so determining whether or not the `C` family of ABIs
1054     // unwinds is conditional not only on their definition but also whether the
1055     // `#![feature(c_unwind)]` feature gate is active.
1056     //
1057     // Note that this means that unlike historical compilers rustc now, by
1058     // default, unconditionally thinks that the `C` ABI may unwind. This will
1059     // prevent some optimization opportunities, however, so we try to scope this
1060     // change and only assume that `C` unwinds with `panic=unwind` (as opposed
1061     // to `panic=abort`).
1062     //
1063     // Eventually the check against `c_unwind` here will ideally get removed and
1064     // this'll be a little cleaner as it'll be a straightforward check of the
1065     // ABI.
1066     //
1067     // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
1068     use SpecAbi::*;
1069     match abi {
1070         C { unwind }
1071         | System { unwind }
1072         | Cdecl { unwind }
1073         | Stdcall { unwind }
1074         | Fastcall { unwind }
1075         | Vectorcall { unwind }
1076         | Thiscall { unwind }
1077         | Aapcs { unwind }
1078         | Win64 { unwind }
1079         | SysV64 { unwind } => {
1080             unwind
1081                 || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
1082         }
1083         PtxKernel
1084         | Msp430Interrupt
1085         | X86Interrupt
1086         | AmdGpuKernel
1087         | EfiApi
1088         | AvrInterrupt
1089         | AvrNonBlockingInterrupt
1090         | CCmseNonSecureCall
1091         | Wasm
1092         | RustIntrinsic
1093         | PlatformIntrinsic
1094         | Unadjusted => false,
1095         Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
1096     }
1097 }
1098
1099 /// Error produced by attempting to compute or adjust a `FnAbi`.
1100 #[derive(Copy, Clone, Debug, HashStable)]
1101 pub enum FnAbiError<'tcx> {
1102     /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
1103     Layout(LayoutError<'tcx>),
1104
1105     /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
1106     AdjustForForeignAbi(call::AdjustForForeignAbiError),
1107 }
1108
1109 impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
1110     fn from(err: LayoutError<'tcx>) -> Self {
1111         Self::Layout(err)
1112     }
1113 }
1114
1115 impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
1116     fn from(err: call::AdjustForForeignAbiError) -> Self {
1117         Self::AdjustForForeignAbi(err)
1118     }
1119 }
1120
1121 impl<'tcx> fmt::Display for FnAbiError<'tcx> {
1122     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1123         match self {
1124             Self::Layout(err) => err.fmt(f),
1125             Self::AdjustForForeignAbi(err) => err.fmt(f),
1126         }
1127     }
1128 }
1129
1130 impl IntoDiagnostic<'_, !> for FnAbiError<'_> {
1131     fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
1132         handler.struct_fatal(self.to_string())
1133     }
1134 }
1135
1136 // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
1137 // just for error handling.
1138 #[derive(Debug)]
1139 pub enum FnAbiRequest<'tcx> {
1140     OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1141     OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1142 }
1143
1144 /// Trait for contexts that want to be able to compute `FnAbi`s.
1145 /// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
1146 pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
1147     /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
1148     /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
1149     type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
1150
1151     /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
1152     /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
1153     ///
1154     /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
1155     /// but this hook allows e.g. codegen to return only `&FnAbi` from its
1156     /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
1157     /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
1158     fn handle_fn_abi_err(
1159         &self,
1160         err: FnAbiError<'tcx>,
1161         span: Span,
1162         fn_abi_request: FnAbiRequest<'tcx>,
1163     ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
1164 }
1165
1166 /// Blanket extension trait for contexts that can compute `FnAbi`s.
1167 pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
1168     /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
1169     ///
1170     /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
1171     /// instead, where the instance is an `InstanceDef::Virtual`.
1172     #[inline]
1173     fn fn_abi_of_fn_ptr(
1174         &self,
1175         sig: ty::PolyFnSig<'tcx>,
1176         extra_args: &'tcx ty::List<Ty<'tcx>>,
1177     ) -> Self::FnAbiOfResult {
1178         // FIXME(eddyb) get a better `span` here.
1179         let span = self.layout_tcx_at_span();
1180         let tcx = self.tcx().at(span);
1181
1182         MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
1183             |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
1184         ))
1185     }
1186
1187     /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1188     /// direct calls to an `fn`.
1189     ///
1190     /// NB: that includes virtual calls, which are represented by "direct calls"
1191     /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1192     #[inline]
1193     #[tracing::instrument(level = "debug", skip(self))]
1194     fn fn_abi_of_instance(
1195         &self,
1196         instance: ty::Instance<'tcx>,
1197         extra_args: &'tcx ty::List<Ty<'tcx>>,
1198     ) -> Self::FnAbiOfResult {
1199         // FIXME(eddyb) get a better `span` here.
1200         let span = self.layout_tcx_at_span();
1201         let tcx = self.tcx().at(span);
1202
1203         MaybeResult::from(
1204             tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
1205                 // HACK(eddyb) at least for definitions of/calls to `Instance`s,
1206                 // we can get some kind of span even if one wasn't provided.
1207                 // However, we don't do this early in order to avoid calling
1208                 // `def_span` unconditionally (which may have a perf penalty).
1209                 let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1210                 self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
1211             }),
1212         )
1213     }
1214 }
1215
1216 impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}