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