1use std::ops::Bound;
2use std::{cmp, fmt};
3
4use rustc_abi::{
5 AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
6 PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
7 TyAbiInterface, VariantIdx, Variants,
8};
9use rustc_error_messages::DiagMessage;
10use rustc_errors::{
11 Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
12};
13use rustc_hir::LangItem;
14use rustc_hir::def_id::DefId;
15use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
16use rustc_session::config::OptLevel;
17use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
18use rustc_target::callconv::FnAbi;
19use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi};
20use tracing::debug;
21use {rustc_abi as abi, rustc_hir as hir};
22
23use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
24use crate::query::TyCtxtAt;
25use crate::ty::normalize_erasing_regions::NormalizationError;
26use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt};
27
28#[extension(pub trait IntegerExt)]
29impl abi::Integer {
30 #[inline]
31 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
32 use abi::Integer::{I8, I16, I32, I64, I128};
33 match (*self, signed) {
34 (I8, false) => tcx.types.u8,
35 (I16, false) => tcx.types.u16,
36 (I32, false) => tcx.types.u32,
37 (I64, false) => tcx.types.u64,
38 (I128, false) => tcx.types.u128,
39 (I8, true) => tcx.types.i8,
40 (I16, true) => tcx.types.i16,
41 (I32, true) => tcx.types.i32,
42 (I64, true) => tcx.types.i64,
43 (I128, true) => tcx.types.i128,
44 }
45 }
46
47 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> abi::Integer {
48 use abi::Integer::{I8, I16, I32, I64, I128};
49 match ity {
50 ty::IntTy::I8 => I8,
51 ty::IntTy::I16 => I16,
52 ty::IntTy::I32 => I32,
53 ty::IntTy::I64 => I64,
54 ty::IntTy::I128 => I128,
55 ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
56 }
57 }
58 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> abi::Integer {
59 use abi::Integer::{I8, I16, I32, I64, I128};
60 match ity {
61 ty::UintTy::U8 => I8,
62 ty::UintTy::U16 => I16,
63 ty::UintTy::U32 => I32,
64 ty::UintTy::U64 => I64,
65 ty::UintTy::U128 => I128,
66 ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
67 }
68 }
69
70 fn repr_discr<'tcx>(
75 tcx: TyCtxt<'tcx>,
76 ty: Ty<'tcx>,
77 repr: &ReprOptions,
78 min: i128,
79 max: i128,
80 ) -> (abi::Integer, bool) {
81 let unsigned_fit = abi::Integer::fit_unsigned(cmp::max(min as u128, max as u128));
86 let signed_fit = cmp::max(abi::Integer::fit_signed(min), abi::Integer::fit_signed(max));
87
88 if let Some(ity) = repr.int {
89 let discr = abi::Integer::from_attr(&tcx, ity);
90 let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
91 if discr < fit {
92 bug!(
93 "Integer::repr_discr: `#[repr]` hint too small for \
94 discriminant range of enum `{}`",
95 ty
96 )
97 }
98 return (discr, ity.is_signed());
99 }
100
101 let at_least = if repr.c() {
102 tcx.data_layout().c_enum_min_size
105 } else {
106 abi::Integer::I8
108 };
109
110 if unsigned_fit <= signed_fit {
112 (cmp::max(unsigned_fit, at_least), false)
113 } else {
114 (cmp::max(signed_fit, at_least), true)
115 }
116 }
117}
118
119#[extension(pub trait FloatExt)]
120impl abi::Float {
121 #[inline]
122 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
123 use abi::Float::*;
124 match *self {
125 F16 => tcx.types.f16,
126 F32 => tcx.types.f32,
127 F64 => tcx.types.f64,
128 F128 => tcx.types.f128,
129 }
130 }
131
132 fn from_float_ty(fty: ty::FloatTy) -> Self {
133 use abi::Float::*;
134 match fty {
135 ty::FloatTy::F16 => F16,
136 ty::FloatTy::F32 => F32,
137 ty::FloatTy::F64 => F64,
138 ty::FloatTy::F128 => F128,
139 }
140 }
141}
142
143#[extension(pub trait PrimitiveExt)]
144impl Primitive {
145 #[inline]
146 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
147 match *self {
148 Primitive::Int(i, signed) => i.to_ty(tcx, signed),
149 Primitive::Float(f) => f.to_ty(tcx),
150 Primitive::Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit),
152 }
153 }
154
155 #[inline]
158 fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
159 match *self {
160 Primitive::Int(i, signed) => i.to_ty(tcx, signed),
161 Primitive::Pointer(_) => {
163 let signed = false;
164 tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
165 }
166 Primitive::Float(_) => bug!("floats do not have an int type"),
167 }
168 }
169}
170
171pub const WIDE_PTR_ADDR: usize = 0;
176
177pub const WIDE_PTR_EXTRA: usize = 1;
182
183pub const MAX_SIMD_LANES: u64 = rustc_abi::MAX_SIMD_LANES;
184
185#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
188pub enum ValidityRequirement {
189 Inhabited,
190 Zero,
191 UninitMitigated0x01Fill,
194 Uninit,
196}
197
198impl ValidityRequirement {
199 pub fn from_intrinsic(intrinsic: Symbol) -> Option<Self> {
200 match intrinsic {
201 sym::assert_inhabited => Some(Self::Inhabited),
202 sym::assert_zero_valid => Some(Self::Zero),
203 sym::assert_mem_uninitialized_valid => Some(Self::UninitMitigated0x01Fill),
204 _ => None,
205 }
206 }
207}
208
209impl fmt::Display for ValidityRequirement {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 match self {
212 Self::Inhabited => f.write_str("is inhabited"),
213 Self::Zero => f.write_str("allows being left zeroed"),
214 Self::UninitMitigated0x01Fill => f.write_str("allows being filled with 0x01"),
215 Self::Uninit => f.write_str("allows being left uninitialized"),
216 }
217 }
218}
219
220#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
221pub enum LayoutError<'tcx> {
222 Unknown(Ty<'tcx>),
230 SizeOverflow(Ty<'tcx>),
232 TooGeneric(Ty<'tcx>),
237 NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
245 ReferencesError(ErrorGuaranteed),
247 Cycle(ErrorGuaranteed),
249}
250
251impl<'tcx> LayoutError<'tcx> {
252 pub fn diagnostic_message(&self) -> DiagMessage {
253 use LayoutError::*;
254
255 use crate::fluent_generated::*;
256 match self {
257 Unknown(_) => middle_layout_unknown,
258 SizeOverflow(_) => middle_layout_size_overflow,
259 TooGeneric(_) => middle_layout_too_generic,
260 NormalizationFailure(_, _) => middle_layout_normalization_failure,
261 Cycle(_) => middle_layout_cycle,
262 ReferencesError(_) => middle_layout_references_error,
263 }
264 }
265
266 pub fn into_diagnostic(self) -> crate::error::LayoutError<'tcx> {
267 use LayoutError::*;
268
269 use crate::error::LayoutError as E;
270 match self {
271 Unknown(ty) => E::Unknown { ty },
272 SizeOverflow(ty) => E::Overflow { ty },
273 TooGeneric(ty) => E::TooGeneric { ty },
274 NormalizationFailure(ty, e) => {
275 E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
276 }
277 Cycle(_) => E::Cycle,
278 ReferencesError(_) => E::ReferencesError,
279 }
280 }
281}
282
283impl<'tcx> fmt::Display for LayoutError<'tcx> {
286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287 match *self {
288 LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
289 LayoutError::TooGeneric(ty) => {
290 write!(f, "the type `{ty}` does not have a fixed layout")
291 }
292 LayoutError::SizeOverflow(ty) => {
293 write!(f, "values of the type `{ty}` are too big for the target architecture")
294 }
295 LayoutError::NormalizationFailure(t, e) => write!(
296 f,
297 "unable to determine layout for `{}` because `{}` cannot be normalized",
298 t,
299 e.get_type_for_failure()
300 ),
301 LayoutError::Cycle(_) => write!(f, "a cycle occurred during layout computation"),
302 LayoutError::ReferencesError(_) => write!(f, "the type has an unknown layout"),
303 }
304 }
305}
306
307impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
308 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
309 self.to_string().into_diag_arg(&mut None)
310 }
311}
312
313#[derive(Clone, Copy)]
314pub struct LayoutCx<'tcx> {
315 pub calc: abi::LayoutCalculator<TyCtxt<'tcx>>,
316 pub typing_env: ty::TypingEnv<'tcx>,
317}
318
319impl<'tcx> LayoutCx<'tcx> {
320 pub fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self {
321 Self { calc: abi::LayoutCalculator::new(tcx), typing_env }
322 }
323}
324
325#[derive(Copy, Clone, Debug)]
330pub enum SizeSkeleton<'tcx> {
331 Known(Size, Option<Align>),
334
335 Generic(ty::Const<'tcx>),
340
341 Pointer {
343 non_zero: bool,
345 tail: Ty<'tcx>,
349 },
350}
351
352impl<'tcx> SizeSkeleton<'tcx> {
353 pub fn compute(
354 ty: Ty<'tcx>,
355 tcx: TyCtxt<'tcx>,
356 typing_env: ty::TypingEnv<'tcx>,
357 ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> {
358 debug_assert!(!ty.has_non_region_infer());
359
360 let err = match tcx.layout_of(typing_env.as_query_input(ty)) {
362 Ok(layout) => {
363 if layout.is_sized() {
364 return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
365 } else {
366 return Err(tcx.arena.alloc(LayoutError::Unknown(ty)));
368 }
369 }
370 Err(err @ LayoutError::TooGeneric(_)) => err,
371 Err(
373 e @ LayoutError::Cycle(_)
374 | e @ LayoutError::Unknown(_)
375 | e @ LayoutError::SizeOverflow(_)
376 | e @ LayoutError::NormalizationFailure(..)
377 | e @ LayoutError::ReferencesError(_),
378 ) => return Err(e),
379 };
380
381 match *ty.kind() {
382 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
383 let non_zero = !ty.is_raw_ptr();
384
385 let tail = tcx.struct_tail_raw(
386 pointee,
387 |ty| match tcx.try_normalize_erasing_regions(typing_env, ty) {
388 Ok(ty) => ty,
389 Err(e) => Ty::new_error_with_message(
390 tcx,
391 DUMMY_SP,
392 format!(
393 "normalization failed for {} but no errors reported",
394 e.get_type_for_failure()
395 ),
396 ),
397 },
398 || {},
399 );
400
401 match tail.kind() {
402 ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
403 debug_assert!(tail.has_non_region_param());
404 Ok(SizeSkeleton::Pointer {
405 non_zero,
406 tail: tcx.erase_and_anonymize_regions(tail),
407 })
408 }
409 ty::Error(guar) => {
410 return Err(tcx.arena.alloc(LayoutError::ReferencesError(*guar)));
412 }
413 _ => bug!(
414 "SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \
415 tail `{tail}` is not a type parameter or a projection",
416 ),
417 }
418 }
419 ty::Array(inner, len) if tcx.features().transmute_generic_consts() => {
420 let len_eval = len.try_to_target_usize(tcx);
421 if len_eval == Some(0) {
422 return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));
423 }
424
425 match SizeSkeleton::compute(inner, tcx, typing_env)? {
426 SizeSkeleton::Known(s, a) => {
429 if let Some(c) = len_eval {
430 let size = s
431 .bytes()
432 .checked_mul(c)
433 .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
434 return Ok(SizeSkeleton::Known(Size::from_bytes(size), a));
436 }
437 Err(err)
438 }
439 SizeSkeleton::Pointer { .. } | SizeSkeleton::Generic(_) => Err(err),
440 }
441 }
442
443 ty::Adt(def, args) => {
444 if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
446 return Err(err);
447 }
448
449 let zero_or_ptr_variant = |i| {
451 let i = VariantIdx::from_usize(i);
452 let fields =
453 def.variant(i).fields.iter().map(|field| {
454 SizeSkeleton::compute(field.ty(tcx, args), tcx, typing_env)
455 });
456 let mut ptr = None;
457 for field in fields {
458 let field = field?;
459 match field {
460 SizeSkeleton::Known(size, align) => {
461 let is_1zst = size.bytes() == 0
462 && align.is_some_and(|align| align.bytes() == 1);
463 if !is_1zst {
464 return Err(err);
465 }
466 }
467 SizeSkeleton::Pointer { .. } => {
468 if ptr.is_some() {
469 return Err(err);
470 }
471 ptr = Some(field);
472 }
473 SizeSkeleton::Generic(_) => {
474 return Err(err);
475 }
476 }
477 }
478 Ok(ptr)
479 };
480
481 let v0 = zero_or_ptr_variant(0)?;
482 if def.variants().len() == 1 {
484 if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
485 return Ok(SizeSkeleton::Pointer {
486 non_zero: non_zero
487 || match tcx.layout_scalar_valid_range(def.did()) {
488 (Bound::Included(start), Bound::Unbounded) => start > 0,
489 (Bound::Included(start), Bound::Included(end)) => {
490 0 < start && start < end
491 }
492 _ => false,
493 },
494 tail,
495 });
496 } else {
497 return Err(err);
498 }
499 }
500
501 let v1 = zero_or_ptr_variant(1)?;
502 match (v0, v1) {
504 (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
505 | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
506 Ok(SizeSkeleton::Pointer { non_zero: false, tail })
507 }
508 _ => Err(err),
509 }
510 }
511
512 ty::Alias(..) => {
513 let normalized = tcx.normalize_erasing_regions(typing_env, ty);
514 if ty == normalized {
515 Err(err)
516 } else {
517 SizeSkeleton::compute(normalized, tcx, typing_env)
518 }
519 }
520
521 ty::Pat(base, _) => SizeSkeleton::compute(base, tcx, typing_env),
523
524 _ => Err(err),
525 }
526 }
527
528 pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
529 match (self, other) {
530 (SizeSkeleton::Known(a, _), SizeSkeleton::Known(b, _)) => a == b,
531 (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
532 a == b
533 }
534 (SizeSkeleton::Generic(a), SizeSkeleton::Generic(b)) => a == b,
537 _ => false,
538 }
539 }
540}
541
542pub trait HasTyCtxt<'tcx>: HasDataLayout {
543 fn tcx(&self) -> TyCtxt<'tcx>;
544}
545
546pub trait HasTypingEnv<'tcx> {
547 fn typing_env(&self) -> ty::TypingEnv<'tcx>;
548
549 fn param_env(&self) -> ty::ParamEnv<'tcx> {
552 self.typing_env().param_env
553 }
554}
555
556impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
557 #[inline]
558 fn data_layout(&self) -> &TargetDataLayout {
559 &self.data_layout
560 }
561}
562
563impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
564 fn target_spec(&self) -> &Target {
565 &self.sess.target
566 }
567}
568
569impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
570 fn x86_abi_opt(&self) -> X86Abi {
571 X86Abi {
572 regparm: self.sess.opts.unstable_opts.regparm,
573 reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return,
574 }
575 }
576}
577
578impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
579 #[inline]
580 fn tcx(&self) -> TyCtxt<'tcx> {
581 *self
582 }
583}
584
585impl<'tcx> HasDataLayout for TyCtxtAt<'tcx> {
586 #[inline]
587 fn data_layout(&self) -> &TargetDataLayout {
588 &self.data_layout
589 }
590}
591
592impl<'tcx> HasTargetSpec for TyCtxtAt<'tcx> {
593 fn target_spec(&self) -> &Target {
594 &self.sess.target
595 }
596}
597
598impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
599 #[inline]
600 fn tcx(&self) -> TyCtxt<'tcx> {
601 **self
602 }
603}
604
605impl<'tcx> HasTypingEnv<'tcx> for LayoutCx<'tcx> {
606 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
607 self.typing_env
608 }
609}
610
611impl<'tcx> HasDataLayout for LayoutCx<'tcx> {
612 fn data_layout(&self) -> &TargetDataLayout {
613 self.calc.cx.data_layout()
614 }
615}
616
617impl<'tcx> HasTargetSpec for LayoutCx<'tcx> {
618 fn target_spec(&self) -> &Target {
619 self.calc.cx.target_spec()
620 }
621}
622
623impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> {
624 fn x86_abi_opt(&self) -> X86Abi {
625 self.calc.cx.x86_abi_opt()
626 }
627}
628
629impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
630 fn tcx(&self) -> TyCtxt<'tcx> {
631 self.calc.cx
632 }
633}
634
635pub trait MaybeResult<T> {
636 type Error;
637
638 fn from(x: Result<T, Self::Error>) -> Self;
639 fn to_result(self) -> Result<T, Self::Error>;
640}
641
642impl<T> MaybeResult<T> for T {
643 type Error = !;
644
645 fn from(Ok(x): Result<T, Self::Error>) -> Self {
646 x
647 }
648 fn to_result(self) -> Result<T, Self::Error> {
649 Ok(self)
650 }
651}
652
653impl<T, E> MaybeResult<T> for Result<T, E> {
654 type Error = E;
655
656 fn from(x: Result<T, Self::Error>) -> Self {
657 x
658 }
659 fn to_result(self) -> Result<T, Self::Error> {
660 self
661 }
662}
663
664pub type TyAndLayout<'tcx> = rustc_abi::TyAndLayout<'tcx, Ty<'tcx>>;
665
666pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> {
669 type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>> = TyAndLayout<'tcx>;
672
673 #[inline]
676 fn layout_tcx_at_span(&self) -> Span {
677 DUMMY_SP
678 }
679
680 fn handle_layout_err(
688 &self,
689 err: LayoutError<'tcx>,
690 span: Span,
691 ty: Ty<'tcx>,
692 ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
693}
694
695pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
697 #[inline]
700 fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
701 self.spanned_layout_of(ty, DUMMY_SP)
702 }
703
704 #[inline]
709 fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
710 let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
711 let tcx = self.tcx().at(span);
712
713 MaybeResult::from(
714 tcx.layout_of(self.typing_env().as_query_input(ty))
715 .map_err(|err| self.handle_layout_err(*err, span, ty)),
716 )
717 }
718}
719
720impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
721
722impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
723 type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
724
725 #[inline]
726 fn handle_layout_err(
727 &self,
728 err: LayoutError<'tcx>,
729 _: Span,
730 _: Ty<'tcx>,
731 ) -> &'tcx LayoutError<'tcx> {
732 self.tcx().arena.alloc(err)
733 }
734}
735
736impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
737where
738 C: HasTyCtxt<'tcx> + HasTypingEnv<'tcx>,
739{
740 fn ty_and_layout_for_variant(
741 this: TyAndLayout<'tcx>,
742 cx: &C,
743 variant_index: VariantIdx,
744 ) -> TyAndLayout<'tcx> {
745 let layout = match this.variants {
746 Variants::Single { index } if index == variant_index => {
748 return this;
749 }
750
751 Variants::Single { .. } | Variants::Empty => {
752 let tcx = cx.tcx();
757 let typing_env = cx.typing_env();
758
759 if let Ok(original_layout) = tcx.layout_of(typing_env.as_query_input(this.ty)) {
761 assert_eq!(original_layout.variants, this.variants);
762 }
763
764 let fields = match this.ty.kind() {
765 ty::Adt(def, _) if def.variants().is_empty() => {
766 bug!("for_variant called on zero-variant enum {}", this.ty)
767 }
768 ty::Adt(def, _) => def.variant(variant_index).fields.len(),
769 _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
770 };
771 tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields))
772 }
773
774 Variants::Multiple { ref variants, .. } => {
775 cx.tcx().mk_layout(variants[variant_index].clone())
776 }
777 };
778
779 assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
780
781 TyAndLayout { ty: this.ty, layout }
782 }
783
784 fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
785 enum TyMaybeWithLayout<'tcx> {
786 Ty(Ty<'tcx>),
787 TyAndLayout(TyAndLayout<'tcx>),
788 }
789
790 fn field_ty_or_layout<'tcx>(
791 this: TyAndLayout<'tcx>,
792 cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>),
793 i: usize,
794 ) -> TyMaybeWithLayout<'tcx> {
795 let tcx = cx.tcx();
796 let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
797 TyAndLayout {
798 layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
799 ty: tag.primitive().to_ty(tcx),
800 }
801 };
802
803 match *this.ty.kind() {
804 ty::Bool
805 | ty::Char
806 | ty::Int(_)
807 | ty::Uint(_)
808 | ty::Float(_)
809 | ty::FnPtr(..)
810 | ty::Never
811 | ty::FnDef(..)
812 | ty::CoroutineWitness(..)
813 | ty::Foreign(..)
814 | ty::Pat(_, _)
815 | ty::Dynamic(_, _, ty::Dyn) => {
816 bug!("TyAndLayout::field({:?}): not applicable", this)
817 }
818
819 ty::UnsafeBinder(bound_ty) => {
820 let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
821 field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i)
822 }
823
824 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
826 assert!(i < this.fields.count());
827
828 if i == 0 {
833 let nil = tcx.types.unit;
834 let unit_ptr_ty = if this.ty.is_raw_ptr() {
835 Ty::new_mut_ptr(tcx, nil)
836 } else {
837 Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil)
838 };
839
840 let typing_env = ty::TypingEnv::fully_monomorphized();
844 return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
845 ty: this.ty,
846 ..tcx.layout_of(typing_env.as_query_input(unit_ptr_ty)).unwrap()
847 });
848 }
849
850 let mk_dyn_vtable = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
851 let min_count = ty::vtable_min_entries(
852 tcx,
853 principal.map(|principal| {
854 tcx.instantiate_bound_regions_with_erased(principal)
855 }),
856 );
857 Ty::new_imm_ref(
858 tcx,
859 tcx.lifetimes.re_static,
860 Ty::new_array(tcx, tcx.types.usize, min_count.try_into().unwrap()),
862 )
863 };
864
865 let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
866 && !pointee.references_error()
869 {
870 let metadata = tcx.normalize_erasing_regions(
871 cx.typing_env(),
872 Ty::new_projection(tcx, metadata_def_id, [pointee]),
873 );
874
875 if let ty::Adt(def, args) = metadata.kind()
880 && tcx.is_lang_item(def.did(), LangItem::DynMetadata)
881 && let ty::Dynamic(data, _, ty::Dyn) = args.type_at(0).kind()
882 {
883 mk_dyn_vtable(data.principal())
884 } else {
885 metadata
886 }
887 } else {
888 match tcx.struct_tail_for_codegen(pointee, cx.typing_env()).kind() {
889 ty::Slice(_) | ty::Str => tcx.types.usize,
890 ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()),
891 _ => bug!("TyAndLayout::field({:?}): not applicable", this),
892 }
893 };
894
895 TyMaybeWithLayout::Ty(metadata)
896 }
897
898 ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
900 ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
901
902 ty::Closure(_, args) => field_ty_or_layout(
904 TyAndLayout { ty: args.as_closure().tupled_upvars_ty(), ..this },
905 cx,
906 i,
907 ),
908
909 ty::CoroutineClosure(_, args) => field_ty_or_layout(
910 TyAndLayout { ty: args.as_coroutine_closure().tupled_upvars_ty(), ..this },
911 cx,
912 i,
913 ),
914
915 ty::Coroutine(def_id, args) => match this.variants {
916 Variants::Empty => unreachable!(),
917 Variants::Single { index } => TyMaybeWithLayout::Ty(
918 args.as_coroutine()
919 .state_tys(def_id, tcx)
920 .nth(index.as_usize())
921 .unwrap()
922 .nth(i)
923 .unwrap(),
924 ),
925 Variants::Multiple { tag, tag_field, .. } => {
926 if FieldIdx::from_usize(i) == tag_field {
927 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
928 }
929 TyMaybeWithLayout::Ty(args.as_coroutine().prefix_tys()[i])
930 }
931 },
932
933 ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
934
935 ty::Adt(def, args) => {
937 match this.variants {
938 Variants::Single { index } => {
939 let field = &def.variant(index).fields[FieldIdx::from_usize(i)];
940 TyMaybeWithLayout::Ty(field.ty(tcx, args))
941 }
942 Variants::Empty => panic!("there is no field in Variants::Empty types"),
943
944 Variants::Multiple { tag, .. } => {
946 assert_eq!(i, 0);
947 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
948 }
949 }
950 }
951
952 ty::Alias(..)
953 | ty::Bound(..)
954 | ty::Placeholder(..)
955 | ty::Param(_)
956 | ty::Infer(_)
957 | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
958 }
959 }
960
961 match field_ty_or_layout(this, cx, i) {
962 TyMaybeWithLayout::Ty(field_ty) => {
963 cx.tcx().layout_of(cx.typing_env().as_query_input(field_ty)).unwrap_or_else(|e| {
964 bug!(
965 "failed to get layout for `{field_ty}`: {e:?},\n\
966 despite it being a field (#{i}) of an existing layout: {this:#?}",
967 )
968 })
969 }
970 TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
971 }
972 }
973
974 fn ty_and_layout_pointee_info_at(
977 this: TyAndLayout<'tcx>,
978 cx: &C,
979 offset: Size,
980 ) -> Option<PointeeInfo> {
981 let tcx = cx.tcx();
982 let typing_env = cx.typing_env();
983
984 let pointee_info = match *this.ty.kind() {
985 ty::RawPtr(p_ty, _) if offset.bytes() == 0 => {
986 tcx.layout_of(typing_env.as_query_input(p_ty)).ok().map(|layout| PointeeInfo {
987 size: layout.size,
988 align: layout.align.abi,
989 safe: None,
990 })
991 }
992 ty::FnPtr(..) if offset.bytes() == 0 => {
993 tcx.layout_of(typing_env.as_query_input(this.ty)).ok().map(|layout| PointeeInfo {
994 size: layout.size,
995 align: layout.align.abi,
996 safe: None,
997 })
998 }
999 ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
1000 let optimize = tcx.sess.opts.optimize != OptLevel::No;
1004 let kind = match mt {
1005 hir::Mutability::Not => {
1006 PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) }
1007 }
1008 hir::Mutability::Mut => {
1009 PointerKind::MutableRef { unpin: optimize && ty.is_unpin(tcx, typing_env) }
1010 }
1011 };
1012
1013 tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo {
1014 size: layout.size,
1015 align: layout.align.abi,
1016 safe: Some(kind),
1017 })
1018 }
1019
1020 _ => {
1021 let mut data_variant = match &this.variants {
1022 Variants::Multiple {
1032 tag_encoding:
1033 TagEncoding::Niche { untagged_variant, niche_variants, niche_start },
1034 tag_field,
1035 variants,
1036 ..
1037 } if variants.len() == 2
1038 && this.fields.offset(tag_field.as_usize()) == offset =>
1039 {
1040 let tagged_variant = if *untagged_variant == VariantIdx::ZERO {
1041 VariantIdx::from_u32(1)
1042 } else {
1043 VariantIdx::from_u32(0)
1044 };
1045 assert_eq!(tagged_variant, *niche_variants.start());
1046 if *niche_start == 0 {
1047 Some(this.for_variant(cx, *untagged_variant))
1053 } else {
1054 None
1055 }
1056 }
1057 Variants::Multiple { .. } => None,
1058 _ => Some(this),
1059 };
1060
1061 if let Some(variant) = data_variant
1062 && let FieldsShape::Union(_) = variant.fields
1064 {
1065 data_variant = None;
1066 }
1067
1068 let mut result = None;
1069
1070 if let Some(variant) = data_variant {
1071 let ptr_end = offset + Primitive::Pointer(AddressSpace::ZERO).size(cx);
1074 for i in 0..variant.fields.count() {
1075 let field_start = variant.fields.offset(i);
1076 if field_start <= offset {
1077 let field = variant.field(cx, i);
1078 result = field.to_result().ok().and_then(|field| {
1079 if ptr_end <= field_start + field.size {
1080 let field_info =
1082 field.pointee_info_at(cx, offset - field_start);
1083 field_info
1084 } else {
1085 None
1086 }
1087 });
1088 if result.is_some() {
1089 break;
1090 }
1091 }
1092 }
1093 }
1094
1095 if let Some(ref mut pointee) = result {
1099 if offset.bytes() == 0
1100 && let Some(boxed_ty) = this.ty.boxed_ty()
1101 {
1102 debug_assert!(pointee.safe.is_none());
1103 let optimize = tcx.sess.opts.optimize != OptLevel::No;
1104 pointee.safe = Some(PointerKind::Box {
1105 unpin: optimize && boxed_ty.is_unpin(tcx, typing_env),
1106 global: this.ty.is_box_global(tcx),
1107 });
1108 }
1109 }
1110
1111 result
1112 }
1113 };
1114
1115 debug!(
1116 "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
1117 offset,
1118 this.ty.kind(),
1119 pointee_info
1120 );
1121
1122 pointee_info
1123 }
1124
1125 fn is_adt(this: TyAndLayout<'tcx>) -> bool {
1126 matches!(this.ty.kind(), ty::Adt(..))
1127 }
1128
1129 fn is_never(this: TyAndLayout<'tcx>) -> bool {
1130 matches!(this.ty.kind(), ty::Never)
1131 }
1132
1133 fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
1134 matches!(this.ty.kind(), ty::Tuple(..))
1135 }
1136
1137 fn is_unit(this: TyAndLayout<'tcx>) -> bool {
1138 matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
1139 }
1140
1141 fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
1142 matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
1143 }
1144}
1145
1146#[inline]
1187#[tracing::instrument(level = "debug", skip(tcx))]
1188pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) -> bool {
1189 if let Some(did) = fn_def_id {
1190 if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
1192 return false;
1193 }
1194
1195 if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
1200 return false;
1201 }
1202
1203 if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort
1208 && tcx.is_lang_item(did, LangItem::DropInPlace)
1209 {
1210 return false;
1211 }
1212 }
1213
1214 use ExternAbi::*;
1221 match abi {
1222 C { unwind }
1223 | System { unwind }
1224 | Cdecl { unwind }
1225 | Stdcall { unwind }
1226 | Fastcall { unwind }
1227 | Vectorcall { unwind }
1228 | Thiscall { unwind }
1229 | Aapcs { unwind }
1230 | Win64 { unwind }
1231 | SysV64 { unwind } => unwind,
1232 PtxKernel
1233 | Msp430Interrupt
1234 | X86Interrupt
1235 | GpuKernel
1236 | EfiApi
1237 | AvrInterrupt
1238 | AvrNonBlockingInterrupt
1239 | CmseNonSecureCall
1240 | CmseNonSecureEntry
1241 | Custom
1242 | RiscvInterruptM
1243 | RiscvInterruptS
1244 | RustInvalid
1245 | Unadjusted => false,
1246 Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
1247 }
1248}
1249
1250#[derive(Copy, Clone, Debug, HashStable)]
1252pub enum FnAbiError<'tcx> {
1253 Layout(LayoutError<'tcx>),
1255}
1256
1257impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> {
1258 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
1259 match self {
1260 Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level),
1261 }
1262 }
1263}
1264
1265#[derive(Debug)]
1268pub enum FnAbiRequest<'tcx> {
1269 OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1270 OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1271}
1272
1273pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
1276 type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>> = &'tcx FnAbi<'tcx, Ty<'tcx>>;
1279
1280 fn handle_fn_abi_err(
1288 &self,
1289 err: FnAbiError<'tcx>,
1290 span: Span,
1291 fn_abi_request: FnAbiRequest<'tcx>,
1292 ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
1293}
1294
1295pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
1297 #[inline]
1302 fn fn_abi_of_fn_ptr(
1303 &self,
1304 sig: ty::PolyFnSig<'tcx>,
1305 extra_args: &'tcx ty::List<Ty<'tcx>>,
1306 ) -> Self::FnAbiOfResult {
1307 let span = self.layout_tcx_at_span();
1309 let tcx = self.tcx().at(span);
1310
1311 MaybeResult::from(
1312 tcx.fn_abi_of_fn_ptr(self.typing_env().as_query_input((sig, extra_args))).map_err(
1313 |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
1314 ),
1315 )
1316 }
1317
1318 #[inline]
1324 #[tracing::instrument(level = "debug", skip(self))]
1325 fn fn_abi_of_instance(
1326 &self,
1327 instance: ty::Instance<'tcx>,
1328 extra_args: &'tcx ty::List<Ty<'tcx>>,
1329 ) -> Self::FnAbiOfResult {
1330 let span = self.layout_tcx_at_span();
1332 let tcx = self.tcx().at(span);
1333
1334 MaybeResult::from(
1335 tcx.fn_abi_of_instance(self.typing_env().as_query_input((instance, extra_args)))
1336 .map_err(|err| {
1337 let span =
1342 if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1343 self.handle_fn_abi_err(
1344 *err,
1345 span,
1346 FnAbiRequest::OfInstance { instance, extra_args },
1347 )
1348 }),
1349 )
1350 }
1351}
1352
1353impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
1354
1355impl<'tcx> TyCtxt<'tcx> {
1356 pub fn offset_of_subfield<I>(
1357 self,
1358 typing_env: ty::TypingEnv<'tcx>,
1359 mut layout: TyAndLayout<'tcx>,
1360 indices: I,
1361 ) -> Size
1362 where
1363 I: Iterator<Item = (VariantIdx, FieldIdx)>,
1364 {
1365 let cx = LayoutCx::new(self, typing_env);
1366 let mut offset = Size::ZERO;
1367
1368 for (variant, field) in indices {
1369 layout = layout.for_variant(&cx, variant);
1370 let index = field.index();
1371 offset += layout.fields.offset(index);
1372 layout = layout.field(&cx, index);
1373 if !layout.is_sized() {
1374 let tail = self.struct_tail_for_codegen(layout.ty, typing_env);
1376 if !matches!(tail.kind(), ty::Slice(..)) {
1377 bug!(
1378 "offset of not-statically-aligned field (type {:?}) cannot be computed statically",
1379 layout.ty
1380 );
1381 }
1382 }
1383 }
1384
1385 offset
1386 }
1387}