1use crate::ast::*;
3use derive_generic_visitor::*;
4use macros::{EnumAsGetters, EnumIsA, VariantName};
5use serde_state::{DeserializeState, SerializeState};
6
7#[derive(Debug, Copy, Clone, PartialEq)]
9#[derive(SerializeState, DeserializeState)]
10#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("Predecessor"))]
11pub enum FieldPredecessor {
12 Field(FieldId),
13 Tag,
14}
15
16#[derive(Debug, Clone)]
18#[derive(EnumIsA, EnumAsGetters, VariantName)]
19#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
20pub enum OffsetGuarantee {
21 AtOffset(SizeExpr),
23 GuaranteedAlignment(SizeExpr),
25 ReprCField(FieldPredecessor),
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32#[derive(EnumIsA, EnumAsGetters, VariantName)]
33#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
34#[cfg_attr(feature = "charon_on_charon", charon::variant_prefix("LayoutValue"))]
35pub enum MetadataValue {
36 DynSize,
38 DynAlign,
40 SliceLength,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
46#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
47#[serde_state(state_implements = DedupSerializerState)]
48pub struct SizeExpr(pub HashConsed<WithCachedTypeInfo<SizeExprKind>>);
49
50#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51#[derive(EnumIsA, EnumAsGetters, VariantName)]
52#[derive(SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
53#[cfg_attr(feature = "charon_on_charon", charon::variants_prefix("SizeExpr"))]
54pub enum SizeExprKind {
55 Constant(ConstantExpr),
57 FromMetadata(MetadataValue),
59 Max(Vec<SizeExpr>),
60 Min(Vec<SizeExpr>),
61 Plus(SizeExpr, SizeExpr),
62 Scale(SizeExpr, ConstantExpr),
64 AtLeast(SizeExpr),
66 AlignTo {
68 base: SizeExpr,
69 target_align: SizeExpr,
70 },
71 IfInhabited {
73 ty: Ty,
74 then_size: SizeExpr,
75 else_size: SizeExpr,
76 },
77}
78
79impl SizeExpr {
80 pub fn new(kind: SizeExprKind) -> Self {
81 Self(HashConsed::new(WithCachedTypeInfo::new(kind)))
82 }
83
84 pub fn kind(&self) -> &SizeExprKind {
85 self.0.inner()
86 }
87
88 pub fn with_kind_mut<R>(&mut self, f: impl FnOnce(&mut SizeExprKind) -> R) -> R {
89 self.0.with_inner_mut(|kind| kind.with_value_mut(f))
90 }
91
92 pub fn from_usize(value: u128) -> Self {
93 SizeExprKind::from_usize(value).into_expr()
94 }
95
96 pub fn size_of(ty: &Ty) -> Self {
98 Self::constant(ConstantExprKind::SizeOf(ty.clone()))
99 }
100
101 pub fn align_of(ty: &Ty) -> Self {
103 Self::constant(ConstantExprKind::AlignOf(ty.clone()))
104 }
105
106 pub fn offset_of(ty: TypeDeclRef, variant: Option<VariantId>, field: FieldId) -> Self {
108 Self::constant(ConstantExprKind::OffsetOf(ty, variant, field))
109 }
110
111 fn constant(kind: ConstantExprKind) -> Self {
112 SizeExprKind::Constant(ConstantExpr::new(kind, Ty::mk_usize())).into_expr()
113 }
114
115 pub fn max_or(mut values: Vec<SizeExpr>, default: SizeExpr) -> SizeExpr {
117 match values.len() {
118 0 => default,
119 1 => values.pop().unwrap(),
120 _ => SizeExprKind::Max(values).into_expr(),
121 }
122 }
123
124 pub fn max_align(values: Vec<SizeExpr>) -> SizeExpr {
126 Self::max_or(values, SizeExpr::from_usize(1))
127 }
128
129 pub fn max_size(values: Vec<SizeExpr>) -> SizeExpr {
131 Self::max_or(values, SizeExpr::from_usize(0))
132 }
133
134 pub fn align_to(base: SizeExpr, target_align: SizeExpr) -> SizeExpr {
135 SizeExprKind::AlignTo { base, target_align }.into_expr()
136 }
137
138 pub fn at_least(value: SizeExpr) -> SizeExpr {
139 SizeExprKind::AtLeast(value).into_expr()
140 }
141
142 pub fn if_inhabited(ty: &Ty, then_size: SizeExpr, else_size: SizeExpr) -> SizeExpr {
143 SizeExprKind::IfInhabited {
144 ty: ty.clone(),
145 then_size,
146 else_size,
147 }
148 .into_expr()
149 }
150
151 pub fn normalize(
155 mut self,
156 krate: Option<&TranslatedCrate>,
157 for_target: Option<&TargetTriple>,
158 allow_precision_loss: bool,
159 ) -> Self {
160 #[derive(Visitor)]
161 struct NormalizeSizeExpr<'a> {
162 krate: Option<&'a TranslatedCrate>,
163 for_target: Option<&'a TargetTriple>,
164 allow_precision_loss: bool,
165 }
166
167 fn fold_concrete_values(
169 values: &mut Vec<SizeExpr>,
170 f: impl Fn(u128, u128) -> u128,
171 ) -> Option<u128> {
172 values
173 .extract_if(.., |val| val.as_usize().is_some())
174 .map(|val| val.as_usize().unwrap())
175 .reduce(f)
176 }
177
178 fn peel_at_least(value: &SizeExpr) -> (SizeExpr, bool) {
179 if let SizeExprKind::AtLeast(inner) = value.kind() {
180 (inner.clone(), true)
181 } else {
182 (value.clone(), false)
183 }
184 }
185
186 fn rewrap_at_least(kind: SizeExprKind, at_least: bool) -> SizeExprKind {
187 if at_least {
188 SizeExprKind::AtLeast(kind.into_expr())
189 } else {
190 kind
191 }
192 }
193
194 fn as_usize_bound(value: &SizeExpr) -> Option<(u128, bool)> {
195 match value.kind() {
196 SizeExprKind::Constant(constant) => {
197 constant.as_usize_literal().map(|value| (value, true))
198 }
199 SizeExprKind::AtLeast(inner) => inner.as_usize().map(|value| (value, false)),
200 _ => None,
201 }
202 }
203
204 fn is_aligned_to(value: &SizeExpr, align: u128) -> bool {
205 if align == 0 {
206 return false;
207 }
208 match value.kind() {
209 SizeExprKind::Constant(constant) => constant
210 .as_usize_literal()
211 .is_some_and(|value| value % align == 0),
212 SizeExprKind::Scale(_, multiplier) => multiplier
213 .as_usize_literal()
214 .is_some_and(|multiplier| multiplier % align == 0),
215 SizeExprKind::AlignTo { target_align, .. } => target_align
216 .as_usize()
217 .is_some_and(|target_align| target_align % align == 0),
218 _ => false,
219 }
220 }
221
222 impl VisitAstMut for NormalizeSizeExpr<'_> {
223 fn visit_with_cached_type_info<T: AstVisitable>(
224 &mut self,
225 value: &mut WithCachedTypeInfo<T>,
226 ) -> ControlFlow<Self::Break> {
227 if value.type_info().is_normalized() {
228 Continue(())
229 } else {
230 self.visit_inner(value)
231 }
232 }
233
234 fn exit_size_expr_kind(&mut self, expr: &mut SizeExprKind) {
235 *expr = match expr {
236 SizeExprKind::Constant(constant) => {
237 debug_assert!(constant.ty().is_usize());
238 let mut guaranteed = match constant.kind() {
239 ConstantExprKind::SizeOf(ty) => match ty.kind() {
240 TyKind::Never => SizeExpr::from_usize(0),
241 TyKind::DynTrait(..) => {
242 SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr()
243 }
244 TyKind::Scalar(scalar_ty) => {
245 if let Some(krate) = self.krate
246 && let Some(target) = self.for_target
247 && let Some(target) = krate.target_information.get(target)
248 {
249 SizeExpr::from_usize(
250 scalar_ty.target_size(target.target_pointer_size)
251 as u128,
252 )
253 } else {
254 return;
255 }
256 }
257 _ => {
258 if let Some(krate) = self.krate
259 && let Some(ty_ref) = ty.as_adt()
260 && let Some(decl) = krate.type_decls.get(ty_ref.id)
261 && let Some(target) = self.for_target
262 && let Some(layout) = decl.layout.get(target)
263 && let Some(value) = layout.size.guarantee.clone()
264 {
265 value.substitute(&ty_ref.generics)
266 } else {
267 return;
268 }
269 }
270 },
271 ConstantExprKind::AlignOf(ty) => match ty.kind() {
272 TyKind::Never => SizeExpr::from_usize(1),
273 TyKind::DynTrait(..) => {
274 SizeExprKind::FromMetadata(MetadataValue::DynAlign).into_expr()
275 }
276 TyKind::Scalar(scalar_ty) => {
277 if let Some(krate) = self.krate
278 && let Some(target) = self.for_target
279 && let Some(target) = krate.target_information.get(target)
280 && let Some(value) =
281 target.primitive_alignments.get(scalar_ty)
282 {
283 SizeExpr::from_usize(u128::from(*value))
284 } else {
285 return;
286 }
287 }
288 _ => {
289 if let Some(krate) = self.krate
290 && let Some(ty_ref) = ty.as_adt()
291 && let Some(decl) = krate.type_decls.get(ty_ref.id)
292 && let Some(target) = self.for_target
293 && let Some(layout) = decl.layout.get(target)
294 && let Some(value) = layout.align.guarantee.clone()
295 {
296 value.substitute(&ty_ref.generics)
297 } else {
298 return;
299 }
300 }
301 },
302 _ => return,
303 };
304 self.visit(&mut guaranteed);
305 if !self.allow_precision_loss
306 && !matches!(
307 guaranteed.kind(),
308 SizeExprKind::Constant(_) | SizeExprKind::FromMetadata(_)
309 )
310 {
311 return;
312 }
313 guaranteed.kind().clone()
314 }
315 SizeExprKind::Max(values) => {
316 let mut at_least = false;
317 for val in std::mem::take(values) {
319 let (val, val_at_least) = peel_at_least(&val);
320 at_least |= val_at_least;
321 match val.kind() {
322 SizeExprKind::Max(nested) => values.extend(nested.iter().cloned()),
323 _ => values.push(val),
324 }
325 }
326 if let Some(value) = fold_concrete_values(values, std::cmp::max)
328 && value != 0
329 {
330 values.push(SizeExpr::from_usize(value));
332 }
333 let kind = if values.len() == 1 {
334 values.pop().unwrap().kind().clone()
335 } else if values.is_empty() {
336 SizeExprKind::zero()
337 } else if at_least {
338 SizeExprKind::Max(std::mem::take(values))
339 } else {
340 return;
341 };
342 rewrap_at_least(kind, at_least)
343 }
344 SizeExprKind::Min(values) => {
345 for val in std::mem::take(values) {
347 match val.kind() {
348 SizeExprKind::Min(nested) => values.extend(nested.iter().cloned()),
349 _ => values.push(val),
350 }
351 }
352 if let Some((value, exact)) = values
356 .extract_if(.., |value| as_usize_bound(value).is_some())
357 .map(|value| as_usize_bound(&value).unwrap())
358 .reduce(|(left, left_exact), (right, right_exact)| {
359 match left.cmp(&right) {
360 std::cmp::Ordering::Less => (left, left_exact),
361 std::cmp::Ordering::Greater => (right, right_exact),
362 std::cmp::Ordering::Equal => (left, left_exact || right_exact),
363 }
364 })
365 {
366 if value == 0 {
368 values.clear();
369 }
370 let value = SizeExprKind::from_usize(value);
371 values.push(rewrap_at_least(value, !exact).into_expr());
372 }
373 if values.len() == 1 {
374 values.pop().unwrap().kind().clone()
375 } else {
376 return;
377 }
378 }
379 SizeExprKind::Plus(left, right) => {
380 fn flatten_addition(
382 value: &SizeExpr,
383 values: &mut Vec<SizeExpr>,
384 at_least: &mut bool,
385 ) {
386 match value.kind() {
387 SizeExprKind::Plus(left, right) => {
388 flatten_addition(left, values, at_least);
389 flatten_addition(right, values, at_least);
390 }
391 SizeExprKind::AtLeast(inner) => {
392 *at_least = true;
393 flatten_addition(inner, values, at_least);
394 }
395 _ => values.push(value.clone()),
396 }
397 }
398 let mut values = Vec::new();
399 let mut at_least = false;
400 flatten_addition(left, &mut values, &mut at_least);
401 flatten_addition(right, &mut values, &mut at_least);
402
403 if let Some(constant) = fold_concrete_values(&mut values, u128::strict_add)
405 && constant != 0
406 {
407 values.insert(0, SizeExpr::from_usize(constant));
408 }
409 let kind = if values.len() == 1 {
410 values.pop().unwrap().kind().clone()
411 } else if values.is_empty() {
412 SizeExprKind::zero()
413 } else {
414 values
415 .into_iter()
416 .reduce(|left, right| SizeExprKind::Plus(left, right).into_expr())
417 .unwrap()
418 .kind()
419 .clone()
420 };
421 rewrap_at_least(kind, at_least)
422 }
423 SizeExprKind::Scale(base, multiplier) => {
424 match (base.as_usize(), multiplier.as_usize_literal()) {
425 (_, Some(0)) | (Some(0), _) => SizeExprKind::zero(),
426 (_, Some(1)) => base.kind().clone(),
427 (Some(base), Some(multiplier)) => {
428 SizeExprKind::from_usize(base.strict_mul(multiplier))
429 }
430 _ if let (base, true) = peel_at_least(base) => {
431 let mut kind = SizeExprKind::Scale(base, multiplier.clone());
432 self.visit(&mut kind);
433 rewrap_at_least(kind, true)
434 }
435 _ => return,
436 }
437 }
438 SizeExprKind::AlignTo { base, target_align } => {
439 match (base.as_usize(), target_align.as_usize()) {
440 (_, Some(1)) => base.kind().clone(),
441 (Some(base), Some(align)) if align != 0 => {
442 let remainder = base % align;
443 SizeExprKind::from_usize(if remainder == 0 {
444 base
445 } else {
446 base.strict_add(align - remainder)
447 })
448 }
449 (_, Some(align)) if is_aligned_to(base, align) => base.kind().clone(),
450 (_, Some(align))
451 if let SizeExprKind::Plus(left, right) = base.kind()
452 && is_aligned_to(left, align) =>
453 {
454 let right = SizeExprKind::AlignTo {
457 base: right.clone(),
458 target_align: target_align.clone(),
459 }
460 .into_expr();
461 let mut new = SizeExprKind::Plus(left.clone(), right);
462 self.visit(&mut new);
463 new
464 }
465 _ if let (base, base_at_least) = peel_at_least(base)
466 && let (target_align, align_at_least) =
467 peel_at_least(target_align)
468 && (base_at_least || align_at_least) =>
469 {
470 let mut kind = SizeExprKind::AlignTo { base, target_align };
471 self.visit(&mut kind);
472 rewrap_at_least(kind, true)
473 }
474 _ => return,
475 }
476 }
477 SizeExprKind::IfInhabited {
478 ty,
479 then_size,
480 else_size,
481 } => {
482 if then_size == else_size {
483 then_size.kind().clone()
484 } else if let Some(krate) = self.krate
485 && let Some(inhabited) = ty
486 .inhabited_predicate(krate, self.for_target)
487 .normalize(krate, self.for_target)
488 .as_bool()
489 {
490 if inhabited { then_size } else { else_size }.kind().clone()
491 } else {
492 return;
493 }
494 }
495 SizeExprKind::AtLeast(inner) => {
496 if inner.kind().is_at_least() {
497 inner.kind().clone()
498 } else {
499 return;
500 }
501 }
502 SizeExprKind::FromMetadata(_) => return,
503 };
504 }
505 }
506
507 NormalizeSizeExpr {
508 krate,
509 for_target,
510 allow_precision_loss,
511 }
512 .visit(&mut self);
513 self
514 }
515
516 fn as_usize(&self) -> Option<u128> {
517 if let SizeExprKind::Constant(constant) = self.kind() {
518 constant.as_usize_literal()
519 } else {
520 None
521 }
522 }
523}
524
525impl SizeExprKind {
526 pub fn zero() -> Self {
527 Self::from_usize(0)
528 }
529
530 pub fn from_usize(value: u128) -> Self {
531 Self::Constant(ConstantExpr::mk_usize(value))
532 }
533
534 pub fn into_expr(self) -> SizeExpr {
535 SizeExpr::new(self)
536 }
537}
538
539impl From<SizeExprKind> for SizeExpr {
540 fn from(kind: SizeExprKind) -> Self {
541 kind.into_expr()
542 }
543}
544
545impl std::ops::Deref for SizeExpr {
546 type Target = WithCachedTypeInfo<SizeExprKind>;
547 fn deref(&self) -> &Self::Target {
548 &self.0
549 }
550}
551
552#[cfg(test)]
553mod tests {
554 use super::*;
555
556 fn test_krate() -> (TranslatedCrate, TargetTriple) {
557 let mut krate = TranslatedCrate::default();
558 let target = "test-target".to_owned();
559 krate.target_information.insert(
560 target.clone(),
561 TargetInfo {
562 arch: from_rustc::Arch::Other("test".into()),
563 vendor: "unknown".to_owned(),
564 os: from_rustc::Os::Unknown,
565 env: from_rustc::Env::Unspecified,
566 cfg_abi: from_rustc::CfgAbi::Unspecified,
567 target_pointer_size: 8,
568 is_little_endian: true,
569 c_enum_smallest_repr_ty: IntTy::I32,
570 primitive_alignments: SeqHashMap::new(),
571 },
572 );
573 (krate, target)
574 }
575
576 #[test]
577 fn normalize_arithmetic() {
578 let (krate, target) = test_krate();
579 let expr = SizeExprKind::AlignTo {
580 base: SizeExprKind::Plus(
581 SizeExpr::from_usize(2),
582 SizeExprKind::Scale(SizeExpr::from_usize(3), ConstantExpr::mk_usize(4)).into_expr(),
583 )
584 .into_expr(),
585 target_align: SizeExpr::from_usize(8),
586 }
587 .into_expr()
588 .normalize(Some(&krate), Some(&target), false);
589
590 assert_eq!(expr.as_usize(), Some(16));
591 }
592
593 #[test]
594 fn normalize_additions() {
595 let (krate, target) = test_krate();
596 let dyn_size = SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr();
597 let dyn_align = SizeExprKind::FromMetadata(MetadataValue::DynAlign).into_expr();
598 let expr = SizeExprKind::Plus(
599 dyn_size.clone(),
600 SizeExprKind::Plus(
601 SizeExpr::from_usize(2),
602 SizeExprKind::Plus(dyn_align.clone(), SizeExpr::from_usize(3)).into_expr(),
603 )
604 .into_expr(),
605 )
606 .into_expr()
607 .normalize(Some(&krate), Some(&target), false);
608
609 assert_eq!(
610 expr,
611 SizeExprKind::Plus(
612 SizeExprKind::Plus(SizeExpr::from_usize(5), dyn_size).into_expr(),
613 dyn_align,
614 )
615 .into_expr()
616 );
617 }
618
619 #[test]
620 fn normalize_align_to_with_aligned_prefix() {
621 let (krate, target) = test_krate();
622 let dyn_size = SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr();
623 let dyn_align = SizeExprKind::FromMetadata(MetadataValue::DynAlign).into_expr();
624 let target_align = SizeExpr::from_usize(4);
625
626 let with_constant = SizeExprKind::AlignTo {
627 base: SizeExprKind::Plus(SizeExpr::from_usize(8), dyn_size.clone()).into_expr(),
628 target_align: target_align.clone(),
629 }
630 .into_expr()
631 .normalize(Some(&krate), Some(&target), false);
632 assert_eq!(
633 with_constant,
634 SizeExprKind::Plus(
635 SizeExpr::from_usize(8),
636 SizeExprKind::AlignTo {
637 base: dyn_size.clone(),
638 target_align: target_align.clone(),
639 }
640 .into_expr(),
641 )
642 .into_expr()
643 );
644
645 let scaled = SizeExprKind::Scale(dyn_size, ConstantExpr::mk_usize(8)).into_expr();
646 let aligned_scale = SizeExprKind::AlignTo {
647 base: scaled.clone(),
648 target_align: target_align.clone(),
649 }
650 .into_expr()
651 .normalize(Some(&krate), Some(&target), false);
652 assert_eq!(aligned_scale, scaled);
653
654 let inner_align_to = SizeExprKind::AlignTo {
655 base: dyn_align.clone(),
656 target_align: SizeExpr::from_usize(8),
657 }
658 .into_expr();
659 let nested_align_to = SizeExprKind::AlignTo {
660 base: inner_align_to.clone(),
661 target_align: target_align.clone(),
662 }
663 .into_expr()
664 .normalize(Some(&krate), Some(&target), false);
665 assert_eq!(nested_align_to, inner_align_to);
666
667 let insufficient_inner_align = SizeExprKind::AlignTo {
668 base: SizeExprKind::AlignTo {
669 base: dyn_align.clone(),
670 target_align: SizeExpr::from_usize(4),
671 }
672 .into_expr(),
673 target_align: SizeExpr::from_usize(8),
674 }
675 .into_expr();
676 assert_eq!(
677 insufficient_inner_align
678 .clone()
679 .normalize(Some(&krate), Some(&target), false),
680 insufficient_inner_align
681 );
682
683 let with_scale = SizeExprKind::AlignTo {
684 base: SizeExprKind::Plus(scaled.clone(), dyn_align.clone()).into_expr(),
685 target_align: target_align.clone(),
686 }
687 .into_expr()
688 .normalize(Some(&krate), Some(&target), false);
689 assert_eq!(
690 with_scale,
691 SizeExprKind::Plus(
692 scaled,
693 SizeExprKind::AlignTo {
694 base: dyn_align,
695 target_align,
696 }
697 .into_expr(),
698 )
699 .into_expr()
700 );
701
702 let unaligned_scale = SizeExprKind::AlignTo {
703 base: SizeExprKind::Plus(
704 SizeExprKind::Scale(
705 SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr(),
706 ConstantExpr::mk_usize(6),
707 )
708 .into_expr(),
709 SizeExprKind::FromMetadata(MetadataValue::DynAlign).into_expr(),
710 )
711 .into_expr(),
712 target_align: SizeExpr::from_usize(4),
713 }
714 .into_expr();
715 assert_eq!(
716 unaligned_scale
717 .clone()
718 .normalize(Some(&krate), Some(&target), false),
719 unaligned_scale
720 );
721 }
722
723 #[test]
724 fn normalize_extrema_partially() {
725 let (krate, target) = test_krate();
726 let expr = SizeExprKind::Max(vec![
727 SizeExpr::from_usize(2),
728 SizeExprKind::Max(vec![
729 SizeExpr::from_usize(5),
730 SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr(),
731 ])
732 .into_expr(),
733 SizeExpr::from_usize(3),
734 ])
735 .into_expr()
736 .normalize(Some(&krate), Some(&target), false);
737
738 let SizeExprKind::Max(contenders) = expr.kind() else {
739 panic!("expected a partially normalized maximum")
740 };
741 assert_eq!(contenders.len(), 2);
742 assert_eq!(contenders[1].as_usize(), Some(5));
743 assert!(matches!(
744 contenders[0].kind(),
745 SizeExprKind::FromMetadata(MetadataValue::DynSize)
746 ));
747
748 let empty =
749 SizeExprKind::Max(Vec::new())
750 .into_expr()
751 .normalize(Some(&krate), Some(&target), false);
752 assert_eq!(empty.as_usize(), Some(0));
753 }
754
755 #[test]
756 fn normalize_extrema_identities() {
757 let (krate, target) = test_krate();
758 let max = SizeExprKind::Max(vec![
759 SizeExpr::from_usize(0),
760 SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr(),
761 ])
762 .into_expr()
763 .normalize(Some(&krate), Some(&target), false);
764 let min = SizeExprKind::Min(vec![
765 SizeExpr::from_usize(7),
766 SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr(),
767 SizeExpr::from_usize(0),
768 ])
769 .into_expr()
770 .normalize(Some(&krate), Some(&target), false);
771
772 assert!(matches!(
773 max.kind(),
774 SizeExprKind::FromMetadata(MetadataValue::DynSize)
775 ));
776 assert_eq!(min.as_usize(), Some(0));
777 }
778
779 #[test]
780 fn normalize_lower_bounds() {
781 let normalize = |kind: SizeExprKind| kind.into_expr().normalize(None, None, false);
782 let at_least = |value| SizeExprKind::AtLeast(SizeExpr::from_usize(value)).into_expr();
783 let dyn_size = SizeExprKind::FromMetadata(MetadataValue::DynSize).into_expr();
784
785 assert_eq!(
786 normalize(SizeExprKind::Max(vec![at_least(2), dyn_size.clone()])),
787 SizeExprKind::AtLeast(
788 SizeExprKind::Max(vec![dyn_size.clone(), SizeExpr::from_usize(2)]).into_expr()
789 )
790 .into_expr()
791 );
792 assert_eq!(
793 normalize(SizeExprKind::Plus(at_least(2), SizeExpr::from_usize(3))),
794 at_least(5)
795 );
796 assert_eq!(
797 normalize(SizeExprKind::Scale(at_least(2), ConstantExpr::mk_usize(3))),
798 at_least(6)
799 );
800 assert_eq!(
801 normalize(SizeExprKind::AlignTo {
802 base: at_least(5),
803 target_align: SizeExpr::from_usize(4),
804 }),
805 at_least(8)
806 );
807 assert_eq!(
808 normalize(SizeExprKind::Min(vec![
809 at_least(5),
810 SizeExpr::from_usize(3)
811 ])),
812 SizeExpr::from_usize(3)
813 );
814 assert_eq!(
815 normalize(SizeExprKind::Min(vec![
816 at_least(3),
817 SizeExpr::from_usize(5)
818 ])),
819 at_least(3)
820 );
821 }
822
823 #[test]
824 fn normalize_if_inhabited() {
825 let (krate, target) = test_krate();
826 let expr = SizeExprKind::IfInhabited {
827 ty: TyKind::Never.into_ty(),
828 then_size: SizeExpr::from_usize(10),
829 else_size: SizeExprKind::Plus(SizeExpr::from_usize(2), SizeExpr::from_usize(3))
830 .into_expr(),
831 }
832 .into_expr()
833 .normalize(Some(&krate), Some(&target), false);
834
835 assert_eq!(expr.as_usize(), Some(5));
836 }
837
838 #[test]
839 fn normalize_for_the_selected_target() {
840 let mut krate = TranslatedCrate::default();
841 let scalar_ty = ScalarTy::Integer(IntegerTy::Unsigned(UIntTy::U64));
842 for (triple, pointer_size, alignment) in [("a", 4, 4), ("b", 8, 8)] {
843 let mut primitive_alignments = SeqHashMap::new();
844 primitive_alignments.insert(scalar_ty, alignment);
845 krate.target_information.insert(
846 triple.to_owned(),
847 TargetInfo {
848 arch: from_rustc::Arch::Other("test".into()),
849 vendor: "unknown".to_owned(),
850 os: from_rustc::Os::Unknown,
851 env: from_rustc::Env::Unspecified,
852 cfg_abi: from_rustc::CfgAbi::Unspecified,
853 target_pointer_size: pointer_size,
854 is_little_endian: true,
855 c_enum_smallest_repr_ty: IntTy::I32,
856 primitive_alignments,
857 },
858 );
859 }
860 let target_a = "a".to_owned();
861 let target_b = "b".to_owned();
862
863 let size = SizeExprKind::Constant(ConstantExpr::new(
864 ConstantExprKind::SizeOf(TyKind::Scalar(scalar_ty).into_ty()),
865 Ty::mk_usize(),
866 ))
867 .into_expr()
868 .normalize(Some(&krate), Some(&target_a), false);
869 let align = SizeExprKind::Constant(ConstantExpr::new(
870 ConstantExprKind::AlignOf(TyKind::Scalar(scalar_ty).into_ty()),
871 Ty::mk_usize(),
872 ))
873 .into_expr()
874 .normalize(Some(&krate), Some(&target_a), false);
875 let pointer_size = SizeExprKind::Constant(ConstantExpr::new(
876 ConstantExprKind::SizeOf(Ty::mk_usize()),
877 Ty::mk_usize(),
878 ))
879 .into_expr();
880 let pointer_size_a = pointer_size
881 .clone()
882 .normalize(Some(&krate), Some(&target_a), false);
883 let pointer_size_b = pointer_size.normalize(Some(&krate), Some(&target_b), false);
884
885 assert_eq!(size.as_usize(), Some(8));
886 assert_eq!(align.as_usize(), Some(4));
887 assert_eq!(pointer_size_a.as_usize(), Some(4));
888 assert_eq!(pointer_size_b.as_usize(), Some(8));
889 }
890
891 #[test]
892 fn normalize_without_a_crate_or_target() {
893 let size_of_usize = SizeExprKind::Constant(ConstantExpr::new(
894 ConstantExprKind::SizeOf(Ty::mk_usize()),
895 Ty::mk_usize(),
896 ))
897 .into_expr();
898 let align_of_u16 = SizeExprKind::Constant(ConstantExpr::new(
899 ConstantExprKind::AlignOf(
900 TyKind::Scalar(ScalarTy::Integer(IntegerTy::Unsigned(UIntTy::U16))).into_ty(),
901 ),
902 Ty::mk_usize(),
903 ))
904 .into_expr();
905
906 assert_eq!(
907 size_of_usize.clone().normalize(None, None, false),
908 size_of_usize
909 );
910 assert_eq!(
911 align_of_u16.clone().normalize(None, None, false),
912 align_of_u16
913 );
914
915 let target_independent = SizeExprKind::Plus(
916 SizeExprKind::Constant(ConstantExpr::new(
917 ConstantExprKind::SizeOf(TyKind::Never.into_ty()),
918 Ty::mk_usize(),
919 ))
920 .into_expr(),
921 SizeExpr::from_usize(4),
922 )
923 .into_expr()
924 .normalize(None, None, false);
925 assert_eq!(target_independent.as_usize(), Some(4));
926 }
927
928 #[test]
929 fn normalize_uses_guarantees_not_chosen_values() {
930 let (mut krate, target) = test_krate();
931 let id = TypeDeclId::ZERO;
932 let mut generics = GenericParams::empty();
933 generics
934 .types
935 .push_with(|id| TypeParam::new(id, "T".to_owned(), Variance::Invariant));
936 let generic_ty = generics.identity_args().types[TypeVarId::ZERO].clone();
937 let mut layouts = SeqHashMap::new();
938 layouts.insert(
939 target.clone(),
940 Layout {
941 size: Size {
942 chosen: Some(SizeExpr::from_usize(99)),
943 guarantee: None,
944 },
945 align: Size::new(1),
946 discriminator: None,
947 inhabited: InhabitedPredicate::mk_true(),
948 variant_layouts: Default::default(),
949 repr: Default::default(),
950 },
951 );
952 krate.type_decls.insert(
953 id,
954 TypeDecl {
955 def_id: id,
956 item_meta: ItemMeta::dummy_public(
957 Span::default(),
958 Name::from_path(&["T"]),
959 true,
960 ItemOpacity::Transparent,
961 ),
962 generics,
963 src: TypeSource::Normal,
964 kind: TypeDeclKind::Opaque,
965 layout: layouts,
966 ptr_metadata: PtrMetadata::None,
967 marker_traits: None,
968 },
969 );
970 let ty = TyKind::Adt(TypeDeclRef::new(
971 id,
972 GenericArgs::new_types(
973 [TyKind::Scalar(ScalarTy::Integer(IntegerTy::Unsigned(UIntTy::U16))).into_ty()]
974 .into_iter()
975 .collect(),
976 ),
977 None,
978 ))
979 .into_ty();
980 let size_of = || {
981 SizeExprKind::Constant(ConstantExpr::new(
982 ConstantExprKind::SizeOf(ty.clone()),
983 Ty::mk_usize(),
984 ))
985 .into_expr()
986 };
987 let align_of = || {
988 SizeExprKind::Constant(ConstantExpr::new(
989 ConstantExprKind::AlignOf(ty.clone()),
990 Ty::mk_usize(),
991 ))
992 .into_expr()
993 };
994
995 let without_guarantee = size_of().normalize(Some(&krate), Some(&target), false);
996 assert!(matches!(
997 without_guarantee.kind(),
998 SizeExprKind::Constant(constant)
999 if matches!(constant.kind(), ConstantExprKind::SizeOf(_))
1000 ));
1001
1002 {
1003 let layout = &mut krate.type_decls.get_mut(id).unwrap().layout[&target];
1004 layout.size.guarantee =
1005 Some(SizeExprKind::AtLeast(SizeExpr::from_usize(2)).into_expr());
1006 layout.align.guarantee =
1007 Some(SizeExprKind::AtLeast(SizeExpr::from_usize(1)).into_expr());
1008 }
1009
1010 let size_without_precision_loss = size_of().normalize(Some(&krate), Some(&target), false);
1011 assert!(matches!(
1012 size_without_precision_loss.kind(),
1013 SizeExprKind::Constant(constant)
1014 if matches!(constant.kind(), ConstantExprKind::SizeOf(_))
1015 ));
1016 let align_without_precision_loss = align_of().normalize(Some(&krate), Some(&target), false);
1017 assert!(matches!(
1018 align_without_precision_loss.kind(),
1019 SizeExprKind::Constant(constant)
1020 if matches!(constant.kind(), ConstantExprKind::AlignOf(_))
1021 ));
1022
1023 let size_with_precision_loss = size_of().normalize(Some(&krate), Some(&target), true);
1024 assert!(matches!(
1025 size_with_precision_loss.kind(),
1026 SizeExprKind::AtLeast(value) if value.as_usize() == Some(2)
1027 ));
1028 let align_with_precision_loss = align_of().normalize(Some(&krate), Some(&target), true);
1029 assert!(matches!(
1030 align_with_precision_loss.kind(),
1031 SizeExprKind::AtLeast(value) if value.as_usize() == Some(1)
1032 ));
1033
1034 let size = &mut krate.type_decls.get_mut(id).unwrap().layout[&target].size;
1035 size.guarantee = Some(
1036 SizeExprKind::Plus(
1037 SizeExprKind::Constant(ConstantExpr::new(
1038 ConstantExprKind::SizeOf(generic_ty),
1039 Ty::mk_usize(),
1040 ))
1041 .into_expr(),
1042 SizeExpr::from_usize(5),
1043 )
1044 .into_expr(),
1045 );
1046 let with_guarantee = size_of().normalize(Some(&krate), Some(&target), false);
1047 assert_eq!(with_guarantee.as_usize(), Some(7));
1048 }
1049}