]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/layout.rs
Rollup merge of #107189 - cjgillot:meta-adt, r=compiler-errors
[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::Foreign(..)
649                 | ty::Dynamic(_, _, ty::Dyn) => {
650                     bug!("TyAndLayout::field({:?}): not applicable", this)
651                 }
652
653                 // Potentially-fat pointers.
654                 ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
655                     assert!(i < this.fields.count());
656
657                     // Reuse the fat `*T` type as its own thin pointer data field.
658                     // This provides information about, e.g., DST struct pointees
659                     // (which may have no non-DST form), and will work as long
660                     // as the `Abi` or `FieldsShape` is checked by users.
661                     if i == 0 {
662                         let nil = tcx.mk_unit();
663                         let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
664                             tcx.mk_mut_ptr(nil)
665                         } else {
666                             tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
667                         };
668
669                         // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
670                         // the `Result` should always work because the type is
671                         // always either `*mut ()` or `&'static mut ()`.
672                         return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
673                             ty: this.ty,
674                             ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
675                         });
676                     }
677
678                     let mk_dyn_vtable = || {
679                         tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
680                         /* FIXME: use actual fn pointers
681                         Warning: naively computing the number of entries in the
682                         vtable by counting the methods on the trait + methods on
683                         all parent traits does not work, because some methods can
684                         be not object safe and thus excluded from the vtable.
685                         Increase this counter if you tried to implement this but
686                         failed to do it without duplicating a lot of code from
687                         other places in the compiler: 2
688                         tcx.mk_tup(&[
689                             tcx.mk_array(tcx.types.usize, 3),
690                             tcx.mk_array(Option<fn()>),
691                         ])
692                         */
693                     };
694
695                     let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
696                         let metadata = tcx.normalize_erasing_regions(
697                             cx.param_env(),
698                             tcx.mk_projection(metadata_def_id, [pointee]),
699                         );
700
701                         // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
702                         // offers better information than `std::ptr::metadata::VTable`,
703                         // and we rely on this layout information to trigger a panic in
704                         // `std::mem::uninitialized::<&dyn Trait>()`, for example.
705                         if let ty::Adt(def, substs) = metadata.kind()
706                             && Some(def.did()) == tcx.lang_items().dyn_metadata()
707                             && substs.type_at(0).is_trait()
708                         {
709                             mk_dyn_vtable()
710                         } else {
711                             metadata
712                         }
713                     } else {
714                         match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
715                             ty::Slice(_) | ty::Str => tcx.types.usize,
716                             ty::Dynamic(_, _, ty::Dyn) => mk_dyn_vtable(),
717                             _ => bug!("TyAndLayout::field({:?}): not applicable", this),
718                         }
719                     };
720
721                     TyMaybeWithLayout::Ty(metadata)
722                 }
723
724                 // Arrays and slices.
725                 ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
726                 ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
727
728                 // Tuples, generators and closures.
729                 ty::Closure(_, ref substs) => field_ty_or_layout(
730                     TyAndLayout { ty: substs.as_closure().tupled_upvars_ty(), ..this },
731                     cx,
732                     i,
733                 ),
734
735                 ty::Generator(def_id, ref substs, _) => match this.variants {
736                     Variants::Single { index } => TyMaybeWithLayout::Ty(
737                         substs
738                             .as_generator()
739                             .state_tys(def_id, tcx)
740                             .nth(index.as_usize())
741                             .unwrap()
742                             .nth(i)
743                             .unwrap(),
744                     ),
745                     Variants::Multiple { tag, tag_field, .. } => {
746                         if i == tag_field {
747                             return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
748                         }
749                         TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
750                     }
751                 },
752
753                 ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
754
755                 // ADTs.
756                 ty::Adt(def, substs) => {
757                     match this.variants {
758                         Variants::Single { index } => {
759                             TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs))
760                         }
761
762                         // Discriminant field for enums (where applicable).
763                         Variants::Multiple { tag, .. } => {
764                             assert_eq!(i, 0);
765                             return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
766                         }
767                     }
768                 }
769
770                 ty::Dynamic(_, _, ty::DynStar) => {
771                     if i == 0 {
772                         TyMaybeWithLayout::Ty(tcx.types.usize)
773                     } else if i == 1 {
774                         // FIXME(dyn-star) same FIXME as above applies here too
775                         TyMaybeWithLayout::Ty(
776                             tcx.mk_imm_ref(
777                                 tcx.lifetimes.re_static,
778                                 tcx.mk_array(tcx.types.usize, 3),
779                             ),
780                         )
781                     } else {
782                         bug!("no field {i} on dyn*")
783                     }
784                 }
785
786                 ty::Alias(..)
787                 | ty::Bound(..)
788                 | ty::Placeholder(..)
789                 | ty::Param(_)
790                 | ty::Infer(_)
791                 | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
792             }
793         }
794
795         match field_ty_or_layout(this, cx, i) {
796             TyMaybeWithLayout::Ty(field_ty) => {
797                 cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
798                     bug!(
799                         "failed to get layout for `{}`: {},\n\
800                          despite it being a field (#{}) of an existing layout: {:#?}",
801                         field_ty,
802                         e,
803                         i,
804                         this
805                     )
806                 })
807             }
808             TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
809         }
810     }
811
812     fn ty_and_layout_pointee_info_at(
813         this: TyAndLayout<'tcx>,
814         cx: &C,
815         offset: Size,
816     ) -> Option<PointeeInfo> {
817         let tcx = cx.tcx();
818         let param_env = cx.param_env();
819
820         let pointee_info =
821             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| {
831                         PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
832                     })
833                 }
834                 ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
835                     let kind = if tcx.sess.opts.optimize == OptLevel::No {
836                         // Use conservative pointer kind if not optimizing. This saves us the
837                         // Freeze/Unpin queries, and can save time in the codegen backend (noalias
838                         // attributes in LLVM have compile-time cost even in unoptimized builds).
839                         PointerKind::SharedMutable
840                     } else {
841                         match mt {
842                             hir::Mutability::Not => {
843                                 if ty.is_freeze(tcx, cx.param_env()) {
844                                     PointerKind::Frozen
845                                 } else {
846                                     PointerKind::SharedMutable
847                                 }
848                             }
849                             hir::Mutability::Mut => {
850                                 // References to self-referential structures should not be considered
851                                 // noalias, as another pointer to the structure can be obtained, that
852                                 // is not based-on the original reference. We consider all !Unpin
853                                 // types to be potentially self-referential here.
854                                 if ty.is_unpin(tcx, cx.param_env()) {
855                                     PointerKind::UniqueBorrowed
856                                 } else {
857                                     PointerKind::UniqueBorrowedPinned
858                                 }
859                             }
860                         }
861                     };
862
863                     tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
864                         size: layout.size,
865                         align: layout.align.abi,
866                         safe: Some(kind),
867                     })
868                 }
869
870                 _ => {
871                     let mut data_variant = match this.variants {
872                         // Within the discriminant field, only the niche itself is
873                         // always initialized, so we only check for a pointer at its
874                         // offset.
875                         //
876                         // If the niche is a pointer, it's either valid (according
877                         // to its type), or null (which the niche field's scalar
878                         // validity range encodes). This allows using
879                         // `dereferenceable_or_null` for e.g., `Option<&T>`, and
880                         // this will continue to work as long as we don't start
881                         // using more niches than just null (e.g., the first page of
882                         // the address space, or unaligned pointers).
883                         Variants::Multiple {
884                             tag_encoding: TagEncoding::Niche { untagged_variant, .. },
885                             tag_field,
886                             ..
887                         } if this.fields.offset(tag_field) == offset => {
888                             Some(this.for_variant(cx, untagged_variant))
889                         }
890                         _ => Some(this),
891                     };
892
893                     if let Some(variant) = data_variant {
894                         // We're not interested in any unions.
895                         if let FieldsShape::Union(_) = variant.fields {
896                             data_variant = None;
897                         }
898                     }
899
900                     let mut result = None;
901
902                     if let Some(variant) = data_variant {
903                         // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
904                         // (requires passing in the expected address space from the caller)
905                         let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
906                         for i in 0..variant.fields.count() {
907                             let field_start = variant.fields.offset(i);
908                             if field_start <= offset {
909                                 let field = variant.field(cx, i);
910                                 result = field.to_result().ok().and_then(|field| {
911                                     if ptr_end <= field_start + field.size {
912                                         // We found the right field, look inside it.
913                                         let field_info =
914                                             field.pointee_info_at(cx, offset - field_start);
915                                         field_info
916                                     } else {
917                                         None
918                                     }
919                                 });
920                                 if result.is_some() {
921                                     break;
922                                 }
923                             }
924                         }
925                     }
926
927                     // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
928                     if let Some(ref mut pointee) = result {
929                         if let ty::Adt(def, _) = this.ty.kind() {
930                             if def.is_box() && offset.bytes() == 0 {
931                                 pointee.safe = Some(PointerKind::UniqueOwned);
932                             }
933                         }
934                     }
935
936                     result
937                 }
938             };
939
940         debug!(
941             "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
942             offset,
943             this.ty.kind(),
944             pointee_info
945         );
946
947         pointee_info
948     }
949
950     fn is_adt(this: TyAndLayout<'tcx>) -> bool {
951         matches!(this.ty.kind(), ty::Adt(..))
952     }
953
954     fn is_never(this: TyAndLayout<'tcx>) -> bool {
955         this.ty.kind() == &ty::Never
956     }
957
958     fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
959         matches!(this.ty.kind(), ty::Tuple(..))
960     }
961
962     fn is_unit(this: TyAndLayout<'tcx>) -> bool {
963         matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
964     }
965 }
966
967 /// Calculates whether a function's ABI can unwind or not.
968 ///
969 /// This takes two primary parameters:
970 ///
971 /// * `codegen_fn_attr_flags` - these are flags calculated as part of the
972 ///   codegen attrs for a defined function. For function pointers this set of
973 ///   flags is the empty set. This is only applicable for Rust-defined
974 ///   functions, and generally isn't needed except for small optimizations where
975 ///   we try to say a function which otherwise might look like it could unwind
976 ///   doesn't actually unwind (such as for intrinsics and such).
977 ///
978 /// * `abi` - this is the ABI that the function is defined with. This is the
979 ///   primary factor for determining whether a function can unwind or not.
980 ///
981 /// Note that in this case unwinding is not necessarily panicking in Rust. Rust
982 /// panics are implemented with unwinds on most platform (when
983 /// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
984 /// Notably unwinding is disallowed for more non-Rust ABIs unless it's
985 /// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
986 /// defined for each ABI individually, but it always corresponds to some form of
987 /// stack-based unwinding (the exact mechanism of which varies
988 /// platform-by-platform).
989 ///
990 /// Rust functions are classified whether or not they can unwind based on the
991 /// active "panic strategy". In other words Rust functions are considered to
992 /// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
993 /// Note that Rust supports intermingling panic=abort and panic=unwind code, but
994 /// only if the final panic mode is panic=abort. In this scenario any code
995 /// previously compiled assuming that a function can unwind is still correct, it
996 /// just never happens to actually unwind at runtime.
997 ///
998 /// This function's answer to whether or not a function can unwind is quite
999 /// impactful throughout the compiler. This affects things like:
1000 ///
1001 /// * Calling a function which can't unwind means codegen simply ignores any
1002 ///   associated unwinding cleanup.
1003 /// * Calling a function which can unwind from a function which can't unwind
1004 ///   causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
1005 ///   aborts the process.
1006 /// * This affects whether functions have the LLVM `nounwind` attribute, which
1007 ///   affects various optimizations and codegen.
1008 ///
1009 /// FIXME: this is actually buggy with respect to Rust functions. Rust functions
1010 /// compiled with `-Cpanic=unwind` and referenced from another crate compiled
1011 /// with `-Cpanic=abort` will look like they can't unwind when in fact they
1012 /// might (from a foreign exception or similar).
1013 #[inline]
1014 #[tracing::instrument(level = "debug", skip(tcx))]
1015 pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
1016     if let Some(did) = fn_def_id {
1017         // Special attribute for functions which can't unwind.
1018         if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
1019             return false;
1020         }
1021
1022         // With `-C panic=abort`, all non-FFI functions are required to not unwind.
1023         //
1024         // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
1025         // function defined in Rust is also required to abort.
1026         if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
1027             return false;
1028         }
1029
1030         // With -Z panic-in-drop=abort, drop_in_place never unwinds.
1031         //
1032         // This is not part of `codegen_fn_attrs` as it can differ between crates
1033         // and therefore cannot be computed in core.
1034         if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort {
1035             if Some(did) == tcx.lang_items().drop_in_place_fn() {
1036                 return false;
1037             }
1038         }
1039     }
1040
1041     // Otherwise if this isn't special then unwinding is generally determined by
1042     // the ABI of the itself. ABIs like `C` have variants which also
1043     // specifically allow unwinding (`C-unwind`), but not all platform-specific
1044     // ABIs have such an option. Otherwise the only other thing here is Rust
1045     // itself, and those ABIs are determined by the panic strategy configured
1046     // for this compilation.
1047     //
1048     // Unfortunately at this time there's also another caveat. Rust [RFC
1049     // 2945][rfc] has been accepted and is in the process of being implemented
1050     // and stabilized. In this interim state we need to deal with historical
1051     // rustc behavior as well as plan for future rustc behavior.
1052     //
1053     // Historically functions declared with `extern "C"` were marked at the
1054     // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
1055     // or not. This is UB for functions in `panic=unwind` mode that then
1056     // actually panic and unwind. Note that this behavior is true for both
1057     // externally declared functions as well as Rust-defined function.
1058     //
1059     // To fix this UB rustc would like to change in the future to catch unwinds
1060     // from function calls that may unwind within a Rust-defined `extern "C"`
1061     // function and forcibly abort the process, thereby respecting the
1062     // `nounwind` attribute emitted for `extern "C"`. This behavior change isn't
1063     // ready to roll out, so determining whether or not the `C` family of ABIs
1064     // unwinds is conditional not only on their definition but also whether the
1065     // `#![feature(c_unwind)]` feature gate is active.
1066     //
1067     // Note that this means that unlike historical compilers rustc now, by
1068     // default, unconditionally thinks that the `C` ABI may unwind. This will
1069     // prevent some optimization opportunities, however, so we try to scope this
1070     // change and only assume that `C` unwinds with `panic=unwind` (as opposed
1071     // to `panic=abort`).
1072     //
1073     // Eventually the check against `c_unwind` here will ideally get removed and
1074     // this'll be a little cleaner as it'll be a straightforward check of the
1075     // ABI.
1076     //
1077     // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
1078     use SpecAbi::*;
1079     match abi {
1080         C { unwind }
1081         | System { unwind }
1082         | Cdecl { unwind }
1083         | Stdcall { unwind }
1084         | Fastcall { unwind }
1085         | Vectorcall { unwind }
1086         | Thiscall { unwind }
1087         | Aapcs { unwind }
1088         | Win64 { unwind }
1089         | SysV64 { unwind } => {
1090             unwind
1091                 || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
1092         }
1093         PtxKernel
1094         | Msp430Interrupt
1095         | X86Interrupt
1096         | AmdGpuKernel
1097         | EfiApi
1098         | AvrInterrupt
1099         | AvrNonBlockingInterrupt
1100         | CCmseNonSecureCall
1101         | Wasm
1102         | RustIntrinsic
1103         | PlatformIntrinsic
1104         | Unadjusted => false,
1105         Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
1106     }
1107 }
1108
1109 /// Error produced by attempting to compute or adjust a `FnAbi`.
1110 #[derive(Copy, Clone, Debug, HashStable)]
1111 pub enum FnAbiError<'tcx> {
1112     /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
1113     Layout(LayoutError<'tcx>),
1114
1115     /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
1116     AdjustForForeignAbi(call::AdjustForForeignAbiError),
1117 }
1118
1119 impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
1120     fn from(err: LayoutError<'tcx>) -> Self {
1121         Self::Layout(err)
1122     }
1123 }
1124
1125 impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
1126     fn from(err: call::AdjustForForeignAbiError) -> Self {
1127         Self::AdjustForForeignAbi(err)
1128     }
1129 }
1130
1131 impl<'tcx> fmt::Display for FnAbiError<'tcx> {
1132     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1133         match self {
1134             Self::Layout(err) => err.fmt(f),
1135             Self::AdjustForForeignAbi(err) => err.fmt(f),
1136         }
1137     }
1138 }
1139
1140 impl IntoDiagnostic<'_, !> for FnAbiError<'_> {
1141     fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
1142         handler.struct_fatal(self.to_string())
1143     }
1144 }
1145
1146 // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
1147 // just for error handling.
1148 #[derive(Debug)]
1149 pub enum FnAbiRequest<'tcx> {
1150     OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1151     OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1152 }
1153
1154 /// Trait for contexts that want to be able to compute `FnAbi`s.
1155 /// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
1156 pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
1157     /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
1158     /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
1159     type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
1160
1161     /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
1162     /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
1163     ///
1164     /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
1165     /// but this hook allows e.g. codegen to return only `&FnAbi` from its
1166     /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
1167     /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
1168     fn handle_fn_abi_err(
1169         &self,
1170         err: FnAbiError<'tcx>,
1171         span: Span,
1172         fn_abi_request: FnAbiRequest<'tcx>,
1173     ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
1174 }
1175
1176 /// Blanket extension trait for contexts that can compute `FnAbi`s.
1177 pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
1178     /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
1179     ///
1180     /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
1181     /// instead, where the instance is an `InstanceDef::Virtual`.
1182     #[inline]
1183     fn fn_abi_of_fn_ptr(
1184         &self,
1185         sig: ty::PolyFnSig<'tcx>,
1186         extra_args: &'tcx ty::List<Ty<'tcx>>,
1187     ) -> Self::FnAbiOfResult {
1188         // FIXME(eddyb) get a better `span` here.
1189         let span = self.layout_tcx_at_span();
1190         let tcx = self.tcx().at(span);
1191
1192         MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
1193             |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
1194         ))
1195     }
1196
1197     /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1198     /// direct calls to an `fn`.
1199     ///
1200     /// NB: that includes virtual calls, which are represented by "direct calls"
1201     /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1202     #[inline]
1203     #[tracing::instrument(level = "debug", skip(self))]
1204     fn fn_abi_of_instance(
1205         &self,
1206         instance: ty::Instance<'tcx>,
1207         extra_args: &'tcx ty::List<Ty<'tcx>>,
1208     ) -> Self::FnAbiOfResult {
1209         // FIXME(eddyb) get a better `span` here.
1210         let span = self.layout_tcx_at_span();
1211         let tcx = self.tcx().at(span);
1212
1213         MaybeResult::from(
1214             tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
1215                 // HACK(eddyb) at least for definitions of/calls to `Instance`s,
1216                 // we can get some kind of span even if one wasn't provided.
1217                 // However, we don't do this early in order to avoid calling
1218                 // `def_span` unconditionally (which may have a perf penalty).
1219                 let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1220                 self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
1221             }),
1222         )
1223     }
1224 }
1225
1226 impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}