1use hir::def_id::DefId;
2use rustc_abi::Integer::{I8, I32};
3use rustc_abi::Primitive::{self, Float, Int, Pointer};
4use rustc_abi::{
5 AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
6 LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding,
7 VariantIdx, Variants, WrappingRange,
8};
9use rustc_hashes::Hash64;
10use rustc_hir::attrs::AttributeKind;
11use rustc_hir::find_attr;
12use rustc_index::IndexVec;
13use rustc_middle::bug;
14use rustc_middle::query::Providers;
15use rustc_middle::traits::ObligationCause;
16use rustc_middle::ty::layout::{
17 FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, SimdLayoutError, TyAndLayout,
18};
19use rustc_middle::ty::print::with_no_trimmed_paths;
20use rustc_middle::ty::{
21 self, AdtDef, CoroutineArgsExt, EarlyBinder, PseudoCanonicalInput, Ty, TyCtxt, TypeVisitableExt,
22};
23use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
24use rustc_span::{Symbol, sym};
25use tracing::{debug, instrument};
26use {rustc_abi as abi, rustc_hir as hir};
27
28use crate::errors::NonPrimitiveSimdType;
29
30mod invariant;
31
32pub(crate) fn provide(providers: &mut Providers) {
33 *providers = Providers { layout_of, ..*providers };
34}
35
36#[instrument(skip(tcx, query), level = "debug")]
37fn layout_of<'tcx>(
38 tcx: TyCtxt<'tcx>,
39 query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
40) -> Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> {
41 let PseudoCanonicalInput { typing_env, value: ty } = query;
42 debug!(?ty);
43
44 let typing_env = typing_env.with_post_analysis_normalized(tcx);
48 let unnormalized_ty = ty;
49
50 let ty = match tcx.try_normalize_erasing_regions(typing_env, ty) {
55 Ok(t) => t,
56 Err(normalization_error) => {
57 return Err(tcx
58 .arena
59 .alloc(LayoutError::NormalizationFailure(ty, normalization_error)));
60 }
61 };
62
63 if ty != unnormalized_ty {
64 return tcx.layout_of(typing_env.as_query_input(ty));
66 }
67
68 let cx = LayoutCx::new(tcx, typing_env);
69
70 let layout = layout_of_uncached(&cx, ty)?;
71 let layout = TyAndLayout { ty, layout };
72
73 if cx.tcx().sess.opts.unstable_opts.print_type_sizes {
76 record_layout_for_printing(&cx, layout);
77 }
78
79 invariant::layout_sanity_check(&cx, &layout);
80
81 Ok(layout)
82}
83
84fn error<'tcx>(cx: &LayoutCx<'tcx>, err: LayoutError<'tcx>) -> &'tcx LayoutError<'tcx> {
85 cx.tcx().arena.alloc(err)
86}
87
88fn map_error<'tcx>(
89 cx: &LayoutCx<'tcx>,
90 ty: Ty<'tcx>,
91 err: LayoutCalculatorError<TyAndLayout<'tcx>>,
92) -> &'tcx LayoutError<'tcx> {
93 let err = match err {
94 LayoutCalculatorError::SizeOverflow => {
95 LayoutError::SizeOverflow(ty)
98 }
99 LayoutCalculatorError::UnexpectedUnsized(field) => {
100 assert!(field.layout.is_unsized(), "invalid layout error {err:#?}");
103 if cx.typing_env.param_env.caller_bounds().is_empty() {
104 cx.tcx().dcx().delayed_bug(format!(
105 "encountered unexpected unsized field in layout of {ty:?}: {field:#?}"
106 ));
107 }
108 LayoutError::Unknown(ty)
109 }
110 LayoutCalculatorError::EmptyUnion => {
111 let guar =
113 cx.tcx().dcx().delayed_bug(format!("computed layout of empty union: {ty:?}"));
114 LayoutError::ReferencesError(guar)
115 }
116 LayoutCalculatorError::ReprConflict => {
117 let guar = cx
119 .tcx()
120 .dcx()
121 .delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}"));
122 LayoutError::ReferencesError(guar)
123 }
124 LayoutCalculatorError::ZeroLengthSimdType => {
125 LayoutError::InvalidSimd { ty, kind: SimdLayoutError::ZeroLength }
127 }
128 LayoutCalculatorError::OversizedSimdType { max_lanes } => {
129 LayoutError::InvalidSimd { ty, kind: SimdLayoutError::TooManyLanes(max_lanes) }
131 }
132 LayoutCalculatorError::NonPrimitiveSimdType(field) => {
133 cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty })
136 }
137 };
138 error(cx, err)
139}
140
141fn extract_const_value<'tcx>(
142 cx: &LayoutCx<'tcx>,
143 ty: Ty<'tcx>,
144 ct: ty::Const<'tcx>,
145) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
146 match ct.kind() {
147 ty::ConstKind::Value(cv) => Ok(cv),
148 ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
149 if !ct.has_param() {
150 bug!("failed to normalize const, but it is not generic: {ct:?}");
151 }
152 Err(error(cx, LayoutError::TooGeneric(ty)))
153 }
154 ty::ConstKind::Unevaluated(_) => {
155 let err = if ct.has_param() {
156 LayoutError::TooGeneric(ty)
157 } else {
158 LayoutError::Unknown(ty)
164 };
165 Err(error(cx, err))
166 }
167 ty::ConstKind::Infer(_)
168 | ty::ConstKind::Bound(..)
169 | ty::ConstKind::Placeholder(_)
170 | ty::ConstKind::Error(_) => {
171 bug!("layout_of: unexpected const: {ct:?}");
174 }
175 }
176}
177
178fn layout_of_uncached<'tcx>(
179 cx: &LayoutCx<'tcx>,
180 ty: Ty<'tcx>,
181) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
182 if let Err(guar) = ty.error_reported() {
186 return Err(error(cx, LayoutError::ReferencesError(guar)));
187 }
188
189 let tcx = cx.tcx();
190
191 let dl = cx.data_layout();
195 let map_layout = |result: Result<_, _>| match result {
196 Ok(layout) => Ok(tcx.mk_layout(layout)),
197 Err(err) => Err(map_error(cx, ty, err)),
198 };
199 let scalar_unit = |value: Primitive| {
200 let size = value.size(dl);
201 assert!(size.bits() <= 128);
202 Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
203 };
204 let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
205
206 let univariant = |tys: &[Ty<'tcx>], kind| {
207 let fields = tys.iter().map(|ty| cx.layout_of(*ty)).try_collect::<IndexVec<_, _>>()?;
208 let repr = ReprOptions::default();
209 map_layout(cx.calc.univariant(&fields, &repr, kind))
210 };
211 debug_assert!(!ty.has_non_region_infer());
212
213 Ok(match *ty.kind() {
214 ty::Pat(ty, pat) => {
215 let layout = cx.layout_of(ty)?.layout;
216 let mut layout = LayoutData::clone(&layout.0);
217 match *pat {
218 ty::PatternKind::Range { start, end } => {
219 if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) =
220 &mut layout.backend_repr
221 {
222 scalar.valid_range_mut().start = extract_const_value(cx, ty, start)?
223 .try_to_bits(tcx, cx.typing_env)
224 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
225
226 scalar.valid_range_mut().end = extract_const_value(cx, ty, end)?
227 .try_to_bits(tcx, cx.typing_env)
228 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
229
230 if scalar.is_signed() {
236 let range = scalar.valid_range_mut();
237 let start = layout.size.sign_extend(range.start);
238 let end = layout.size.sign_extend(range.end);
239 if end < start {
240 let guar = tcx.dcx().err(format!(
241 "pattern type ranges cannot wrap: {start}..={end}"
242 ));
243
244 return Err(error(cx, LayoutError::ReferencesError(guar)));
245 }
246 } else {
247 let range = scalar.valid_range_mut();
248 if range.end < range.start {
249 let guar = tcx.dcx().err(format!(
250 "pattern type ranges cannot wrap: {}..={}",
251 range.start, range.end
252 ));
253
254 return Err(error(cx, LayoutError::ReferencesError(guar)));
255 }
256 };
257
258 let niche = Niche {
259 offset: Size::ZERO,
260 value: scalar.primitive(),
261 valid_range: scalar.valid_range(cx),
262 };
263
264 layout.largest_niche = Some(niche);
265 } else {
266 bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
267 }
268 }
269 ty::PatternKind::Or(variants) => match *variants[0] {
270 ty::PatternKind::Range { .. } => {
271 if let BackendRepr::Scalar(scalar) = &mut layout.backend_repr {
272 let variants: Result<Vec<_>, _> = variants
273 .iter()
274 .map(|pat| match *pat {
275 ty::PatternKind::Range { start, end } => Ok((
276 extract_const_value(cx, ty, start)
277 .unwrap()
278 .try_to_bits(tcx, cx.typing_env)
279 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
280 extract_const_value(cx, ty, end)
281 .unwrap()
282 .try_to_bits(tcx, cx.typing_env)
283 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
284 )),
285 ty::PatternKind::Or(_) => {
286 unreachable!("mixed or patterns are not allowed")
287 }
288 })
289 .collect();
290 let mut variants = variants?;
291 if !scalar.is_signed() {
292 let guar = tcx.dcx().err(format!(
293 "only signed integer base types are allowed for or-pattern pattern types at present"
294 ));
295
296 return Err(error(cx, LayoutError::ReferencesError(guar)));
297 }
298 variants.sort();
299 if variants.len() != 2 {
300 let guar = tcx
301 .dcx()
302 .err(format!("the only or-pattern types allowed are two range patterns that are directly connected at their overflow site"));
303
304 return Err(error(cx, LayoutError::ReferencesError(guar)));
305 }
306
307 let mut first = variants[0];
309 let mut second = variants[1];
310 if second.0
311 == layout.size.truncate(layout.size.signed_int_min() as u128)
312 {
313 (second, first) = (first, second);
314 }
315
316 if layout.size.sign_extend(first.1) >= layout.size.sign_extend(second.0)
317 {
318 let guar = tcx.dcx().err(format!(
319 "only non-overlapping pattern type ranges are allowed at present"
320 ));
321
322 return Err(error(cx, LayoutError::ReferencesError(guar)));
323 }
324 if layout.size.signed_int_max() as u128 != second.1 {
325 let guar = tcx.dcx().err(format!(
326 "one pattern needs to end at `{ty}::MAX`, but was {} instead",
327 second.1
328 ));
329
330 return Err(error(cx, LayoutError::ReferencesError(guar)));
331 }
332
333 scalar.valid_range_mut().start = second.0;
335 scalar.valid_range_mut().end = first.1;
336
337 let niche = Niche {
338 offset: Size::ZERO,
339 value: scalar.primitive(),
340 valid_range: scalar.valid_range(cx),
341 };
342
343 layout.largest_niche = Some(niche);
344 } else {
345 bug!(
346 "pattern type with range but not scalar layout: {ty:?}, {layout:?}"
347 )
348 }
349 }
350 ty::PatternKind::Or(..) => bug!("patterns cannot have nested or patterns"),
351 },
352 }
353 tcx.mk_layout(layout)
354 }
355
356 ty::Bool => tcx.mk_layout(LayoutData::scalar(
358 cx,
359 Scalar::Initialized {
360 value: Int(I8, false),
361 valid_range: WrappingRange { start: 0, end: 1 },
362 },
363 )),
364 ty::Char => tcx.mk_layout(LayoutData::scalar(
365 cx,
366 Scalar::Initialized {
367 value: Int(I32, false),
368 valid_range: WrappingRange { start: 0, end: 0x10FFFF },
369 },
370 )),
371 ty::Int(ity) => scalar(Int(abi::Integer::from_int_ty(dl, ity), true)),
372 ty::Uint(ity) => scalar(Int(abi::Integer::from_uint_ty(dl, ity), false)),
373 ty::Float(fty) => scalar(Float(abi::Float::from_float_ty(fty))),
374 ty::FnPtr(..) => {
375 let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
376 ptr.valid_range_mut().start = 1;
377 tcx.mk_layout(LayoutData::scalar(cx, ptr))
378 }
379
380 ty::Never => tcx.mk_layout(LayoutData::never_type(cx)),
382
383 ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
385 let mut data_ptr = scalar_unit(Pointer(AddressSpace::ZERO));
386 if !ty.is_raw_ptr() {
387 data_ptr.valid_range_mut().start = 1;
388 }
389
390 if pointee.is_sized(tcx, cx.typing_env) {
391 return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
392 }
393
394 let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type() {
395 let pointee_metadata = Ty::new_projection(tcx, metadata_def_id, [pointee]);
396 let metadata_ty = match tcx
397 .try_normalize_erasing_regions(cx.typing_env, pointee_metadata)
398 {
399 Ok(metadata_ty) => metadata_ty,
400 Err(mut err) => {
401 match tcx.try_normalize_erasing_regions(
410 cx.typing_env,
411 tcx.struct_tail_raw(pointee, &ObligationCause::dummy(), |ty| ty, || {}),
412 ) {
413 Ok(_) => {}
414 Err(better_err) => {
415 err = better_err;
416 }
417 }
418 return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
419 }
420 };
421
422 let metadata_layout = cx.layout_of(metadata_ty)?;
423 if metadata_layout.is_1zst() {
425 return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
426 }
427
428 let BackendRepr::Scalar(metadata) = metadata_layout.backend_repr else {
429 return Err(error(cx, LayoutError::Unknown(pointee)));
430 };
431
432 metadata
433 } else {
434 let unsized_part = tcx.struct_tail_for_codegen(pointee, cx.typing_env);
435
436 match unsized_part.kind() {
437 ty::Foreign(..) => {
438 return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
439 }
440 ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
441 ty::Dynamic(..) => {
442 let mut vtable = scalar_unit(Pointer(AddressSpace::ZERO));
443 vtable.valid_range_mut().start = 1;
444 vtable
445 }
446 _ => {
447 return Err(error(cx, LayoutError::Unknown(pointee)));
448 }
449 }
450 };
451
452 tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata))
454 }
455
456 ty::Array(element, count) => {
458 let count = extract_const_value(cx, ty, count)?
459 .try_to_target_usize(tcx)
460 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
461
462 let element = cx.layout_of(element)?;
463 map_layout(cx.calc.array_like(&element, Some(count)))?
464 }
465 ty::Slice(element) => {
466 let element = cx.layout_of(element)?;
467 map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
468 layout.randomization_seed = Hash64::new(0x2dcba99c39784102);
470 layout
471 }))?
472 }
473 ty::Str => {
474 let element = scalar(Int(I8, false));
475 map_layout(cx.calc.array_like(&element, None).map(|mut layout| {
476 layout.randomization_seed = Hash64::new(0xc1325f37d127be22);
478 layout
479 }))?
480 }
481
482 ty::FnDef(..) | ty::Dynamic(_, _) | ty::Foreign(..) => {
484 let sized = matches!(ty.kind(), ty::FnDef(..));
485 tcx.mk_layout(LayoutData::unit(cx, sized))
486 }
487
488 ty::Coroutine(def_id, args) => {
489 use rustc_middle::ty::layout::PrimitiveExt as _;
490
491 let info = tcx.coroutine_layout(def_id, args)?;
492
493 let local_layouts = info
494 .field_tys
495 .iter()
496 .map(|local| {
497 let field_ty = EarlyBinder::bind(local.ty);
498 let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty.instantiate(tcx, args));
499 cx.spanned_layout_of(uninit_ty, local.source_info.span)
500 })
501 .try_collect::<IndexVec<_, _>>()?;
502
503 let prefix_layouts = args
504 .as_coroutine()
505 .prefix_tys()
506 .iter()
507 .map(|ty| cx.layout_of(ty))
508 .try_collect::<IndexVec<_, _>>()?;
509
510 let layout = cx
511 .calc
512 .coroutine(
513 &local_layouts,
514 prefix_layouts,
515 &info.variant_fields,
516 &info.storage_conflicts,
517 |tag| TyAndLayout {
518 ty: tag.primitive().to_ty(tcx),
519 layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
520 },
521 )
522 .map(|mut layout| {
523 layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash();
525 debug!("coroutine layout ({:?}): {:#?}", ty, layout);
526 layout
527 });
528 map_layout(layout)?
529 }
530
531 ty::Closure(_, args) => univariant(args.as_closure().upvar_tys(), StructKind::AlwaysSized)?,
532
533 ty::CoroutineClosure(_, args) => {
534 univariant(args.as_coroutine_closure().upvar_tys(), StructKind::AlwaysSized)?
535 }
536
537 ty::Tuple(tys) => {
538 let kind =
539 if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
540
541 univariant(tys, kind)?
542 }
543
544 ty::Adt(def, args) if def.repr().simd() => {
546 let Some(ty::Array(e_ty, e_len)) = def
552 .is_struct()
553 .then(|| &def.variant(FIRST_VARIANT).fields)
554 .filter(|fields| fields.len() == 1)
555 .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).kind())
556 else {
557 let guar = tcx.dcx().delayed_bug("#[repr(simd)] was applied to an invalid ADT");
559 return Err(error(cx, LayoutError::ReferencesError(guar)));
560 };
561
562 let e_len = extract_const_value(cx, ty, e_len)?
563 .try_to_target_usize(tcx)
564 .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
565
566 let e_ly = cx.layout_of(e_ty)?;
567
568 if let Some(limit) = find_attr!(
570 tcx.get_all_attrs(def.did()),
571 AttributeKind::RustcSimdMonomorphizeLaneLimit(limit) => limit
572 ) {
573 if !limit.value_within_limit(e_len as usize) {
574 return Err(map_error(
575 &cx,
576 ty,
577 rustc_abi::LayoutCalculatorError::OversizedSimdType {
578 max_lanes: limit.0 as u64,
579 },
580 ));
581 }
582 }
583
584 map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
585 }
586
587 ty::Adt(def, args) => {
589 let variants = def
591 .variants()
592 .iter()
593 .map(|v| {
594 v.fields
595 .iter()
596 .map(|field| cx.layout_of(field.ty(tcx, args)))
597 .try_collect::<IndexVec<_, _>>()
598 })
599 .try_collect::<IndexVec<VariantIdx, _>>()?;
600
601 if def.is_union() {
602 if def.repr().pack.is_some() && def.repr().align.is_some() {
603 let guar = tcx.dcx().span_delayed_bug(
604 tcx.def_span(def.did()),
605 "union cannot be packed and aligned",
606 );
607 return Err(error(cx, LayoutError::ReferencesError(guar)));
608 }
609
610 return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
611 }
612
613 let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
615
616 let get_discriminant_type =
617 |min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
618
619 let discriminants_iter = || {
620 def.is_enum()
621 .then(|| def.discriminants(tcx).map(|(v, d)| (v, d.val as i128)))
622 .into_iter()
623 .flatten()
624 };
625
626 let maybe_unsized = def.is_struct()
627 && def.non_enum_variant().tail_opt().is_some_and(|last_field| {
628 let typing_env = ty::TypingEnv::post_analysis(tcx, def.did());
629 !tcx.type_of(last_field.did).instantiate_identity().is_sized(tcx, typing_env)
630 });
631
632 let layout = cx
633 .calc
634 .layout_of_struct_or_enum(
635 &def.repr(),
636 &variants,
637 def.is_enum(),
638 is_special_no_niche,
639 tcx.layout_scalar_valid_range(def.did()),
640 get_discriminant_type,
641 discriminants_iter(),
642 !maybe_unsized,
643 )
644 .map_err(|err| map_error(cx, ty, err))?;
645
646 if !maybe_unsized && layout.is_unsized() {
647 bug!("got unsized layout for type that cannot be unsized {ty:?}: {layout:#?}");
648 }
649
650 if cfg!(debug_assertions)
652 && maybe_unsized
653 && def.non_enum_variant().tail().ty(tcx, args).is_sized(tcx, cx.typing_env)
654 {
655 let mut variants = variants;
656 let tail_replacement = cx.layout_of(Ty::new_slice(tcx, tcx.types.u8)).unwrap();
657 *variants[FIRST_VARIANT].raw.last_mut().unwrap() = tail_replacement;
658
659 let Ok(unsized_layout) = cx.calc.layout_of_struct_or_enum(
660 &def.repr(),
661 &variants,
662 def.is_enum(),
663 is_special_no_niche,
664 tcx.layout_scalar_valid_range(def.did()),
665 get_discriminant_type,
666 discriminants_iter(),
667 !maybe_unsized,
668 ) else {
669 bug!("failed to compute unsized layout of {ty:?}");
670 };
671
672 let FieldsShape::Arbitrary { offsets: sized_offsets, .. } = &layout.fields else {
673 bug!("unexpected FieldsShape for sized layout of {ty:?}: {:?}", layout.fields);
674 };
675 let FieldsShape::Arbitrary { offsets: unsized_offsets, .. } =
676 &unsized_layout.fields
677 else {
678 bug!(
679 "unexpected FieldsShape for unsized layout of {ty:?}: {:?}",
680 unsized_layout.fields
681 );
682 };
683
684 let (sized_tail, sized_fields) = sized_offsets.raw.split_last().unwrap();
685 let (unsized_tail, unsized_fields) = unsized_offsets.raw.split_last().unwrap();
686
687 if sized_fields != unsized_fields {
688 bug!("unsizing {ty:?} changed field order!\n{layout:?}\n{unsized_layout:?}");
689 }
690
691 if sized_tail < unsized_tail {
692 bug!("unsizing {ty:?} moved tail backwards!\n{layout:?}\n{unsized_layout:?}");
693 }
694 }
695
696 tcx.mk_layout(layout)
697 }
698
699 ty::UnsafeBinder(bound_ty) => {
700 let ty = tcx.instantiate_bound_regions_with_erased(bound_ty.into());
701 cx.layout_of(ty)?.layout
702 }
703
704 ty::Param(_) | ty::Placeholder(..) => {
706 return Err(error(cx, LayoutError::TooGeneric(ty)));
707 }
708
709 ty::Alias(..) => {
710 let err = if ty.has_param() {
713 LayoutError::TooGeneric(ty)
714 } else {
715 LayoutError::Unknown(ty)
718 };
719 return Err(error(cx, err));
720 }
721
722 ty::Bound(..) | ty::CoroutineWitness(..) | ty::Infer(_) | ty::Error(_) => {
723 bug!("layout_of: unexpected type `{ty}`")
725 }
726 })
727}
728
729fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) {
730 if layout.ty.has_non_region_param() || !cx.typing_env.param_env.caller_bounds().is_empty() {
734 return;
735 }
736
737 let record = |kind, packed, opt_discr_size, variants| {
739 let type_desc = with_no_trimmed_paths!(format!("{}", layout.ty));
740 cx.tcx().sess.code_stats.record_type_size(
741 kind,
742 type_desc,
743 layout.align.abi,
744 layout.size,
745 packed,
746 opt_discr_size,
747 variants,
748 );
749 };
750
751 match *layout.ty.kind() {
752 ty::Adt(adt_def, _) => {
753 debug!("print-type-size t: `{:?}` process adt", layout.ty);
754 let adt_kind = adt_def.adt_kind();
755 let adt_packed = adt_def.repr().pack.is_some();
756 let (variant_infos, opt_discr_size) = variant_info_for_adt(cx, layout, adt_def);
757 record(adt_kind.into(), adt_packed, opt_discr_size, variant_infos);
758 }
759
760 ty::Coroutine(def_id, args) => {
761 debug!("print-type-size t: `{:?}` record coroutine", layout.ty);
762 let (variant_infos, opt_discr_size) =
764 variant_info_for_coroutine(cx, layout, def_id, args);
765 record(DataTypeKind::Coroutine, false, opt_discr_size, variant_infos);
766 }
767
768 ty::Closure(..) => {
769 debug!("print-type-size t: `{:?}` record closure", layout.ty);
770 record(DataTypeKind::Closure, false, None, vec![]);
771 }
772
773 _ => {
774 debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
775 }
776 };
777}
778
779fn variant_info_for_adt<'tcx>(
780 cx: &LayoutCx<'tcx>,
781 layout: TyAndLayout<'tcx>,
782 adt_def: AdtDef<'tcx>,
783) -> (Vec<VariantInfo>, Option<Size>) {
784 let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
785 let mut min_size = Size::ZERO;
786 let field_info: Vec<_> = flds
787 .iter()
788 .enumerate()
789 .map(|(i, &name)| {
790 let field_layout = layout.field(cx, i);
791 let offset = layout.fields.offset(i);
792 min_size = min_size.max(offset + field_layout.size);
793 FieldInfo {
794 kind: FieldKind::AdtField,
795 name,
796 offset: offset.bytes(),
797 size: field_layout.size.bytes(),
798 align: field_layout.align.bytes(),
799 type_name: None,
800 }
801 })
802 .collect();
803
804 VariantInfo {
805 name: n,
806 kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact },
807 align: layout.align.bytes(),
808 size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() },
809 fields: field_info,
810 }
811 };
812
813 match layout.variants {
814 Variants::Empty => (vec![], None),
815
816 Variants::Single { index } => {
817 debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variant(index).name);
818 let variant_def = &adt_def.variant(index);
819 let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
820 (vec![build_variant_info(Some(variant_def.name), &fields, layout)], None)
821 }
822
823 Variants::Multiple { tag, ref tag_encoding, .. } => {
824 debug!(
825 "print-type-size `{:#?}` adt general variants def {}",
826 layout.ty,
827 adt_def.variants().len()
828 );
829 let variant_infos: Vec<_> = adt_def
830 .variants()
831 .iter_enumerated()
832 .map(|(i, variant_def)| {
833 let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
834 build_variant_info(Some(variant_def.name), &fields, layout.for_variant(cx, i))
835 })
836 .collect();
837
838 (
839 variant_infos,
840 match tag_encoding {
841 TagEncoding::Direct => Some(tag.size(cx)),
842 _ => None,
843 },
844 )
845 }
846 }
847}
848
849fn variant_info_for_coroutine<'tcx>(
850 cx: &LayoutCx<'tcx>,
851 layout: TyAndLayout<'tcx>,
852 def_id: DefId,
853 args: ty::GenericArgsRef<'tcx>,
854) -> (Vec<VariantInfo>, Option<Size>) {
855 use itertools::Itertools;
856
857 let Variants::Multiple { tag, ref tag_encoding, tag_field, .. } = layout.variants else {
858 return (vec![], None);
859 };
860
861 let coroutine = cx.tcx().coroutine_layout(def_id, args).unwrap();
862 let upvar_names = cx.tcx().closure_saved_names_of_captured_variables(def_id);
863
864 let mut upvars_size = Size::ZERO;
865 let upvar_fields: Vec<_> = args
866 .as_coroutine()
867 .upvar_tys()
868 .iter()
869 .zip_eq(upvar_names)
870 .enumerate()
871 .map(|(field_idx, (_, name))| {
872 let field_layout = layout.field(cx, field_idx);
873 let offset = layout.fields.offset(field_idx);
874 upvars_size = upvars_size.max(offset + field_layout.size);
875 FieldInfo {
876 kind: FieldKind::Upvar,
877 name: *name,
878 offset: offset.bytes(),
879 size: field_layout.size.bytes(),
880 align: field_layout.align.bytes(),
881 type_name: None,
882 }
883 })
884 .collect();
885
886 let mut variant_infos: Vec<_> = coroutine
887 .variant_fields
888 .iter_enumerated()
889 .map(|(variant_idx, variant_def)| {
890 let variant_layout = layout.for_variant(cx, variant_idx);
891 let mut variant_size = Size::ZERO;
892 let fields = variant_def
893 .iter()
894 .enumerate()
895 .map(|(field_idx, local)| {
896 let field_name = coroutine.field_names[*local];
897 let field_layout = variant_layout.field(cx, field_idx);
898 let offset = variant_layout.fields.offset(field_idx);
899 variant_size = variant_size.max(offset + field_layout.size);
901 FieldInfo {
902 kind: FieldKind::CoroutineLocal,
903 name: field_name.unwrap_or_else(|| {
904 Symbol::intern(&format!(".coroutine_field{}", local.as_usize()))
905 }),
906 offset: offset.bytes(),
907 size: field_layout.size.bytes(),
908 align: field_layout.align.bytes(),
909 type_name: (field_name.is_none() || field_name == Some(sym::__awaitee))
912 .then(|| Symbol::intern(&field_layout.ty.to_string())),
913 }
914 })
915 .chain(upvar_fields.iter().copied())
916 .collect();
917
918 if variant_size == Size::ZERO {
920 variant_size = upvars_size;
921 }
922
923 if layout.fields.offset(tag_field.as_usize()) >= variant_size {
939 variant_size += match tag_encoding {
940 TagEncoding::Direct => tag.size(cx),
941 _ => Size::ZERO,
942 };
943 }
944
945 VariantInfo {
946 name: Some(Symbol::intern(&ty::CoroutineArgs::variant_name(variant_idx))),
947 kind: SizeKind::Exact,
948 size: variant_size.bytes(),
949 align: variant_layout.align.bytes(),
950 fields,
951 }
952 })
953 .collect();
954
955 let end_states = variant_infos.drain(1..=2);
960 let end_states: Vec<_> = end_states.collect();
961 variant_infos.extend(end_states);
962
963 (
964 variant_infos,
965 match tag_encoding {
966 TagEncoding::Direct => Some(tag.size(cx)),
967 _ => None,
968 },
969 )
970}