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};
5 use rustc_attr as attr;
6 use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
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};
18 use std::num::NonZeroUsize;
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;
35 impl IntegerExt for Integer {
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,
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();
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()
68 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer {
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(),
78 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> Integer {
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(),
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.
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));
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 };
112 "Integer::repr_discr: `#[repr]` hint too small for \
113 discriminant range of enum `{}",
117 return (discr, ity.is_signed());
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
125 // repr(Rust) enums try to be as small as possible
129 // If there are no negative values, we can use the unsigned fit.
131 (cmp::max(unsigned_fit, at_least), false)
133 (cmp::max(signed_fit, at_least), true)
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>;
143 impl PrimitiveExt for Primitive {
145 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
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()),
154 /// Return an *integer* type matching this primitive.
155 /// Useful in particular when dealing with enum discriminants.
157 fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
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"),
166 /// The first half of a fat pointer.
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;
172 /// The second half of a fat pointer.
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;
178 /// The maximum supported number of lanes in a SIMD vector.
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;
185 #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
186 pub enum LayoutError<'tcx> {
188 SizeOverflow(Ty<'tcx>),
189 NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
192 impl IntoDiagnostic<'_, !> for LayoutError<'_> {
193 fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
194 let mut diag = handler.struct_fatal("");
197 LayoutError::Unknown(ty) => {
198 diag.set_arg("ty", ty);
199 diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout);
201 LayoutError::SizeOverflow(ty) => {
202 diag.set_arg("ty", ty);
203 diag.set_primary_message(rustc_errors::fluent::middle_values_too_big);
205 LayoutError::NormalizationFailure(ty, e) => {
206 diag.set_arg("ty", ty);
207 diag.set_arg("failure_ty", e.get_type_for_failure());
208 diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized);
215 // FIXME: Once the other errors that embed this error have been converted to translateable
216 // diagnostics, this Display impl should be removed.
217 impl<'tcx> fmt::Display for LayoutError<'tcx> {
218 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty),
221 LayoutError::SizeOverflow(ty) => {
222 write!(f, "values of the type `{}` are too big for the current architecture", ty)
224 LayoutError::NormalizationFailure(t, e) => write!(
226 "unable to determine layout for `{}` because `{}` cannot be normalized",
228 e.get_type_for_failure()
234 #[derive(Clone, Copy)]
235 pub struct LayoutCx<'tcx, C> {
237 pub param_env: ty::ParamEnv<'tcx>,
240 /// Type size "skeleton", i.e., the only information determining a type's size.
241 /// While this is conservative, (aside from constant sizes, only pointers,
242 /// newtypes thereof and null pointer optimized enums are allowed), it is
243 /// enough to statically check common use cases of transmute.
244 #[derive(Copy, Clone, Debug)]
245 pub enum SizeSkeleton<'tcx> {
246 /// Any statically computable Layout.
249 /// A potentially-fat pointer.
251 /// If true, this pointer is never null.
253 /// The type which determines the unsized metadata, if any,
254 /// of this pointer. Either a type parameter or a projection
255 /// depending on one, with regions erased.
260 impl<'tcx> SizeSkeleton<'tcx> {
264 param_env: ty::ParamEnv<'tcx>,
265 ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
266 debug_assert!(!ty.has_non_region_infer());
268 // First try computing a static layout.
269 let err = match tcx.layout_of(param_env.and(ty)) {
271 return Ok(SizeSkeleton::Known(layout.size));
277 ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
278 let non_zero = !ty.is_unsafe_ptr();
279 let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
281 ty::Param(_) | ty::Projection(_) => {
282 debug_assert!(tail.has_non_region_param());
283 Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
286 "SizeSkeleton::compute({}): layout errored ({}), yet \
287 tail `{}` is not a type parameter or a projection",
295 ty::Adt(def, substs) => {
296 // Only newtypes and enums w/ nullable pointer optimization.
297 if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
301 // Get a zero-sized variant or a pointer newtype.
302 let zero_or_ptr_variant = |i| {
303 let i = VariantIdx::new(i);
305 def.variant(i).fields.iter().map(|field| {
306 SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
309 for field in fields {
312 SizeSkeleton::Known(size) => {
313 if size.bytes() > 0 {
317 SizeSkeleton::Pointer { .. } => {
328 let v0 = zero_or_ptr_variant(0)?;
330 if def.variants().len() == 1 {
331 if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
332 return Ok(SizeSkeleton::Pointer {
334 || match tcx.layout_scalar_valid_range(def.did()) {
335 (Bound::Included(start), Bound::Unbounded) => start > 0,
336 (Bound::Included(start), Bound::Included(end)) => {
337 0 < start && start < end
348 let v1 = zero_or_ptr_variant(1)?;
349 // Nullable pointer enum optimization.
351 (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
352 | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
353 Ok(SizeSkeleton::Pointer { non_zero: false, tail })
359 ty::Projection(_) | ty::Opaque(..) => {
360 let normalized = tcx.normalize_erasing_regions(param_env, ty);
361 if ty == normalized {
364 SizeSkeleton::compute(normalized, tcx, param_env)
372 pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
373 match (self, other) {
374 (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b,
375 (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
383 pub trait HasTyCtxt<'tcx>: HasDataLayout {
384 fn tcx(&self) -> TyCtxt<'tcx>;
387 pub trait HasParamEnv<'tcx> {
388 fn param_env(&self) -> ty::ParamEnv<'tcx>;
391 impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
393 fn data_layout(&self) -> &TargetDataLayout {
398 impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
399 fn target_spec(&self) -> &Target {
404 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
406 fn tcx(&self) -> TyCtxt<'tcx> {
411 impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
413 fn data_layout(&self) -> &TargetDataLayout {
418 impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
419 fn target_spec(&self) -> &Target {
424 impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
426 fn tcx(&self) -> TyCtxt<'tcx> {
431 impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
432 fn param_env(&self) -> ty::ParamEnv<'tcx> {
437 impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
438 fn data_layout(&self) -> &TargetDataLayout {
439 self.tcx.data_layout()
443 impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
444 fn target_spec(&self) -> &Target {
445 self.tcx.target_spec()
449 impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
450 fn tcx(&self) -> TyCtxt<'tcx> {
455 pub trait MaybeResult<T> {
458 fn from(x: Result<T, Self::Error>) -> Self;
459 fn to_result(self) -> Result<T, Self::Error>;
462 impl<T> MaybeResult<T> for T {
465 fn from(Ok(x): Result<T, Self::Error>) -> Self {
468 fn to_result(self) -> Result<T, Self::Error> {
473 impl<T, E> MaybeResult<T> for Result<T, E> {
476 fn from(x: Result<T, Self::Error>) -> Self {
479 fn to_result(self) -> Result<T, Self::Error> {
484 pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
486 /// Trait for contexts that want to be able to compute layouts of types.
487 /// This automatically gives access to `LayoutOf`, through a blanket `impl`.
488 pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> {
489 /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
490 /// returned from `layout_of` (see also `handle_layout_err`).
491 type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>>;
493 /// `Span` to use for `tcx.at(span)`, from `layout_of`.
494 // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better?
496 fn layout_tcx_at_span(&self) -> Span {
500 /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
501 /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
503 /// Most `impl`s, which propagate `LayoutError`s, should simply return `err`,
504 /// but this hook allows e.g. codegen to return only `TyAndLayout` from its
505 /// `cx.layout_of(...)`, without any `Result<...>` around it to deal with
506 /// (and any `LayoutError`s are turned into fatal errors or ICEs).
507 fn handle_layout_err(
509 err: LayoutError<'tcx>,
512 ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
515 /// Blanket extension trait for contexts that can compute layouts of types.
516 pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
517 /// Computes the layout of a type. Note that this implicitly
518 /// executes in "reveal all" mode, and will normalize the input type.
520 fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
521 self.spanned_layout_of(ty, DUMMY_SP)
524 /// Computes the layout of a type, at `span`. Note that this implicitly
525 /// executes in "reveal all" mode, and will normalize the input type.
526 // FIXME(eddyb) avoid passing information like this, and instead add more
527 // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
529 fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
530 let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
531 let tcx = self.tcx().at(span);
534 tcx.layout_of(self.param_env().and(ty))
535 .map_err(|err| self.handle_layout_err(err, span, ty)),
540 impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
542 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
543 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
546 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
551 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
552 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
555 fn layout_tcx_at_span(&self) -> Span {
560 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
565 impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
567 C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
569 fn ty_and_layout_for_variant(
570 this: TyAndLayout<'tcx>,
572 variant_index: VariantIdx,
573 ) -> TyAndLayout<'tcx> {
574 let layout = match this.variants {
575 Variants::Single { index }
576 // If all variants but one are uninhabited, the variant layout is the enum layout.
577 if index == variant_index &&
578 // Don't confuse variants of uninhabited enums with the enum itself.
579 // For more details see https://github.com/rust-lang/rust/issues/69763.
580 this.fields != FieldsShape::Primitive =>
585 Variants::Single { index } => {
587 let param_env = cx.param_env();
589 // Deny calling for_variant more than once for non-Single enums.
590 if let Ok(original_layout) = tcx.layout_of(param_env.and(this.ty)) {
591 assert_eq!(original_layout.variants, Variants::Single { index });
594 let fields = match this.ty.kind() {
595 ty::Adt(def, _) if def.variants().is_empty() =>
596 bug!("for_variant called on zero-variant enum"),
597 ty::Adt(def, _) => def.variant(variant_index).fields.len(),
600 tcx.intern_layout(LayoutS {
601 variants: Variants::Single { index: variant_index },
602 fields: match NonZeroUsize::new(fields) {
603 Some(fields) => FieldsShape::Union(fields),
604 None => FieldsShape::Arbitrary { offsets: vec![], memory_index: vec![] },
606 abi: Abi::Uninhabited,
608 align: tcx.data_layout.i8_align,
613 Variants::Multiple { ref variants, .. } => variants[variant_index],
616 assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
618 TyAndLayout { ty: this.ty, layout }
621 fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
622 enum TyMaybeWithLayout<'tcx> {
624 TyAndLayout(TyAndLayout<'tcx>),
627 fn field_ty_or_layout<'tcx>(
628 this: TyAndLayout<'tcx>,
629 cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
631 ) -> TyMaybeWithLayout<'tcx> {
633 let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
635 layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
636 ty: tag.primitive().to_ty(tcx),
640 match *this.ty.kind() {
649 | ty::GeneratorWitness(..)
651 | ty::Dynamic(_, _, ty::Dyn) => {
652 bug!("TyAndLayout::field({:?}): not applicable", this)
655 // Potentially-fat pointers.
656 ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
657 assert!(i < this.fields.count());
659 // Reuse the fat `*T` type as its own thin pointer data field.
660 // This provides information about, e.g., DST struct pointees
661 // (which may have no non-DST form), and will work as long
662 // as the `Abi` or `FieldsShape` is checked by users.
664 let nil = tcx.mk_unit();
665 let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
668 tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
671 // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
672 // the `Result` should always work because the type is
673 // always either `*mut ()` or `&'static mut ()`.
674 return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
676 ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
680 match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
681 ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
682 ty::Dynamic(_, _, ty::Dyn) => {
683 TyMaybeWithLayout::Ty(tcx.mk_imm_ref(
684 tcx.lifetimes.re_static,
685 tcx.mk_array(tcx.types.usize, 3),
687 /* FIXME: use actual fn pointers
688 Warning: naively computing the number of entries in the
689 vtable by counting the methods on the trait + methods on
690 all parent traits does not work, because some methods can
691 be not object safe and thus excluded from the vtable.
692 Increase this counter if you tried to implement this but
693 failed to do it without duplicating a lot of code from
694 other places in the compiler: 2
696 tcx.mk_array(tcx.types.usize, 3),
697 tcx.mk_array(Option<fn()>),
701 _ => bug!("TyAndLayout::field({:?}): not applicable", this),
705 // Arrays and slices.
706 ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
707 ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
709 // Tuples, generators and closures.
710 ty::Closure(_, ref substs) => field_ty_or_layout(
711 TyAndLayout { ty: substs.as_closure().tupled_upvars_ty(), ..this },
716 ty::Generator(def_id, ref substs, _) => match this.variants {
717 Variants::Single { index } => TyMaybeWithLayout::Ty(
720 .state_tys(def_id, tcx)
721 .nth(index.as_usize())
726 Variants::Multiple { tag, tag_field, .. } => {
728 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
730 TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
734 ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
737 ty::Adt(def, substs) => {
738 match this.variants {
739 Variants::Single { index } => {
740 TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs))
743 // Discriminant field for enums (where applicable).
744 Variants::Multiple { tag, .. } => {
746 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
751 ty::Dynamic(_, _, ty::DynStar) => {
753 TyMaybeWithLayout::Ty(tcx.types.usize)
755 // FIXME(dyn-star) same FIXME as above applies here too
756 TyMaybeWithLayout::Ty(
758 tcx.lifetimes.re_static,
759 tcx.mk_array(tcx.types.usize, 3),
763 bug!("no field {i} on dyn*")
769 | ty::Placeholder(..)
773 | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
777 match field_ty_or_layout(this, cx, i) {
778 TyMaybeWithLayout::Ty(field_ty) => {
779 cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
781 "failed to get layout for `{}`: {},\n\
782 despite it being a field (#{}) of an existing layout: {:#?}",
790 TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
794 fn ty_and_layout_pointee_info_at(
795 this: TyAndLayout<'tcx>,
798 ) -> Option<PointeeInfo> {
800 let param_env = cx.param_env();
802 let addr_space_of_ty = |ty: Ty<'tcx>| {
803 if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
806 let pointee_info = match *this.ty.kind() {
807 ty::RawPtr(mt) if offset.bytes() == 0 => {
808 tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
810 align: layout.align.abi,
812 address_space: addr_space_of_ty(mt.ty),
815 ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
816 tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
818 align: layout.align.abi,
820 address_space: cx.data_layout().instruction_address_space,
823 ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
824 let address_space = addr_space_of_ty(ty);
825 let kind = if tcx.sess.opts.optimize == OptLevel::No {
826 // Use conservative pointer kind if not optimizing. This saves us the
827 // Freeze/Unpin queries, and can save time in the codegen backend (noalias
828 // attributes in LLVM have compile-time cost even in unoptimized builds).
829 PointerKind::SharedMutable
832 hir::Mutability::Not => {
833 if ty.is_freeze(tcx, cx.param_env()) {
836 PointerKind::SharedMutable
839 hir::Mutability::Mut => {
840 // References to self-referential structures should not be considered
841 // noalias, as another pointer to the structure can be obtained, that
842 // is not based-on the original reference. We consider all !Unpin
843 // types to be potentially self-referential here.
844 if ty.is_unpin(tcx, cx.param_env()) {
845 PointerKind::UniqueBorrowed
847 PointerKind::UniqueBorrowedPinned
853 tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
855 align: layout.align.abi,
862 let mut data_variant = match this.variants {
863 // Within the discriminant field, only the niche itself is
864 // always initialized, so we only check for a pointer at its
867 // If the niche is a pointer, it's either valid (according
868 // to its type), or null (which the niche field's scalar
869 // validity range encodes). This allows using
870 // `dereferenceable_or_null` for e.g., `Option<&T>`, and
871 // this will continue to work as long as we don't start
872 // using more niches than just null (e.g., the first page of
873 // the address space, or unaligned pointers).
875 tag_encoding: TagEncoding::Niche { untagged_variant, .. },
878 } if this.fields.offset(tag_field) == offset => {
879 Some(this.for_variant(cx, untagged_variant))
884 if let Some(variant) = data_variant {
885 // We're not interested in any unions.
886 if let FieldsShape::Union(_) = variant.fields {
891 let mut result = None;
893 if let Some(variant) = data_variant {
894 let ptr_end = offset + Pointer.size(cx);
895 for i in 0..variant.fields.count() {
896 let field_start = variant.fields.offset(i);
897 if field_start <= offset {
898 let field = variant.field(cx, i);
899 result = field.to_result().ok().and_then(|field| {
900 if ptr_end <= field_start + field.size {
901 // We found the right field, look inside it.
903 field.pointee_info_at(cx, offset - field_start);
909 if result.is_some() {
916 // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
917 if let Some(ref mut pointee) = result {
918 if let ty::Adt(def, _) = this.ty.kind() {
919 if def.is_box() && offset.bytes() == 0 {
920 pointee.safe = Some(PointerKind::UniqueOwned);
930 "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
939 fn is_adt(this: TyAndLayout<'tcx>) -> bool {
940 matches!(this.ty.kind(), ty::Adt(..))
943 fn is_never(this: TyAndLayout<'tcx>) -> bool {
944 this.ty.kind() == &ty::Never
947 fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
948 matches!(this.ty.kind(), ty::Tuple(..))
951 fn is_unit(this: TyAndLayout<'tcx>) -> bool {
952 matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
956 /// Calculates whether a function's ABI can unwind or not.
958 /// This takes two primary parameters:
960 /// * `codegen_fn_attr_flags` - these are flags calculated as part of the
961 /// codegen attrs for a defined function. For function pointers this set of
962 /// flags is the empty set. This is only applicable for Rust-defined
963 /// functions, and generally isn't needed except for small optimizations where
964 /// we try to say a function which otherwise might look like it could unwind
965 /// doesn't actually unwind (such as for intrinsics and such).
967 /// * `abi` - this is the ABI that the function is defined with. This is the
968 /// primary factor for determining whether a function can unwind or not.
970 /// Note that in this case unwinding is not necessarily panicking in Rust. Rust
971 /// panics are implemented with unwinds on most platform (when
972 /// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
973 /// Notably unwinding is disallowed for more non-Rust ABIs unless it's
974 /// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
975 /// defined for each ABI individually, but it always corresponds to some form of
976 /// stack-based unwinding (the exact mechanism of which varies
977 /// platform-by-platform).
979 /// Rust functions are classified whether or not they can unwind based on the
980 /// active "panic strategy". In other words Rust functions are considered to
981 /// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
982 /// Note that Rust supports intermingling panic=abort and panic=unwind code, but
983 /// only if the final panic mode is panic=abort. In this scenario any code
984 /// previously compiled assuming that a function can unwind is still correct, it
985 /// just never happens to actually unwind at runtime.
987 /// This function's answer to whether or not a function can unwind is quite
988 /// impactful throughout the compiler. This affects things like:
990 /// * Calling a function which can't unwind means codegen simply ignores any
991 /// associated unwinding cleanup.
992 /// * Calling a function which can unwind from a function which can't unwind
993 /// causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
994 /// aborts the process.
995 /// * This affects whether functions have the LLVM `nounwind` attribute, which
996 /// affects various optimizations and codegen.
998 /// FIXME: this is actually buggy with respect to Rust functions. Rust functions
999 /// compiled with `-Cpanic=unwind` and referenced from another crate compiled
1000 /// with `-Cpanic=abort` will look like they can't unwind when in fact they
1001 /// might (from a foreign exception or similar).
1003 #[tracing::instrument(level = "debug", skip(tcx))]
1004 pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
1005 if let Some(did) = fn_def_id {
1006 // Special attribute for functions which can't unwind.
1007 if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
1011 // With `-C panic=abort`, all non-FFI functions are required to not unwind.
1013 // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
1014 // function defined in Rust is also required to abort.
1015 if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
1019 // With -Z panic-in-drop=abort, drop_in_place never unwinds.
1021 // This is not part of `codegen_fn_attrs` as it can differ between crates
1022 // and therefore cannot be computed in core.
1023 if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort {
1024 if Some(did) == tcx.lang_items().drop_in_place_fn() {
1030 // Otherwise if this isn't special then unwinding is generally determined by
1031 // the ABI of the itself. ABIs like `C` have variants which also
1032 // specifically allow unwinding (`C-unwind`), but not all platform-specific
1033 // ABIs have such an option. Otherwise the only other thing here is Rust
1034 // itself, and those ABIs are determined by the panic strategy configured
1035 // for this compilation.
1037 // Unfortunately at this time there's also another caveat. Rust [RFC
1038 // 2945][rfc] has been accepted and is in the process of being implemented
1039 // and stabilized. In this interim state we need to deal with historical
1040 // rustc behavior as well as plan for future rustc behavior.
1042 // Historically functions declared with `extern "C"` were marked at the
1043 // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
1044 // or not. This is UB for functions in `panic=unwind` mode that then
1045 // actually panic and unwind. Note that this behavior is true for both
1046 // externally declared functions as well as Rust-defined function.
1048 // To fix this UB rustc would like to change in the future to catch unwinds
1049 // from function calls that may unwind within a Rust-defined `extern "C"`
1050 // function and forcibly abort the process, thereby respecting the
1051 // `nounwind` attribute emitted for `extern "C"`. This behavior change isn't
1052 // ready to roll out, so determining whether or not the `C` family of ABIs
1053 // unwinds is conditional not only on their definition but also whether the
1054 // `#![feature(c_unwind)]` feature gate is active.
1056 // Note that this means that unlike historical compilers rustc now, by
1057 // default, unconditionally thinks that the `C` ABI may unwind. This will
1058 // prevent some optimization opportunities, however, so we try to scope this
1059 // change and only assume that `C` unwinds with `panic=unwind` (as opposed
1060 // to `panic=abort`).
1062 // Eventually the check against `c_unwind` here will ideally get removed and
1063 // this'll be a little cleaner as it'll be a straightforward check of the
1066 // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
1072 | Stdcall { unwind }
1073 | Fastcall { unwind }
1074 | Vectorcall { unwind }
1075 | Thiscall { unwind }
1078 | SysV64 { unwind } => {
1080 || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
1088 | AvrNonBlockingInterrupt
1089 | CCmseNonSecureCall
1093 | Unadjusted => false,
1094 Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
1098 /// Error produced by attempting to compute or adjust a `FnAbi`.
1099 #[derive(Copy, Clone, Debug, HashStable)]
1100 pub enum FnAbiError<'tcx> {
1101 /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
1102 Layout(LayoutError<'tcx>),
1104 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
1105 AdjustForForeignAbi(call::AdjustForForeignAbiError),
1108 impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
1109 fn from(err: LayoutError<'tcx>) -> Self {
1114 impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
1115 fn from(err: call::AdjustForForeignAbiError) -> Self {
1116 Self::AdjustForForeignAbi(err)
1120 impl<'tcx> fmt::Display for FnAbiError<'tcx> {
1121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1123 Self::Layout(err) => err.fmt(f),
1124 Self::AdjustForForeignAbi(err) => err.fmt(f),
1129 impl IntoDiagnostic<'_, !> for FnAbiError<'_> {
1130 fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
1131 handler.struct_fatal(self.to_string())
1135 // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
1136 // just for error handling.
1138 pub enum FnAbiRequest<'tcx> {
1139 OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1140 OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1143 /// Trait for contexts that want to be able to compute `FnAbi`s.
1144 /// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
1145 pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
1146 /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
1147 /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
1148 type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
1150 /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
1151 /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
1153 /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
1154 /// but this hook allows e.g. codegen to return only `&FnAbi` from its
1155 /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
1156 /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
1157 fn handle_fn_abi_err(
1159 err: FnAbiError<'tcx>,
1161 fn_abi_request: FnAbiRequest<'tcx>,
1162 ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
1165 /// Blanket extension trait for contexts that can compute `FnAbi`s.
1166 pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
1167 /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
1169 /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
1170 /// instead, where the instance is an `InstanceDef::Virtual`.
1172 fn fn_abi_of_fn_ptr(
1174 sig: ty::PolyFnSig<'tcx>,
1175 extra_args: &'tcx ty::List<Ty<'tcx>>,
1176 ) -> Self::FnAbiOfResult {
1177 // FIXME(eddyb) get a better `span` here.
1178 let span = self.layout_tcx_at_span();
1179 let tcx = self.tcx().at(span);
1181 MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
1182 |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
1186 /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1187 /// direct calls to an `fn`.
1189 /// NB: that includes virtual calls, which are represented by "direct calls"
1190 /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1192 #[tracing::instrument(level = "debug", skip(self))]
1193 fn fn_abi_of_instance(
1195 instance: ty::Instance<'tcx>,
1196 extra_args: &'tcx ty::List<Ty<'tcx>>,
1197 ) -> Self::FnAbiOfResult {
1198 // FIXME(eddyb) get a better `span` here.
1199 let span = self.layout_tcx_at_span();
1200 let tcx = self.tcx().at(span);
1203 tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
1204 // HACK(eddyb) at least for definitions of/calls to `Instance`s,
1205 // we can get some kind of span even if one wasn't provided.
1206 // However, we don't do this early in order to avoid calling
1207 // `def_span` unconditionally (which may have a perf penalty).
1208 let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1209 self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
1215 impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}