1 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2 use crate::ty::normalize_erasing_regions::NormalizationError;
3 use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitable};
4 use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
6 use rustc_hir::def_id::DefId;
7 use rustc_index::vec::Idx;
8 use rustc_session::config::OptLevel;
9 use rustc_span::{Span, DUMMY_SP};
10 use rustc_target::abi::call::FnAbi;
11 use rustc_target::abi::*;
12 use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
16 use std::num::NonZeroUsize;
19 pub trait IntegerExt {
20 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
21 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer;
22 fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer;
32 impl IntegerExt for Integer {
34 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
35 match (*self, signed) {
36 (I8, false) => tcx.types.u8,
37 (I16, false) => tcx.types.u16,
38 (I32, false) => tcx.types.u32,
39 (I64, false) => tcx.types.u64,
40 (I128, false) => tcx.types.u128,
41 (I8, true) => tcx.types.i8,
42 (I16, true) => tcx.types.i16,
43 (I32, true) => tcx.types.i32,
44 (I64, true) => tcx.types.i64,
45 (I128, true) => tcx.types.i128,
49 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer {
52 ty::IntTy::I16 => I16,
53 ty::IntTy::I32 => I32,
54 ty::IntTy::I64 => I64,
55 ty::IntTy::I128 => I128,
56 ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
59 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> Integer {
62 ty::UintTy::U16 => I16,
63 ty::UintTy::U32 => I32,
64 ty::UintTy::U64 => I64,
65 ty::UintTy::U128 => I128,
66 ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
70 /// Finds the appropriate Integer type and signedness for the given
71 /// signed discriminant range and `#[repr]` attribute.
72 /// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
73 /// that shouldn't affect anything, other than maybe debuginfo.
80 ) -> (Integer, bool) {
81 // Theoretically, negative values could be larger in unsigned representation
82 // than the unsigned representation of the signed minimum. However, if there
83 // are any negative values, the only valid unsigned representation is u128
84 // which can fit all i128 values, so the result remains unaffected.
85 let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
86 let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
88 if let Some(ity) = repr.int {
89 let discr = Integer::from_attr(&tcx, ity);
90 let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
93 "Integer::repr_discr: `#[repr]` hint too small for \
94 discriminant range of enum `{}",
98 return (discr, ity.is_signed());
101 let at_least = if repr.c() {
102 // This is usually I32, however it can be different on some platforms,
103 // notably hexagon and arm-none/thumb-none
104 tcx.data_layout().c_enum_min_size
106 // repr(Rust) enums try to be as small as possible
110 // If there are no negative values, we can use the unsigned fit.
112 (cmp::max(unsigned_fit, at_least), false)
114 (cmp::max(signed_fit, at_least), true)
119 pub trait PrimitiveExt {
120 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
121 fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
124 impl PrimitiveExt for Primitive {
126 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
128 Int(i, signed) => i.to_ty(tcx, signed),
129 F32 => tcx.types.f32,
130 F64 => tcx.types.f64,
131 // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
132 Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()),
136 /// Return an *integer* type matching this primitive.
137 /// Useful in particular when dealing with enum discriminants.
139 fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
141 Int(i, signed) => i.to_ty(tcx, signed),
142 // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
145 tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
147 F32 | F64 => bug!("floats do not have an int type"),
152 /// The first half of a fat pointer.
154 /// - For a trait object, this is the address of the box.
155 /// - For a slice, this is the base address.
156 pub const FAT_PTR_ADDR: usize = 0;
158 /// The second half of a fat pointer.
160 /// - For a trait object, this is the address of the vtable.
161 /// - For a slice, this is the length.
162 pub const FAT_PTR_EXTRA: usize = 1;
164 /// The maximum supported number of lanes in a SIMD vector.
166 /// This value is selected based on backend support:
167 /// * LLVM does not appear to have a vector width limit.
168 /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
169 pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
171 #[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
172 pub enum LayoutError<'tcx> {
174 SizeOverflow(Ty<'tcx>),
175 NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
178 impl IntoDiagnostic<'_, !> for LayoutError<'_> {
179 fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
180 let mut diag = handler.struct_fatal("");
183 LayoutError::Unknown(ty) => {
184 diag.set_arg("ty", ty);
185 diag.set_primary_message(rustc_errors::fluent::middle_unknown_layout);
187 LayoutError::SizeOverflow(ty) => {
188 diag.set_arg("ty", ty);
189 diag.set_primary_message(rustc_errors::fluent::middle_values_too_big);
191 LayoutError::NormalizationFailure(ty, e) => {
192 diag.set_arg("ty", ty);
193 diag.set_arg("failure_ty", e.get_type_for_failure());
194 diag.set_primary_message(rustc_errors::fluent::middle_cannot_be_normalized);
201 // FIXME: Once the other errors that embed this error have been converted to translateable
202 // diagnostics, this Display impl should be removed.
203 impl<'tcx> fmt::Display for LayoutError<'tcx> {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty),
207 LayoutError::SizeOverflow(ty) => {
208 write!(f, "values of the type `{}` are too big for the current architecture", ty)
210 LayoutError::NormalizationFailure(t, e) => write!(
212 "unable to determine layout for `{}` because `{}` cannot be normalized",
214 e.get_type_for_failure()
220 #[derive(Clone, Copy)]
221 pub struct LayoutCx<'tcx, C> {
223 pub param_env: ty::ParamEnv<'tcx>,
226 impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> {
227 type TargetDataLayoutRef = &'tcx TargetDataLayout;
229 fn delay_bug(&self, txt: &str) {
230 self.tcx.sess.delay_span_bug(DUMMY_SP, txt);
233 fn current_data_layout(&self) -> Self::TargetDataLayoutRef {
234 &self.tcx.data_layout
238 /// Type size "skeleton", i.e., the only information determining a type's size.
239 /// While this is conservative, (aside from constant sizes, only pointers,
240 /// newtypes thereof and null pointer optimized enums are allowed), it is
241 /// enough to statically check common use cases of transmute.
242 #[derive(Copy, Clone, Debug)]
243 pub enum SizeSkeleton<'tcx> {
244 /// Any statically computable Layout.
247 /// A potentially-fat pointer.
249 /// If true, this pointer is never null.
251 /// The type which determines the unsized metadata, if any,
252 /// of this pointer. Either a type parameter or a projection
253 /// depending on one, with regions erased.
258 impl<'tcx> SizeSkeleton<'tcx> {
262 param_env: ty::ParamEnv<'tcx>,
263 ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
264 debug_assert!(!ty.has_non_region_infer());
266 // First try computing a static layout.
267 let err = match tcx.layout_of(param_env.and(ty)) {
269 return Ok(SizeSkeleton::Known(layout.size));
275 ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
276 let non_zero = !ty.is_unsafe_ptr();
277 let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
279 ty::Param(_) | ty::Alias(ty::Projection, _) => {
280 debug_assert!(tail.has_non_region_param());
281 Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
284 "SizeSkeleton::compute({}): layout errored ({}), yet \
285 tail `{}` is not a type parameter or a projection",
293 ty::Adt(def, substs) => {
294 // Only newtypes and enums w/ nullable pointer optimization.
295 if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
299 // Get a zero-sized variant or a pointer newtype.
300 let zero_or_ptr_variant = |i| {
301 let i = VariantIdx::new(i);
303 def.variant(i).fields.iter().map(|field| {
304 SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
307 for field in fields {
310 SizeSkeleton::Known(size) => {
311 if size.bytes() > 0 {
315 SizeSkeleton::Pointer { .. } => {
326 let v0 = zero_or_ptr_variant(0)?;
328 if def.variants().len() == 1 {
329 if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
330 return Ok(SizeSkeleton::Pointer {
332 || match tcx.layout_scalar_valid_range(def.did()) {
333 (Bound::Included(start), Bound::Unbounded) => start > 0,
334 (Bound::Included(start), Bound::Included(end)) => {
335 0 < start && start < end
346 let v1 = zero_or_ptr_variant(1)?;
347 // Nullable pointer enum optimization.
349 (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
350 | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
351 Ok(SizeSkeleton::Pointer { non_zero: false, tail })
358 let normalized = tcx.normalize_erasing_regions(param_env, ty);
359 if ty == normalized {
362 SizeSkeleton::compute(normalized, tcx, param_env)
370 pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
371 match (self, other) {
372 (SizeSkeleton::Known(a), SizeSkeleton::Known(b)) => a == b,
373 (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
381 pub trait HasTyCtxt<'tcx>: HasDataLayout {
382 fn tcx(&self) -> TyCtxt<'tcx>;
385 pub trait HasParamEnv<'tcx> {
386 fn param_env(&self) -> ty::ParamEnv<'tcx>;
389 impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
391 fn data_layout(&self) -> &TargetDataLayout {
396 impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
397 fn target_spec(&self) -> &Target {
402 impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
404 fn tcx(&self) -> TyCtxt<'tcx> {
409 impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
411 fn data_layout(&self) -> &TargetDataLayout {
416 impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
417 fn target_spec(&self) -> &Target {
422 impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
424 fn tcx(&self) -> TyCtxt<'tcx> {
429 impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
430 fn param_env(&self) -> ty::ParamEnv<'tcx> {
435 impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
436 fn data_layout(&self) -> &TargetDataLayout {
437 self.tcx.data_layout()
441 impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
442 fn target_spec(&self) -> &Target {
443 self.tcx.target_spec()
447 impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
448 fn tcx(&self) -> TyCtxt<'tcx> {
453 pub trait MaybeResult<T> {
456 fn from(x: Result<T, Self::Error>) -> Self;
457 fn to_result(self) -> Result<T, Self::Error>;
460 impl<T> MaybeResult<T> for T {
463 fn from(Ok(x): Result<T, Self::Error>) -> Self {
466 fn to_result(self) -> Result<T, Self::Error> {
471 impl<T, E> MaybeResult<T> for Result<T, E> {
474 fn from(x: Result<T, Self::Error>) -> Self {
477 fn to_result(self) -> Result<T, Self::Error> {
482 pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
484 /// Trait for contexts that want to be able to compute layouts of types.
485 /// This automatically gives access to `LayoutOf`, through a blanket `impl`.
486 pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasParamEnv<'tcx> {
487 /// The `TyAndLayout`-wrapping type (or `TyAndLayout` itself), which will be
488 /// returned from `layout_of` (see also `handle_layout_err`).
489 type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>>;
491 /// `Span` to use for `tcx.at(span)`, from `layout_of`.
492 // FIXME(eddyb) perhaps make this mandatory to get contexts to track it better?
494 fn layout_tcx_at_span(&self) -> Span {
498 /// Helper used for `layout_of`, to adapt `tcx.layout_of(...)` into a
499 /// `Self::LayoutOfResult` (which does not need to be a `Result<...>`).
501 /// Most `impl`s, which propagate `LayoutError`s, should simply return `err`,
502 /// but this hook allows e.g. codegen to return only `TyAndLayout` from its
503 /// `cx.layout_of(...)`, without any `Result<...>` around it to deal with
504 /// (and any `LayoutError`s are turned into fatal errors or ICEs).
505 fn handle_layout_err(
507 err: LayoutError<'tcx>,
510 ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
513 /// Blanket extension trait for contexts that can compute layouts of types.
514 pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
515 /// Computes the layout of a type. Note that this implicitly
516 /// executes in "reveal all" mode, and will normalize the input type.
518 fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
519 self.spanned_layout_of(ty, DUMMY_SP)
522 /// Computes the layout of a type, at `span`. Note that this implicitly
523 /// executes in "reveal all" mode, and will normalize the input type.
524 // FIXME(eddyb) avoid passing information like this, and instead add more
525 // `TyCtxt::at`-like APIs to be able to do e.g. `cx.at(span).layout_of(ty)`.
527 fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
528 let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
529 let tcx = self.tcx().at(span);
532 tcx.layout_of(self.param_env().and(ty))
533 .map_err(|err| self.handle_layout_err(err, span, ty)),
538 impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
540 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
541 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
544 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
549 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
550 type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
553 fn layout_tcx_at_span(&self) -> Span {
558 fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
563 impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
565 C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
567 fn ty_and_layout_for_variant(
568 this: TyAndLayout<'tcx>,
570 variant_index: VariantIdx,
571 ) -> TyAndLayout<'tcx> {
572 let layout = match this.variants {
573 Variants::Single { index }
574 // If all variants but one are uninhabited, the variant layout is the enum layout.
575 if index == variant_index &&
576 // Don't confuse variants of uninhabited enums with the enum itself.
577 // For more details see https://github.com/rust-lang/rust/issues/69763.
578 this.fields != FieldsShape::Primitive =>
583 Variants::Single { index } => {
585 let param_env = cx.param_env();
587 // Deny calling for_variant more than once for non-Single enums.
588 if let Ok(original_layout) = tcx.layout_of(param_env.and(this.ty)) {
589 assert_eq!(original_layout.variants, Variants::Single { index });
592 let fields = match this.ty.kind() {
593 ty::Adt(def, _) if def.variants().is_empty() =>
594 bug!("for_variant called on zero-variant enum"),
595 ty::Adt(def, _) => def.variant(variant_index).fields.len(),
598 tcx.intern_layout(LayoutS {
599 variants: Variants::Single { index: variant_index },
600 fields: match NonZeroUsize::new(fields) {
601 Some(fields) => FieldsShape::Union(fields),
602 None => FieldsShape::Arbitrary { offsets: vec![], memory_index: vec![] },
604 abi: Abi::Uninhabited,
606 align: tcx.data_layout.i8_align,
611 Variants::Multiple { ref variants, .. } => cx.tcx().intern_layout(variants[variant_index].clone()),
614 assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
616 TyAndLayout { ty: this.ty, layout }
619 fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
620 enum TyMaybeWithLayout<'tcx> {
622 TyAndLayout(TyAndLayout<'tcx>),
625 fn field_ty_or_layout<'tcx>(
626 this: TyAndLayout<'tcx>,
627 cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
629 ) -> TyMaybeWithLayout<'tcx> {
631 let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
633 layout: tcx.intern_layout(LayoutS::scalar(cx, tag)),
634 ty: tag.primitive().to_ty(tcx),
638 match *this.ty.kind() {
647 | ty::GeneratorWitness(..)
648 | ty::GeneratorWitnessMIR(..)
650 | ty::Dynamic(_, _, ty::Dyn) => {
651 bug!("TyAndLayout::field({:?}): not applicable", this)
654 // Potentially-fat pointers.
655 ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
656 assert!(i < this.fields.count());
658 // Reuse the fat `*T` type as its own thin pointer data field.
659 // This provides information about, e.g., DST struct pointees
660 // (which may have no non-DST form), and will work as long
661 // as the `Abi` or `FieldsShape` is checked by users.
663 let nil = tcx.mk_unit();
664 let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
667 tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
670 // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
671 // the `Result` should always work because the type is
672 // always either `*mut ()` or `&'static mut ()`.
673 return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
675 ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
679 let mk_dyn_vtable = || {
680 tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3))
681 /* FIXME: use actual fn pointers
682 Warning: naively computing the number of entries in the
683 vtable by counting the methods on the trait + methods on
684 all parent traits does not work, because some methods can
685 be not object safe and thus excluded from the vtable.
686 Increase this counter if you tried to implement this but
687 failed to do it without duplicating a lot of code from
688 other places in the compiler: 2
690 tcx.mk_array(tcx.types.usize, 3),
691 tcx.mk_array(Option<fn()>),
696 let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
697 let metadata = tcx.normalize_erasing_regions(
699 tcx.mk_projection(metadata_def_id, [pointee]),
702 // Map `Metadata = DynMetadata<dyn Trait>` back to a vtable, since it
703 // offers better information than `std::ptr::metadata::VTable`,
704 // and we rely on this layout information to trigger a panic in
705 // `std::mem::uninitialized::<&dyn Trait>()`, for example.
706 if let ty::Adt(def, substs) = metadata.kind()
707 && Some(def.did()) == tcx.lang_items().dyn_metadata()
708 && substs.type_at(0).is_trait()
715 match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
716 ty::Slice(_) | ty::Str => tcx.types.usize,
717 ty::Dynamic(_, _, ty::Dyn) => mk_dyn_vtable(),
718 _ => bug!("TyAndLayout::field({:?}): not applicable", this),
722 TyMaybeWithLayout::Ty(metadata)
725 // Arrays and slices.
726 ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
727 ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
729 // Tuples, generators and closures.
730 ty::Closure(_, ref substs) => field_ty_or_layout(
731 TyAndLayout { ty: substs.as_closure().tupled_upvars_ty(), ..this },
736 ty::Generator(def_id, ref substs, _) => match this.variants {
737 Variants::Single { index } => TyMaybeWithLayout::Ty(
740 .state_tys(def_id, tcx)
741 .nth(index.as_usize())
746 Variants::Multiple { tag, tag_field, .. } => {
748 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
750 TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
754 ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
757 ty::Adt(def, substs) => {
758 match this.variants {
759 Variants::Single { index } => {
760 TyMaybeWithLayout::Ty(def.variant(index).fields[i].ty(tcx, substs))
763 // Discriminant field for enums (where applicable).
764 Variants::Multiple { tag, .. } => {
766 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
771 ty::Dynamic(_, _, ty::DynStar) => {
773 TyMaybeWithLayout::Ty(tcx.types.usize)
775 // FIXME(dyn-star) same FIXME as above applies here too
776 TyMaybeWithLayout::Ty(
778 tcx.lifetimes.re_static,
779 tcx.mk_array(tcx.types.usize, 3),
783 bug!("no field {i} on dyn*")
789 | ty::Placeholder(..)
792 | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
796 match field_ty_or_layout(this, cx, i) {
797 TyMaybeWithLayout::Ty(field_ty) => {
798 cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
800 "failed to get layout for `{}`: {},\n\
801 despite it being a field (#{}) of an existing layout: {:#?}",
809 TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
813 fn ty_and_layout_pointee_info_at(
814 this: TyAndLayout<'tcx>,
817 ) -> Option<PointeeInfo> {
819 let param_env = cx.param_env();
822 match *this.ty.kind() {
823 ty::RawPtr(mt) if offset.bytes() == 0 => {
824 tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
826 align: layout.align.abi,
830 ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
831 tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| {
832 PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
835 ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
836 let kind = if tcx.sess.opts.optimize == OptLevel::No {
837 // Use conservative pointer kind if not optimizing. This saves us the
838 // Freeze/Unpin queries, and can save time in the codegen backend (noalias
839 // attributes in LLVM have compile-time cost even in unoptimized builds).
840 PointerKind::SharedMutable
843 hir::Mutability::Not => {
844 if ty.is_freeze(tcx, cx.param_env()) {
847 PointerKind::SharedMutable
850 hir::Mutability::Mut => {
851 // References to self-referential structures should not be considered
852 // noalias, as another pointer to the structure can be obtained, that
853 // is not based-on the original reference. We consider all !Unpin
854 // types to be potentially self-referential here.
855 if ty.is_unpin(tcx, cx.param_env()) {
856 PointerKind::UniqueBorrowed
858 PointerKind::UniqueBorrowedPinned
864 tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
866 align: layout.align.abi,
872 let mut data_variant = match this.variants {
873 // Within the discriminant field, only the niche itself is
874 // always initialized, so we only check for a pointer at its
877 // If the niche is a pointer, it's either valid (according
878 // to its type), or null (which the niche field's scalar
879 // validity range encodes). This allows using
880 // `dereferenceable_or_null` for e.g., `Option<&T>`, and
881 // this will continue to work as long as we don't start
882 // using more niches than just null (e.g., the first page of
883 // the address space, or unaligned pointers).
885 tag_encoding: TagEncoding::Niche { untagged_variant, .. },
888 } if this.fields.offset(tag_field) == offset => {
889 Some(this.for_variant(cx, untagged_variant))
894 if let Some(variant) = data_variant {
895 // We're not interested in any unions.
896 if let FieldsShape::Union(_) = variant.fields {
901 let mut result = None;
903 if let Some(variant) = data_variant {
904 // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
905 // (requires passing in the expected address space from the caller)
906 let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
907 for i in 0..variant.fields.count() {
908 let field_start = variant.fields.offset(i);
909 if field_start <= offset {
910 let field = variant.field(cx, i);
911 result = field.to_result().ok().and_then(|field| {
912 if ptr_end <= field_start + field.size {
913 // We found the right field, look inside it.
915 field.pointee_info_at(cx, offset - field_start);
921 if result.is_some() {
928 // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
929 if let Some(ref mut pointee) = result {
930 if let ty::Adt(def, _) = this.ty.kind() {
931 if def.is_box() && offset.bytes() == 0 {
932 pointee.safe = Some(PointerKind::UniqueOwned);
942 "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
951 fn is_adt(this: TyAndLayout<'tcx>) -> bool {
952 matches!(this.ty.kind(), ty::Adt(..))
955 fn is_never(this: TyAndLayout<'tcx>) -> bool {
956 this.ty.kind() == &ty::Never
959 fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
960 matches!(this.ty.kind(), ty::Tuple(..))
963 fn is_unit(this: TyAndLayout<'tcx>) -> bool {
964 matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
968 /// Calculates whether a function's ABI can unwind or not.
970 /// This takes two primary parameters:
972 /// * `codegen_fn_attr_flags` - these are flags calculated as part of the
973 /// codegen attrs for a defined function. For function pointers this set of
974 /// flags is the empty set. This is only applicable for Rust-defined
975 /// functions, and generally isn't needed except for small optimizations where
976 /// we try to say a function which otherwise might look like it could unwind
977 /// doesn't actually unwind (such as for intrinsics and such).
979 /// * `abi` - this is the ABI that the function is defined with. This is the
980 /// primary factor for determining whether a function can unwind or not.
982 /// Note that in this case unwinding is not necessarily panicking in Rust. Rust
983 /// panics are implemented with unwinds on most platform (when
984 /// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
985 /// Notably unwinding is disallowed for more non-Rust ABIs unless it's
986 /// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
987 /// defined for each ABI individually, but it always corresponds to some form of
988 /// stack-based unwinding (the exact mechanism of which varies
989 /// platform-by-platform).
991 /// Rust functions are classified whether or not they can unwind based on the
992 /// active "panic strategy". In other words Rust functions are considered to
993 /// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
994 /// Note that Rust supports intermingling panic=abort and panic=unwind code, but
995 /// only if the final panic mode is panic=abort. In this scenario any code
996 /// previously compiled assuming that a function can unwind is still correct, it
997 /// just never happens to actually unwind at runtime.
999 /// This function's answer to whether or not a function can unwind is quite
1000 /// impactful throughout the compiler. This affects things like:
1002 /// * Calling a function which can't unwind means codegen simply ignores any
1003 /// associated unwinding cleanup.
1004 /// * Calling a function which can unwind from a function which can't unwind
1005 /// causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
1006 /// aborts the process.
1007 /// * This affects whether functions have the LLVM `nounwind` attribute, which
1008 /// affects various optimizations and codegen.
1010 /// FIXME: this is actually buggy with respect to Rust functions. Rust functions
1011 /// compiled with `-Cpanic=unwind` and referenced from another crate compiled
1012 /// with `-Cpanic=abort` will look like they can't unwind when in fact they
1013 /// might (from a foreign exception or similar).
1015 #[tracing::instrument(level = "debug", skip(tcx))]
1016 pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
1017 if let Some(did) = fn_def_id {
1018 // Special attribute for functions which can't unwind.
1019 if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
1023 // With `-C panic=abort`, all non-FFI functions are required to not unwind.
1025 // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
1026 // function defined in Rust is also required to abort.
1027 if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
1031 // With -Z panic-in-drop=abort, drop_in_place never unwinds.
1033 // This is not part of `codegen_fn_attrs` as it can differ between crates
1034 // and therefore cannot be computed in core.
1035 if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort {
1036 if Some(did) == tcx.lang_items().drop_in_place_fn() {
1042 // Otherwise if this isn't special then unwinding is generally determined by
1043 // the ABI of the itself. ABIs like `C` have variants which also
1044 // specifically allow unwinding (`C-unwind`), but not all platform-specific
1045 // ABIs have such an option. Otherwise the only other thing here is Rust
1046 // itself, and those ABIs are determined by the panic strategy configured
1047 // for this compilation.
1049 // Unfortunately at this time there's also another caveat. Rust [RFC
1050 // 2945][rfc] has been accepted and is in the process of being implemented
1051 // and stabilized. In this interim state we need to deal with historical
1052 // rustc behavior as well as plan for future rustc behavior.
1054 // Historically functions declared with `extern "C"` were marked at the
1055 // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
1056 // or not. This is UB for functions in `panic=unwind` mode that then
1057 // actually panic and unwind. Note that this behavior is true for both
1058 // externally declared functions as well as Rust-defined function.
1060 // To fix this UB rustc would like to change in the future to catch unwinds
1061 // from function calls that may unwind within a Rust-defined `extern "C"`
1062 // function and forcibly abort the process, thereby respecting the
1063 // `nounwind` attribute emitted for `extern "C"`. This behavior change isn't
1064 // ready to roll out, so determining whether or not the `C` family of ABIs
1065 // unwinds is conditional not only on their definition but also whether the
1066 // `#![feature(c_unwind)]` feature gate is active.
1068 // Note that this means that unlike historical compilers rustc now, by
1069 // default, unconditionally thinks that the `C` ABI may unwind. This will
1070 // prevent some optimization opportunities, however, so we try to scope this
1071 // change and only assume that `C` unwinds with `panic=unwind` (as opposed
1072 // to `panic=abort`).
1074 // Eventually the check against `c_unwind` here will ideally get removed and
1075 // this'll be a little cleaner as it'll be a straightforward check of the
1078 // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
1084 | Stdcall { unwind }
1085 | Fastcall { unwind }
1086 | Vectorcall { unwind }
1087 | Thiscall { unwind }
1090 | SysV64 { unwind } => {
1092 || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
1100 | AvrNonBlockingInterrupt
1101 | CCmseNonSecureCall
1105 | Unadjusted => false,
1106 Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
1110 /// Error produced by attempting to compute or adjust a `FnAbi`.
1111 #[derive(Copy, Clone, Debug, HashStable)]
1112 pub enum FnAbiError<'tcx> {
1113 /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
1114 Layout(LayoutError<'tcx>),
1116 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
1117 AdjustForForeignAbi(call::AdjustForForeignAbiError),
1120 impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
1121 fn from(err: LayoutError<'tcx>) -> Self {
1126 impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
1127 fn from(err: call::AdjustForForeignAbiError) -> Self {
1128 Self::AdjustForForeignAbi(err)
1132 impl<'tcx> fmt::Display for FnAbiError<'tcx> {
1133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1135 Self::Layout(err) => err.fmt(f),
1136 Self::AdjustForForeignAbi(err) => err.fmt(f),
1141 impl IntoDiagnostic<'_, !> for FnAbiError<'_> {
1142 fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
1143 handler.struct_fatal(self.to_string())
1147 // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
1148 // just for error handling.
1150 pub enum FnAbiRequest<'tcx> {
1151 OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1152 OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1155 /// Trait for contexts that want to be able to compute `FnAbi`s.
1156 /// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
1157 pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
1158 /// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
1159 /// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
1160 type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
1162 /// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
1163 /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
1165 /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
1166 /// but this hook allows e.g. codegen to return only `&FnAbi` from its
1167 /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
1168 /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
1169 fn handle_fn_abi_err(
1171 err: FnAbiError<'tcx>,
1173 fn_abi_request: FnAbiRequest<'tcx>,
1174 ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
1177 /// Blanket extension trait for contexts that can compute `FnAbi`s.
1178 pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
1179 /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
1181 /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
1182 /// instead, where the instance is an `InstanceDef::Virtual`.
1184 fn fn_abi_of_fn_ptr(
1186 sig: ty::PolyFnSig<'tcx>,
1187 extra_args: &'tcx ty::List<Ty<'tcx>>,
1188 ) -> Self::FnAbiOfResult {
1189 // FIXME(eddyb) get a better `span` here.
1190 let span = self.layout_tcx_at_span();
1191 let tcx = self.tcx().at(span);
1193 MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
1194 |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
1198 /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
1199 /// direct calls to an `fn`.
1201 /// NB: that includes virtual calls, which are represented by "direct calls"
1202 /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
1204 #[tracing::instrument(level = "debug", skip(self))]
1205 fn fn_abi_of_instance(
1207 instance: ty::Instance<'tcx>,
1208 extra_args: &'tcx ty::List<Ty<'tcx>>,
1209 ) -> Self::FnAbiOfResult {
1210 // FIXME(eddyb) get a better `span` here.
1211 let span = self.layout_tcx_at_span();
1212 let tcx = self.tcx().at(span);
1215 tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
1216 // HACK(eddyb) at least for definitions of/calls to `Instance`s,
1217 // we can get some kind of span even if one wasn't provided.
1218 // However, we don't do this early in order to avoid calling
1219 // `def_span` unconditionally (which may have a perf penalty).
1220 let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1221 self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
1227 impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}