1use std::ops::Bound;
2use std::{cmp, fmt};
3
4use rustc_abi::{
5 AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
6 PointerKind, Primitive, ReprFlags, 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, 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::traits::ObligationCause;
26use crate::ty::normalize_erasing_regions::NormalizationError;
27use crate::ty::{self, CoroutineArgsExt, Ty, TyCtxt, TypeVisitableExt};
28
29#[extension(pub trait IntegerExt)]
30impl abi::Integer {
31 #[inline]
32 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
33 use abi::Integer::{I8, I16, I32, I64, I128};
34 match (*self, signed) {
35 (I8, false) => tcx.types.u8,
36 (I16, false) => tcx.types.u16,
37 (I32, false) => tcx.types.u32,
38 (I64, false) => tcx.types.u64,
39 (I128, false) => tcx.types.u128,
40 (I8, true) => tcx.types.i8,
41 (I16, true) => tcx.types.i16,
42 (I32, true) => tcx.types.i32,
43 (I64, true) => tcx.types.i64,
44 (I128, true) => tcx.types.i128,
45 }
46 }
47
48 fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> abi::Integer {
49 use abi::Integer::{I8, I16, I32, I64, I128};
50 match ity {
51 ty::IntTy::I8 => I8,
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(),
57 }
58 }
59 fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> abi::Integer {
60 use abi::Integer::{I8, I16, I32, I64, I128};
61 match ity {
62 ty::UintTy::U8 => I8,
63 ty::UintTy::U16 => I16,
64 ty::UintTy::U32 => I32,
65 ty::UintTy::U64 => I64,
66 ty::UintTy::U128 => I128,
67 ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
68 }
69 }
70
71 fn discr_range_of_repr<'tcx>(
79 tcx: TyCtxt<'tcx>,
80 ty: Ty<'tcx>,
81 repr: &ReprOptions,
82 min: i128,
83 max: i128,
84 ) -> (abi::Integer, bool) {
85 let unsigned_fit = abi::Integer::fit_unsigned(cmp::max(min as u128, max as u128));
90 let signed_fit = cmp::max(abi::Integer::fit_signed(min), abi::Integer::fit_signed(max));
91
92 if let Some(ity) = repr.int {
93 let discr = abi::Integer::from_attr(&tcx, ity);
94 let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
95 if discr < fit {
96 bug!(
97 "Integer::repr_discr: `#[repr]` hint too small for \
98 discriminant range of enum `{}`",
99 ty
100 )
101 }
102 return (discr, ity.is_signed());
103 }
104
105 let at_least = if repr.c() {
106 tcx.data_layout().c_enum_min_size
109 } else {
110 abi::Integer::I8
112 };
113
114 if unsigned_fit <= signed_fit {
117 (cmp::max(unsigned_fit, at_least), false)
118 } else {
119 (cmp::max(signed_fit, at_least), true)
120 }
121 }
122}
123
124#[extension(pub trait FloatExt)]
125impl abi::Float {
126 #[inline]
127 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
128 use abi::Float::*;
129 match *self {
130 F16 => tcx.types.f16,
131 F32 => tcx.types.f32,
132 F64 => tcx.types.f64,
133 F128 => tcx.types.f128,
134 }
135 }
136
137 fn from_float_ty(fty: ty::FloatTy) -> Self {
138 use abi::Float::*;
139 match fty {
140 ty::FloatTy::F16 => F16,
141 ty::FloatTy::F32 => F32,
142 ty::FloatTy::F64 => F64,
143 ty::FloatTy::F128 => F128,
144 }
145 }
146}
147
148#[extension(pub trait PrimitiveExt)]
149impl Primitive {
150 #[inline]
151 fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
152 match *self {
153 Primitive::Int(i, signed) => i.to_ty(tcx, signed),
154 Primitive::Float(f) => f.to_ty(tcx),
155 Primitive::Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit),
157 }
158 }
159
160 #[inline]
163 fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
164 match *self {
165 Primitive::Int(i, signed) => i.to_ty(tcx, signed),
166 Primitive::Pointer(_) => {
168 let signed = false;
169 tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
170 }
171 Primitive::Float(_) => bug!("floats do not have an int type"),
172 }
173 }
174}
175
176pub const WIDE_PTR_ADDR: usize = 0;
181
182pub const WIDE_PTR_EXTRA: usize = 1;
187
188pub const MAX_SIMD_LANES: u64 = rustc_abi::MAX_SIMD_LANES;
189
190#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
193pub enum ValidityRequirement {
194 Inhabited,
195 Zero,
196 UninitMitigated0x01Fill,
199 Uninit,
201}
202
203impl ValidityRequirement {
204 pub fn from_intrinsic(intrinsic: Symbol) -> Option<Self> {
205 match intrinsic {
206 sym::assert_inhabited => Some(Self::Inhabited),
207 sym::assert_zero_valid => Some(Self::Zero),
208 sym::assert_mem_uninitialized_valid => Some(Self::UninitMitigated0x01Fill),
209 _ => None,
210 }
211 }
212}
213
214impl fmt::Display for ValidityRequirement {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 match self {
217 Self::Inhabited => f.write_str("is inhabited"),
218 Self::Zero => f.write_str("allows being left zeroed"),
219 Self::UninitMitigated0x01Fill => f.write_str("allows being filled with 0x01"),
220 Self::Uninit => f.write_str("allows being left uninitialized"),
221 }
222 }
223}
224
225#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
226pub enum SimdLayoutError {
227 ZeroLength,
229 TooManyLanes(u64),
232}
233
234#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
235pub enum LayoutError<'tcx> {
236 Unknown(Ty<'tcx>),
244 SizeOverflow(Ty<'tcx>),
246 InvalidSimd { ty: Ty<'tcx>, kind: SimdLayoutError },
248 TooGeneric(Ty<'tcx>),
253 NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
261 ReferencesError(ErrorGuaranteed),
263 Cycle(ErrorGuaranteed),
265}
266
267impl<'tcx> LayoutError<'tcx> {
268 pub fn diagnostic_message(&self) -> DiagMessage {
269 use LayoutError::*;
270
271 use crate::fluent_generated::*;
272 match self {
273 Unknown(_) => middle_layout_unknown,
274 SizeOverflow(_) => middle_layout_size_overflow,
275 InvalidSimd { kind: SimdLayoutError::TooManyLanes(_), .. } => {
276 middle_layout_simd_too_many
277 }
278 InvalidSimd { kind: SimdLayoutError::ZeroLength, .. } => middle_layout_simd_zero_length,
279 TooGeneric(_) => middle_layout_too_generic,
280 NormalizationFailure(_, _) => middle_layout_normalization_failure,
281 Cycle(_) => middle_layout_cycle,
282 ReferencesError(_) => middle_layout_references_error,
283 }
284 }
285
286 pub fn into_diagnostic(self) -> crate::error::LayoutError<'tcx> {
287 use LayoutError::*;
288
289 use crate::error::LayoutError as E;
290 match self {
291 Unknown(ty) => E::Unknown { ty },
292 SizeOverflow(ty) => E::Overflow { ty },
293 InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
294 E::SimdTooManyLanes { ty, max_lanes }
295 }
296 InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => E::SimdZeroLength { ty },
297 TooGeneric(ty) => E::TooGeneric { ty },
298 NormalizationFailure(ty, e) => {
299 E::NormalizationFailure { ty, failure_ty: e.get_type_for_failure() }
300 }
301 Cycle(_) => E::Cycle,
302 ReferencesError(_) => E::ReferencesError,
303 }
304 }
305}
306
307impl<'tcx> fmt::Display for LayoutError<'tcx> {
310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311 match *self {
312 LayoutError::Unknown(ty) => write!(f, "the type `{ty}` has an unknown layout"),
313 LayoutError::TooGeneric(ty) => {
314 write!(f, "the type `{ty}` does not have a fixed layout")
315 }
316 LayoutError::SizeOverflow(ty) => {
317 write!(f, "values of the type `{ty}` are too big for the target architecture")
318 }
319 LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) } => {
320 write!(f, "the SIMD type `{ty}` has more elements than the limit {max_lanes}")
321 }
322 LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength } => {
323 write!(f, "the SIMD type `{ty}` has zero elements")
324 }
325 LayoutError::NormalizationFailure(t, e) => write!(
326 f,
327 "unable to determine layout for `{}` because `{}` cannot be normalized",
328 t,
329 e.get_type_for_failure()
330 ),
331 LayoutError::Cycle(_) => write!(f, "a cycle occurred during layout computation"),
332 LayoutError::ReferencesError(_) => write!(f, "the type has an unknown layout"),
333 }
334 }
335}
336
337impl<'tcx> IntoDiagArg for LayoutError<'tcx> {
338 fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
339 self.to_string().into_diag_arg(&mut None)
340 }
341}
342
343#[derive(Clone, Copy)]
344pub struct LayoutCx<'tcx> {
345 pub calc: abi::LayoutCalculator<TyCtxt<'tcx>>,
346 pub typing_env: ty::TypingEnv<'tcx>,
347}
348
349impl<'tcx> LayoutCx<'tcx> {
350 pub fn new(tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Self {
351 Self { calc: abi::LayoutCalculator::new(tcx), typing_env }
352 }
353}
354
355#[derive(Copy, Clone, Debug)]
360pub enum SizeSkeleton<'tcx> {
361 Known(Size, Option<Align>),
364
365 Generic(ty::Const<'tcx>),
370
371 Pointer {
373 non_zero: bool,
375 tail: Ty<'tcx>,
379 },
380}
381
382impl<'tcx> SizeSkeleton<'tcx> {
383 pub fn compute(
384 ty: Ty<'tcx>,
385 tcx: TyCtxt<'tcx>,
386 typing_env: ty::TypingEnv<'tcx>,
387 ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> {
388 debug_assert!(!ty.has_non_region_infer());
389
390 let err = match tcx.layout_of(typing_env.as_query_input(ty)) {
392 Ok(layout) => {
393 if layout.is_sized() {
394 return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
395 } else {
396 return Err(tcx.arena.alloc(LayoutError::Unknown(ty)));
398 }
399 }
400 Err(err @ LayoutError::TooGeneric(_)) => err,
401 Err(
403 e @ LayoutError::Cycle(_)
404 | e @ LayoutError::Unknown(_)
405 | e @ LayoutError::SizeOverflow(_)
406 | e @ LayoutError::InvalidSimd { .. }
407 | e @ LayoutError::NormalizationFailure(..)
408 | e @ LayoutError::ReferencesError(_),
409 ) => return Err(e),
410 };
411
412 match *ty.kind() {
413 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
414 let non_zero = !ty.is_raw_ptr();
415
416 let tail = tcx.struct_tail_raw(
417 pointee,
418 &ObligationCause::dummy(),
419 |ty| match tcx.try_normalize_erasing_regions(typing_env, ty) {
420 Ok(ty) => ty,
421 Err(e) => Ty::new_error_with_message(
422 tcx,
423 DUMMY_SP,
424 format!(
425 "normalization failed for {} but no errors reported",
426 e.get_type_for_failure()
427 ),
428 ),
429 },
430 || {},
431 );
432
433 match tail.kind() {
434 ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
435 debug_assert!(tail.has_non_region_param());
436 Ok(SizeSkeleton::Pointer {
437 non_zero,
438 tail: tcx.erase_and_anonymize_regions(tail),
439 })
440 }
441 ty::Error(guar) => {
442 return Err(tcx.arena.alloc(LayoutError::ReferencesError(*guar)));
444 }
445 _ => bug!(
446 "SizeSkeleton::compute({ty}): layout errored ({err:?}), yet \
447 tail `{tail}` is not a type parameter or a projection",
448 ),
449 }
450 }
451 ty::Array(inner, len) if tcx.features().transmute_generic_consts() => {
452 let len_eval = len.try_to_target_usize(tcx);
453 if len_eval == Some(0) {
454 return Ok(SizeSkeleton::Known(Size::from_bytes(0), None));
455 }
456
457 match SizeSkeleton::compute(inner, tcx, typing_env)? {
458 SizeSkeleton::Known(s, a) => {
461 if let Some(c) = len_eval {
462 let size = s
463 .bytes()
464 .checked_mul(c)
465 .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
466 return Ok(SizeSkeleton::Known(Size::from_bytes(size), a));
468 }
469 Err(err)
470 }
471 SizeSkeleton::Pointer { .. } | SizeSkeleton::Generic(_) => Err(err),
472 }
473 }
474
475 ty::Adt(def, args) => {
476 if def.is_union() || def.variants().is_empty() || def.variants().len() > 2 {
478 return Err(err);
479 }
480
481 let zero_or_ptr_variant = |i| {
483 let i = VariantIdx::from_usize(i);
484 let fields =
485 def.variant(i).fields.iter().map(|field| {
486 SizeSkeleton::compute(field.ty(tcx, args), tcx, typing_env)
487 });
488 let mut ptr = None;
489 for field in fields {
490 let field = field?;
491 match field {
492 SizeSkeleton::Known(size, align) => {
493 let is_1zst = size.bytes() == 0
494 && align.is_some_and(|align| align.bytes() == 1);
495 if !is_1zst {
496 return Err(err);
497 }
498 }
499 SizeSkeleton::Pointer { .. } => {
500 if ptr.is_some() {
501 return Err(err);
502 }
503 ptr = Some(field);
504 }
505 SizeSkeleton::Generic(_) => {
506 return Err(err);
507 }
508 }
509 }
510 Ok(ptr)
511 };
512
513 let v0 = zero_or_ptr_variant(0)?;
514 if def.variants().len() == 1 {
516 if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
517 return Ok(SizeSkeleton::Pointer {
518 non_zero: non_zero
519 || match tcx.layout_scalar_valid_range(def.did()) {
520 (Bound::Included(start), Bound::Unbounded) => start > 0,
521 (Bound::Included(start), Bound::Included(end)) => {
522 0 < start && start < end
523 }
524 _ => false,
525 },
526 tail,
527 });
528 } else {
529 return Err(err);
530 }
531 }
532
533 let v1 = zero_or_ptr_variant(1)?;
534 match (v0, v1) {
536 (Some(SizeSkeleton::Pointer { non_zero: true, tail }), None)
537 | (None, Some(SizeSkeleton::Pointer { non_zero: true, tail })) => {
538 Ok(SizeSkeleton::Pointer { non_zero: false, tail })
539 }
540 _ => Err(err),
541 }
542 }
543
544 ty::Alias(..) => {
545 let normalized = tcx.normalize_erasing_regions(typing_env, ty);
546 if ty == normalized {
547 Err(err)
548 } else {
549 SizeSkeleton::compute(normalized, tcx, typing_env)
550 }
551 }
552
553 ty::Pat(base, _) => SizeSkeleton::compute(base, tcx, typing_env),
555
556 _ => Err(err),
557 }
558 }
559
560 pub fn same_size(self, other: SizeSkeleton<'tcx>) -> bool {
561 match (self, other) {
562 (SizeSkeleton::Known(a, _), SizeSkeleton::Known(b, _)) => a == b,
563 (SizeSkeleton::Pointer { tail: a, .. }, SizeSkeleton::Pointer { tail: b, .. }) => {
564 a == b
565 }
566 (SizeSkeleton::Generic(a), SizeSkeleton::Generic(b)) => a == b,
569 _ => false,
570 }
571 }
572}
573
574pub trait HasTyCtxt<'tcx>: HasDataLayout {
575 fn tcx(&self) -> TyCtxt<'tcx>;
576}
577
578pub trait HasTypingEnv<'tcx> {
579 fn typing_env(&self) -> ty::TypingEnv<'tcx>;
580
581 fn param_env(&self) -> ty::ParamEnv<'tcx> {
584 self.typing_env().param_env
585 }
586}
587
588impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
589 #[inline]
590 fn data_layout(&self) -> &TargetDataLayout {
591 &self.data_layout
592 }
593}
594
595impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
596 fn target_spec(&self) -> &Target {
597 &self.sess.target
598 }
599}
600
601impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
602 fn x86_abi_opt(&self) -> X86Abi {
603 X86Abi {
604 regparm: self.sess.opts.unstable_opts.regparm,
605 reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return,
606 }
607 }
608}
609
610impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
611 #[inline]
612 fn tcx(&self) -> TyCtxt<'tcx> {
613 *self
614 }
615}
616
617impl<'tcx> HasDataLayout for TyCtxtAt<'tcx> {
618 #[inline]
619 fn data_layout(&self) -> &TargetDataLayout {
620 &self.data_layout
621 }
622}
623
624impl<'tcx> HasTargetSpec for TyCtxtAt<'tcx> {
625 fn target_spec(&self) -> &Target {
626 &self.sess.target
627 }
628}
629
630impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
631 #[inline]
632 fn tcx(&self) -> TyCtxt<'tcx> {
633 **self
634 }
635}
636
637impl<'tcx> HasTypingEnv<'tcx> for LayoutCx<'tcx> {
638 fn typing_env(&self) -> ty::TypingEnv<'tcx> {
639 self.typing_env
640 }
641}
642
643impl<'tcx> HasDataLayout for LayoutCx<'tcx> {
644 fn data_layout(&self) -> &TargetDataLayout {
645 self.calc.cx.data_layout()
646 }
647}
648
649impl<'tcx> HasTargetSpec for LayoutCx<'tcx> {
650 fn target_spec(&self) -> &Target {
651 self.calc.cx.target_spec()
652 }
653}
654
655impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> {
656 fn x86_abi_opt(&self) -> X86Abi {
657 self.calc.cx.x86_abi_opt()
658 }
659}
660
661impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
662 fn tcx(&self) -> TyCtxt<'tcx> {
663 self.calc.cx
664 }
665}
666
667pub trait MaybeResult<T> {
668 type Error;
669
670 fn from(x: Result<T, Self::Error>) -> Self;
671 fn to_result(self) -> Result<T, Self::Error>;
672}
673
674impl<T> MaybeResult<T> for T {
675 type Error = !;
676
677 fn from(Ok(x): Result<T, Self::Error>) -> Self {
678 x
679 }
680 fn to_result(self) -> Result<T, Self::Error> {
681 Ok(self)
682 }
683}
684
685impl<T, E> MaybeResult<T> for Result<T, E> {
686 type Error = E;
687
688 fn from(x: Result<T, Self::Error>) -> Self {
689 x
690 }
691 fn to_result(self) -> Result<T, Self::Error> {
692 self
693 }
694}
695
696pub type TyAndLayout<'tcx> = rustc_abi::TyAndLayout<'tcx, Ty<'tcx>>;
697
698pub trait LayoutOfHelpers<'tcx>: HasDataLayout + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> {
701 type LayoutOfResult: MaybeResult<TyAndLayout<'tcx>> = TyAndLayout<'tcx>;
704
705 #[inline]
708 fn layout_tcx_at_span(&self) -> Span {
709 DUMMY_SP
710 }
711
712 fn handle_layout_err(
720 &self,
721 err: LayoutError<'tcx>,
722 span: Span,
723 ty: Ty<'tcx>,
724 ) -> <Self::LayoutOfResult as MaybeResult<TyAndLayout<'tcx>>>::Error;
725}
726
727pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
729 #[inline]
732 fn layout_of(&self, ty: Ty<'tcx>) -> Self::LayoutOfResult {
733 self.spanned_layout_of(ty, DUMMY_SP)
734 }
735
736 #[inline]
741 fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
742 let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
743 let tcx = self.tcx().at(span);
744
745 MaybeResult::from(
746 tcx.layout_of(self.typing_env().as_query_input(ty))
747 .map_err(|err| self.handle_layout_err(*err, span, ty)),
748 )
749 }
750}
751
752impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
753
754impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx> {
755 type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
756
757 #[inline]
758 fn handle_layout_err(
759 &self,
760 err: LayoutError<'tcx>,
761 _: Span,
762 _: Ty<'tcx>,
763 ) -> &'tcx LayoutError<'tcx> {
764 self.tcx().arena.alloc(err)
765 }
766}
767
768impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
769where
770 C: HasTyCtxt<'tcx> + HasTypingEnv<'tcx>,
771{
772 fn ty_and_layout_for_variant(
773 this: TyAndLayout<'tcx>,
774 cx: &C,
775 variant_index: VariantIdx,
776 ) -> TyAndLayout<'tcx> {
777 let layout = match this.variants {
778 Variants::Single { index } if index == variant_index => {
780 return this;
781 }
782
783 Variants::Single { .. } | Variants::Empty => {
784 let tcx = cx.tcx();
789 let typing_env = cx.typing_env();
790
791 if let Ok(original_layout) = tcx.layout_of(typing_env.as_query_input(this.ty)) {
793 assert_eq!(original_layout.variants, this.variants);
794 }
795
796 let fields = match this.ty.kind() {
797 ty::Adt(def, _) if def.variants().is_empty() => {
798 bug!("for_variant called on zero-variant enum {}", this.ty)
799 }
800 ty::Adt(def, _) => def.variant(variant_index).fields.len(),
801 _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
802 };
803 tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields))
804 }
805
806 Variants::Multiple { ref variants, .. } => {
807 cx.tcx().mk_layout(variants[variant_index].clone())
808 }
809 };
810
811 assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
812
813 TyAndLayout { ty: this.ty, layout }
814 }
815
816 fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
817 enum TyMaybeWithLayout<'tcx> {
818 Ty(Ty<'tcx>),
819 TyAndLayout(TyAndLayout<'tcx>),
820 }
821
822 fn field_ty_or_layout<'tcx>(
823 this: TyAndLayout<'tcx>,
824 cx: &(impl HasTyCtxt<'tcx> + HasTypingEnv<'tcx>),
825 i: usize,
826 ) -> TyMaybeWithLayout<'tcx> {
827 let tcx = cx.tcx();
828 let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
829 TyAndLayout {
830 layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
831 ty: tag.primitive().to_ty(tcx),
832 }
833 };
834
835 match *this.ty.kind() {
836 ty::Bool
837 | ty::Char
838 | ty::Int(_)
839 | ty::Uint(_)
840 | ty::Float(_)
841 | ty::FnPtr(..)
842 | ty::Never
843 | ty::FnDef(..)
844 | ty::CoroutineWitness(..)
845 | ty::Foreign(..)
846 | ty::Dynamic(_, _) => {
847 bug!("TyAndLayout::field({:?}): not applicable", this)
848 }
849
850 ty::Pat(base, _) => {
851 assert_eq!(i, 0);
852 TyMaybeWithLayout::Ty(base)
853 }
854
855 ty::UnsafeBinder(bound_ty) => {
856 let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
857 field_ty_or_layout(TyAndLayout { ty, ..this }, cx, i)
858 }
859
860 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
862 assert!(i < this.fields.count());
863
864 if i == 0 {
869 let nil = tcx.types.unit;
870 let unit_ptr_ty = if this.ty.is_raw_ptr() {
871 Ty::new_mut_ptr(tcx, nil)
872 } else {
873 Ty::new_mut_ref(tcx, tcx.lifetimes.re_static, nil)
874 };
875
876 let typing_env = ty::TypingEnv::fully_monomorphized();
880 return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
881 ty: this.ty,
882 ..tcx.layout_of(typing_env.as_query_input(unit_ptr_ty)).unwrap()
883 });
884 }
885
886 let mk_dyn_vtable = |principal: Option<ty::PolyExistentialTraitRef<'tcx>>| {
887 let min_count = ty::vtable_min_entries(
888 tcx,
889 principal.map(|principal| {
890 tcx.instantiate_bound_regions_with_erased(principal)
891 }),
892 );
893 Ty::new_imm_ref(
894 tcx,
895 tcx.lifetimes.re_static,
896 Ty::new_array(tcx, tcx.types.usize, min_count.try_into().unwrap()),
898 )
899 };
900
901 let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
902 && !pointee.references_error()
905 {
906 let metadata = tcx.normalize_erasing_regions(
907 cx.typing_env(),
908 Ty::new_projection(tcx, metadata_def_id, [pointee]),
909 );
910
911 if let ty::Adt(def, args) = metadata.kind()
916 && tcx.is_lang_item(def.did(), LangItem::DynMetadata)
917 && let ty::Dynamic(data, _) = args.type_at(0).kind()
918 {
919 mk_dyn_vtable(data.principal())
920 } else {
921 metadata
922 }
923 } else {
924 match tcx.struct_tail_for_codegen(pointee, cx.typing_env()).kind() {
925 ty::Slice(_) | ty::Str => tcx.types.usize,
926 ty::Dynamic(data, _) => mk_dyn_vtable(data.principal()),
927 _ => bug!("TyAndLayout::field({:?}): not applicable", this),
928 }
929 };
930
931 TyMaybeWithLayout::Ty(metadata)
932 }
933
934 ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
936 ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
937
938 ty::Closure(_, args) => field_ty_or_layout(
940 TyAndLayout { ty: args.as_closure().tupled_upvars_ty(), ..this },
941 cx,
942 i,
943 ),
944
945 ty::CoroutineClosure(_, args) => field_ty_or_layout(
946 TyAndLayout { ty: args.as_coroutine_closure().tupled_upvars_ty(), ..this },
947 cx,
948 i,
949 ),
950
951 ty::Coroutine(def_id, args) => match this.variants {
952 Variants::Empty => unreachable!(),
953 Variants::Single { index } => TyMaybeWithLayout::Ty(
954 args.as_coroutine()
955 .state_tys(def_id, tcx)
956 .nth(index.as_usize())
957 .unwrap()
958 .nth(i)
959 .unwrap(),
960 ),
961 Variants::Multiple { tag, tag_field, .. } => {
962 if FieldIdx::from_usize(i) == tag_field {
963 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
964 }
965 TyMaybeWithLayout::Ty(args.as_coroutine().prefix_tys()[i])
966 }
967 },
968
969 ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i]),
970
971 ty::Adt(def, args) => {
973 match this.variants {
974 Variants::Single { index } => {
975 let field = &def.variant(index).fields[FieldIdx::from_usize(i)];
976 TyMaybeWithLayout::Ty(field.ty(tcx, args))
977 }
978 Variants::Empty => panic!("there is no field in Variants::Empty types"),
979
980 Variants::Multiple { tag, .. } => {
982 assert_eq!(i, 0);
983 return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
984 }
985 }
986 }
987
988 ty::Alias(..)
989 | ty::Bound(..)
990 | ty::Placeholder(..)
991 | ty::Param(_)
992 | ty::Infer(_)
993 | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
994 }
995 }
996
997 match field_ty_or_layout(this, cx, i) {
998 TyMaybeWithLayout::Ty(field_ty) => {
999 cx.tcx().layout_of(cx.typing_env().as_query_input(field_ty)).unwrap_or_else(|e| {
1000 bug!(
1001 "failed to get layout for `{field_ty}`: {e:?},\n\
1002 despite it being a field (#{i}) of an existing layout: {this:#?}",
1003 )
1004 })
1005 }
1006 TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
1007 }
1008 }
1009
1010 fn ty_and_layout_pointee_info_at(
1013 this: TyAndLayout<'tcx>,
1014 cx: &C,
1015 offset: Size,
1016 ) -> Option<PointeeInfo> {
1017 let tcx = cx.tcx();
1018 let typing_env = cx.typing_env();
1019
1020 let pointee_info = match *this.ty.kind() {
1021 ty::RawPtr(p_ty, _) if offset.bytes() == 0 => {
1022 tcx.layout_of(typing_env.as_query_input(p_ty)).ok().map(|layout| PointeeInfo {
1023 size: layout.size,
1024 align: layout.align.abi,
1025 safe: None,
1026 })
1027 }
1028 ty::FnPtr(..) if offset.bytes() == 0 => {
1029 tcx.layout_of(typing_env.as_query_input(this.ty)).ok().map(|layout| PointeeInfo {
1030 size: layout.size,
1031 align: layout.align.abi,
1032 safe: None,
1033 })
1034 }
1035 ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
1036 let optimize = tcx.sess.opts.optimize != OptLevel::No;
1040 let kind = match mt {
1041 hir::Mutability::Not => {
1042 PointerKind::SharedRef { frozen: optimize && ty.is_freeze(tcx, typing_env) }
1043 }
1044 hir::Mutability::Mut => {
1045 PointerKind::MutableRef { unpin: optimize && ty.is_unpin(tcx, typing_env) }
1046 }
1047 };
1048
1049 tcx.layout_of(typing_env.as_query_input(ty)).ok().map(|layout| PointeeInfo {
1050 size: layout.size,
1051 align: layout.align.abi,
1052 safe: Some(kind),
1053 })
1054 }
1055
1056 _ => {
1057 let mut data_variant = match &this.variants {
1058 Variants::Multiple {
1068 tag_encoding:
1069 TagEncoding::Niche { untagged_variant, niche_variants, niche_start },
1070 tag_field,
1071 variants,
1072 ..
1073 } if variants.len() == 2
1074 && this.fields.offset(tag_field.as_usize()) == offset =>
1075 {
1076 let tagged_variant = if *untagged_variant == VariantIdx::ZERO {
1077 VariantIdx::from_u32(1)
1078 } else {
1079 VariantIdx::from_u32(0)
1080 };
1081 assert_eq!(tagged_variant, *niche_variants.start());
1082 if *niche_start == 0 {
1083 Some(this.for_variant(cx, *untagged_variant))
1089 } else {
1090 None
1091 }
1092 }
1093 Variants::Multiple { .. } => None,
1094 _ => Some(this),
1095 };
1096
1097 if let Some(variant) = data_variant
1098 && let FieldsShape::Union(_) = variant.fields
1100 {
1101 data_variant = None;
1102 }
1103
1104 let mut result = None;
1105
1106 if let Some(variant) = data_variant {
1107 let ptr_end = offset + Primitive::Pointer(AddressSpace::ZERO).size(cx);
1110 for i in 0..variant.fields.count() {
1111 let field_start = variant.fields.offset(i);
1112 if field_start <= offset {
1113 let field = variant.field(cx, i);
1114 result = field.to_result().ok().and_then(|field| {
1115 if ptr_end <= field_start + field.size {
1116 let field_info =
1118 field.pointee_info_at(cx, offset - field_start);
1119 field_info
1120 } else {
1121 None
1122 }
1123 });
1124 if result.is_some() {
1125 break;
1126 }
1127 }
1128 }
1129 }
1130
1131 if let Some(ref mut pointee) = result {
1135 if offset.bytes() == 0
1136 && let Some(boxed_ty) = this.ty.boxed_ty()
1137 {
1138 debug_assert!(pointee.safe.is_none());
1139 let optimize = tcx.sess.opts.optimize != OptLevel::No;
1140 pointee.safe = Some(PointerKind::Box {
1141 unpin: optimize && boxed_ty.is_unpin(tcx, typing_env),
1142 global: this.ty.is_box_global(tcx),
1143 });
1144 }
1145 }
1146
1147 result
1148 }
1149 };
1150
1151 debug!(
1152 "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
1153 offset,
1154 this.ty.kind(),
1155 pointee_info
1156 );
1157
1158 pointee_info
1159 }
1160
1161 fn is_adt(this: TyAndLayout<'tcx>) -> bool {
1162 matches!(this.ty.kind(), ty::Adt(..))
1163 }
1164
1165 fn is_never(this: TyAndLayout<'tcx>) -> bool {
1166 matches!(this.ty.kind(), ty::Never)
1167 }
1168
1169 fn is_tuple(this: TyAndLayout<'tcx>) -> bool {
1170 matches!(this.ty.kind(), ty::Tuple(..))
1171 }
1172
1173 fn is_unit(this: TyAndLayout<'tcx>) -> bool {
1174 matches!(this.ty.kind(), ty::Tuple(list) if list.len() == 0)
1175 }
1176
1177 fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
1178 matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
1179 }
1180
1181 fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'tcx>) -> bool {
1183 matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY_IN_NON_RUSTIC_ABIS))
1184 }
1185}
1186
1187#[inline]
1228#[tracing::instrument(level = "debug", skip(tcx))]
1229pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) -> bool {
1230 if let Some(did) = fn_def_id {
1231 if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
1233 return false;
1234 }
1235
1236 if !tcx.sess.panic_strategy().unwinds() && !tcx.is_foreign_item(did) {
1241 return false;
1242 }
1243
1244 if !tcx.sess.opts.unstable_opts.panic_in_drop.unwinds()
1249 && tcx.is_lang_item(did, LangItem::DropInPlace)
1250 {
1251 return false;
1252 }
1253 }
1254
1255 use ExternAbi::*;
1262 match abi {
1263 C { unwind }
1264 | System { unwind }
1265 | Cdecl { unwind }
1266 | Stdcall { unwind }
1267 | Fastcall { unwind }
1268 | Vectorcall { unwind }
1269 | Thiscall { unwind }
1270 | Aapcs { unwind }
1271 | Win64 { unwind }
1272 | SysV64 { unwind } => unwind,
1273 PtxKernel
1274 | Msp430Interrupt
1275 | X86Interrupt
1276 | GpuKernel
1277 | EfiApi
1278 | AvrInterrupt
1279 | AvrNonBlockingInterrupt
1280 | CmseNonSecureCall
1281 | CmseNonSecureEntry
1282 | Custom
1283 | RiscvInterruptM
1284 | RiscvInterruptS
1285 | RustInvalid
1286 | Unadjusted => false,
1287 Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(),
1288 }
1289}
1290
1291#[derive(Copy, Clone, Debug, HashStable)]
1293pub enum FnAbiError<'tcx> {
1294 Layout(LayoutError<'tcx>),
1296}
1297
1298impl<'a, 'b, G: EmissionGuarantee> Diagnostic<'a, G> for FnAbiError<'b> {
1299 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
1300 match self {
1301 Self::Layout(e) => e.into_diagnostic().into_diag(dcx, level),
1302 }
1303 }
1304}
1305
1306#[derive(Debug)]
1309pub enum FnAbiRequest<'tcx> {
1310 OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1311 OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
1312}
1313
1314pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
1317 type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>> = &'tcx FnAbi<'tcx, Ty<'tcx>>;
1320
1321 fn handle_fn_abi_err(
1329 &self,
1330 err: FnAbiError<'tcx>,
1331 span: Span,
1332 fn_abi_request: FnAbiRequest<'tcx>,
1333 ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
1334}
1335
1336pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
1338 #[inline]
1343 fn fn_abi_of_fn_ptr(
1344 &self,
1345 sig: ty::PolyFnSig<'tcx>,
1346 extra_args: &'tcx ty::List<Ty<'tcx>>,
1347 ) -> Self::FnAbiOfResult {
1348 let span = self.layout_tcx_at_span();
1350 let tcx = self.tcx().at(span);
1351
1352 MaybeResult::from(
1353 tcx.fn_abi_of_fn_ptr(self.typing_env().as_query_input((sig, extra_args))).map_err(
1354 |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
1355 ),
1356 )
1357 }
1358
1359 #[inline]
1365 #[tracing::instrument(level = "debug", skip(self))]
1366 fn fn_abi_of_instance(
1367 &self,
1368 instance: ty::Instance<'tcx>,
1369 extra_args: &'tcx ty::List<Ty<'tcx>>,
1370 ) -> Self::FnAbiOfResult {
1371 let span = self.layout_tcx_at_span();
1373 let tcx = self.tcx().at(span);
1374
1375 MaybeResult::from(
1376 tcx.fn_abi_of_instance(self.typing_env().as_query_input((instance, extra_args)))
1377 .map_err(|err| {
1378 let span =
1383 if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
1384 self.handle_fn_abi_err(
1385 *err,
1386 span,
1387 FnAbiRequest::OfInstance { instance, extra_args },
1388 )
1389 }),
1390 )
1391 }
1392}
1393
1394impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
1395
1396impl<'tcx> TyCtxt<'tcx> {
1397 pub fn offset_of_subfield<I>(
1398 self,
1399 typing_env: ty::TypingEnv<'tcx>,
1400 mut layout: TyAndLayout<'tcx>,
1401 indices: I,
1402 ) -> Size
1403 where
1404 I: Iterator<Item = (VariantIdx, FieldIdx)>,
1405 {
1406 let cx = LayoutCx::new(self, typing_env);
1407 let mut offset = Size::ZERO;
1408
1409 for (variant, field) in indices {
1410 layout = layout.for_variant(&cx, variant);
1411 let index = field.index();
1412 offset += layout.fields.offset(index);
1413 layout = layout.field(&cx, index);
1414 if !layout.is_sized() {
1415 let tail = self.struct_tail_for_codegen(layout.ty, typing_env);
1417 if !matches!(tail.kind(), ty::Slice(..)) {
1418 bug!(
1419 "offset of not-statically-aligned field (type {:?}) cannot be computed statically",
1420 layout.ty
1421 );
1422 }
1423 }
1424 }
1425
1426 offset
1427 }
1428}