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