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