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