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<'a> IntoDiagnostic<'a, !> for LayoutError<'a> {
193 fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
194 handler.struct_fatal(self.to_string())
198 impl<'tcx> fmt::Display for LayoutError<'tcx> {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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)
205 LayoutError::NormalizationFailure(t, e) => write!(
207 "unable to determine layout for `{}` because `{}` cannot be normalized",
209 e.get_type_for_failure()
215 #[derive(Clone, Copy)]
216 pub struct LayoutCx<'tcx, C> {
218 pub param_env: ty::ParamEnv<'tcx>,
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.
230 /// A potentially-fat pointer.
232 /// If true, this pointer is never null.
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.
241 impl<'tcx> SizeSkeleton<'tcx> {
245 param_env: ty::ParamEnv<'tcx>,
246 ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
247 debug_assert!(!ty.has_infer_types_or_consts());
249 // First try computing a static layout.
250 let err = match tcx.layout_of(param_env.and(ty)) {
252 return Ok(SizeSkeleton::Known(layout.size));
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);
262 ty::Param(_) | ty::Projection(_) => {
263 debug_assert!(tail.has_param_types_or_consts());
264 Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
267 "SizeSkeleton::compute({}): layout errored ({}), yet \
268 tail `{}` is not a type parameter or a projection",
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 {
282 // Get a zero-sized variant or a pointer newtype.
283 let zero_or_ptr_variant = |i| {
284 let i = VariantIdx::new(i);
286 def.variant(i).fields.iter().map(|field| {
287 SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
290 for field in fields {
293 SizeSkeleton::Known(size) => {
294 if size.bytes() > 0 {
298 SizeSkeleton::Pointer { .. } => {
309 let v0 = zero_or_ptr_variant(0)?;
311 if def.variants().len() == 1 {
312 if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
313 return Ok(SizeSkeleton::Pointer {
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
329 let v1 = zero_or_ptr_variant(1)?;
330 // Nullable pointer enum optimization.
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 })
340 ty::Projection(_) | ty::Opaque(..) => {
341 let normalized = tcx.normalize_erasing_regions(param_env, ty);
342 if ty == normalized {
345 SizeSkeleton::compute(normalized, tcx, param_env)
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, .. }) => {
364 pub trait HasTyCtxt<'tcx>: HasDataLayout {
365 fn tcx(&self) -> TyCtxt<'tcx>;
368 pub trait HasParamEnv<'tcx> {
369 fn param_env(&self) -> ty::ParamEnv<'tcx>;
372 impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
374 fn data_layout(&self) -> &TargetDataLayout {
379 impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
380 fn target_spec(&self) -> &Target {
385 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
387 fn tcx(&self) -> TyCtxt<'tcx> {
392 impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
394 fn data_layout(&self) -> &TargetDataLayout {
399 impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
400 fn target_spec(&self) -> &Target {
405 impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
407 fn tcx(&self) -> TyCtxt<'tcx> {
412 impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
413 fn param_env(&self) -> ty::ParamEnv<'tcx> {
418 impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
419 fn data_layout(&self) -> &TargetDataLayout {
420 self.tcx.data_layout()
424 impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
425 fn target_spec(&self) -> &Target {
426 self.tcx.target_spec()
430 impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
431 fn tcx(&self) -> TyCtxt<'tcx> {
436 pub trait MaybeResult<T> {
439 fn from(x: Result<T, Self::Error>) -> Self;
440 fn to_result(self) -> Result<T, Self::Error>;
443 impl<T> MaybeResult<T> for T {
446 fn from(Ok(x): Result<T, Self::Error>) -> Self {
449 fn to_result(self) -> Result<T, Self::Error> {
454 impl<T, E> MaybeResult<T> for Result<T, E> {
457 fn from(x: Result<T, Self::Error>) -> Self {
460 fn to_result(self) -> Result<T, Self::Error> {
465 pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
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>>;
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?
477 fn layout_tcx_at_span(&self) -> Span {
481 /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
482 /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
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(
490 err: LayoutError<'tcx>,
493 ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
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.
501 fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
502 self.spanned_layout_of(ty, DUMMY_SP)
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)`.
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);
515 tcx.layout_of(self.param_env().and(ty))
516 .map_err(|err| self.handle_layout_err(err, span, ty)),
521 impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
523 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
524 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
527 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
532 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
533 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
536 fn layout_tcx_at_span(&self) -> Span {
541 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
546 impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
548 C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
550 fn ty_and_layout_for_variant(
551 this: TyAndLayout<'tcx>,
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 =>
566 Variants::Single { index } => {
568 let param_env = cx.param_env();
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 });
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(),
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![] },
587 abi: Abi::Uninhabited,
589 align: tcx.data_layout.i8_align,
594 Variants::Multiple { ref variants, .. } => variants[variant_index],
597 assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
599 TyAndLayout { ty: this.ty, layout }
602 fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
603 enum TyMaybeWithLayout<'tcx> {
605 TyAndLayout(TyAndLayout<'tcx>),
608 fn field_ty_or_layout<'tcx>(
609 this: TyAndLayout<'tcx>,
610 cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
612 ) -> TyMaybeWithLayout<'tcx> {
614 let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
616 layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
617 ty: tag.primitive().to_ty(tcx),
621 match *this.ty.kind() {
630 | ty::GeneratorWitness(..)
632 | ty::Dynamic(_, _, ty::Dyn) => {
633 bug!("TyAndLayout::field({:?}): not applicable", this)
636 // Potentially-fat pointers.
637 ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
638 assert!(i < this.fields.count());
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.
645 let nil = tcx.mk_unit();
646 let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
649 tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
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 {
657 ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
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),
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
677 tcx.mk_array(tcx.types.usize, 3),
678 tcx.mk_array(Option<fn()>),
682 _ => bug!("TyAndLayout::field({:?}): not applicable", this),
686 // Arrays and slices.
687 ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
688 ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
690 // Tuples, generators and closures.
691 ty::Closure(_, ref substs) => field_ty_or_layout(
692 TyAndLayout { ty: substs.as_closure().tupled_upvars_ty(), ..this },
697 ty::Generator(def_id, ref substs, _) => match this.variants {
698 Variants::Single { index } => TyMaybeWithLayout::Ty(
701 .state_tys(def_id, tcx)
702 .nth(index.as_usize())
707 Variants::Multiple { tag, tag_field, .. } => {
709 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
711 TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
715 ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
718 ty::Adt(def, substs) => {
719 match this.variants {
720 Variants::Single { index } => {
721 TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs))
724 // Discriminant field for enums (where applicable).
725 Variants::Multiple { tag, .. } => {
727 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
732 ty::Dynamic(_, _, ty::DynStar) => {
734 TyMaybeWithLayout::Ty(tcx.types.usize)
736 // FIXME(dyn-star) same FIXME as above applies here too
737 TyMaybeWithLayout::Ty(
739 tcx.lifetimes.re_static,
740 tcx.mk_array(tcx.types.usize, 3),
744 bug!("no field {i} on dyn*")
750 | ty::Placeholder(..)
754 | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
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| {
762 "failed to get layout for `{}`: {},\n\
763 despite it being a field (#{}) of an existing layout: {:#?}",
771 TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
775 fn ty_and_layout_pointee_info_at(
776 this: TyAndLayout<'tcx>,
779 ) -> Option<PointeeInfo> {
781 let param_env = cx.param_env();
783 let addr_space_of_ty = |ty: Ty<'tcx>| {
784 if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
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 {
791 align: layout.align.abi,
793 address_space: addr_space_of_ty(mt.ty),
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 {
799 align: layout.align.abi,
801 address_space: cx.data_layout().instruction_address_space,
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
813 hir::Mutability::Not => {
814 if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
817 PointerKind::SharedMutable
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
828 PointerKind::UniqueBorrowedPinned
834 tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
836 align: layout.align.abi,
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
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).
856 tag_encoding: TagEncoding::Niche { untagged_variant, .. },
859 } if this.fields.offset(tag_field) == offset => {
860 Some(this.for_variant(cx, untagged_variant))
865 if let Some(variant) = data_variant {
866 // We're not interested in any unions.
867 if let FieldsShape::Union(_) = variant.fields {
872 let mut result = None;
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.
884 field.pointee_info_at(cx, offset - field_start);
890 if result.is_some() {
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);
911 "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
920 fn is_adt(this: TyAndLayout<'tcx>) -> bool {
921 matches!(this.ty.kind(), ty::Adt(..))
924 fn is_never(this: TyAndLayout<'tcx>) -> bool {
925 this.ty.kind() == &ty::Never
928 fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
929 matches!(this.ty.kind(), ty::Tuple(..))
932 fn is_unit(this: TyAndLayout<'tcx>) -> bool {
933 matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
937 /// Calculates whether a function's ABI can unwind or not.
939 /// This takes two primary parameters:
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).
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.
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).
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.
968 /// This function's answer to whether or not a function can unwind is quite
969 /// impactful throughout the compiler. This affects things like:
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.
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).
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) {
992 // With `-C panic=abort`, all non-FFI functions are required to not unwind.
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) {
1000 // With -Z panic-in-drop=abort, drop_in_place never unwinds.
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() {
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.
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.
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.
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.
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`).
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
1047 // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
1053 | Stdcall { unwind }
1054 | Fastcall { unwind }
1055 | Vectorcall { unwind }
1056 | Thiscall { unwind }
1059 | SysV64 { unwind } => {
1061 || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
1069 | AvrNonBlockingInterrupt
1070 | CCmseNonSecureCall
1074 | Unadjusted => false,
1075 Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
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>),
1085 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
1086 AdjustForForeignAbi(call::AdjustForForeignAbiError),
1089 impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
1090 fn from(err: LayoutError<'tcx>) -> Self {
1095 impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
1096 fn from(err: call::AdjustForForeignAbiError) -> Self {
1097 Self::AdjustForForeignAbi(err)
1101 impl<'tcx> fmt::Display for FnAbiError<'tcx> {
1102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1104 Self::Layout(err) => err.fmt(f),
1105 Self::AdjustForForeignAbi(err) => err.fmt(f),
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())
1116 // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
1117 // just for error handling.
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>> },
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>>>;
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<...>`).
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(
1140 err: FnAbiError<'tcx>,
1142 fn_abi_request: FnAbiRequest<'tcx>,
1143 ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
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.
1150 /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
1151 /// instead, where the instance is an `InstanceDef::Virtual`.
1153 fn fn_abi_of_fn_ptr(
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);
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 }),
1167 /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1168 /// direct calls to an `fn`.
1170 /// NB: that includes virtual calls, which are represented by "direct calls"
1171 /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1173 #[tracing::instrument(level = "debug", skip(self))]
1174 fn fn_abi_of_instance(
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);
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 })
1196 impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}