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