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