1#![doc(html_root_url = "https://docs.rs/rucc-types/0.9.4")]
82
83mod classify;
84mod compat;
85mod convert;
86mod granule;
87mod kind;
88mod layout;
89mod print;
90mod record;
91mod types;
92
93pub use crate::classify::{
94 element, is_aggregate, is_arithmetic, is_array, is_atomic, is_complete, is_complex,
95 is_floating, is_function, is_integer, is_modifiable, is_object, is_pointer, is_real,
96 is_real_floating, is_record, is_scalar, is_vector, is_void, lanes, pointee,
97};
98pub use crate::compat::{adjust_parameter, compatible, composite};
99pub use crate::convert::{
100 mask_of, promote, promote_bit_field, usual_arithmetic, vectors_convertible,
101};
102pub use crate::granule::{GRANULE, Keying, Tally, measure, measure_all, report as granule_report};
103pub use crate::kind::{
104 ArrayLen, EnumId, FloatKind, FunctionId, FunctionType, IntKind, Qualifiers, RecordId,
105 RecordKind, Type, TypeKind, VlaId,
106};
107pub use crate::layout::{
108 IntegerInfo, Layout, LayoutError, float_format, float_width, int_width, integer_info, layout,
109};
110pub use crate::print::{declare, spell};
111pub use crate::record::{
112 Field, FieldDecl, RecordError, RecordLayout, RecordOptions, layout_record,
113};
114pub use crate::types::{EnumInfo, RecordInfo, TypeId, Types};
115
116pub const MILESTONE: &str = "M2";
118
119#[cfg(test)]
120mod tests {
121 use std::num::NonZeroU32;
122
123 use rucc_base::{Interner, Symbol};
124 use rucc_target::{TargetInfo, Triple};
125
126 use super::*;
127
128 fn target(triple: &str) -> TargetInfo {
129 TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
130 }
131
132 fn linux() -> TargetInfo {
133 target("x86_64-unknown-linux-gnu")
134 }
135
136 fn windows() -> TargetInfo {
140 target("x86_64-pc-windows-msvc")
141 }
142
143 fn aapcs() -> TargetInfo {
147 target("aarch64-unknown-linux-gnu")
148 }
149
150 fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
152 lay_out_on(&linux(), types, kind, fields)
153 }
154
155 fn lay_out_on(
157 target: &TargetInfo,
158 types: &Types,
159 kind: RecordKind,
160 fields: &[FieldDecl],
161 ) -> RecordLayout {
162 layout_record(types, kind, fields, &RecordOptions::default(), target)
163 .expect("a record every member of which has a layout")
164 }
165
166 fn offsets(laid_out: &RecordLayout) -> Vec<u128> {
169 laid_out.fields.iter().map(Field::bit_offset).collect()
170 }
171
172 fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
174 let id = types.declare_record(kind, None);
175 let laid_out = lay_out(types, kind, fields);
176 types.complete_record(id, laid_out);
177 types.record(id)
178 }
179
180 fn member(ty: TypeId) -> FieldDecl {
182 FieldDecl::new(None, ty)
183 }
184
185 fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
188 FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
189 }
190
191 fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
193 FieldDecl::bit_field(None, ty, width)
194 }
195
196 #[test]
197 fn milestone_is_recorded() {
198 assert!(MILESTONE.starts_with('M'));
199 }
200
201 #[test]
202 fn an_integer_type_answers_with_the_width_of_its_value_and_not_of_its_object() {
203 let mut interner = Interner::new();
204 let mut types = Types::new();
205 let target = linux();
206
207 let boolean = types.boolean();
210 let bits = types.bit_int(true, 37);
211 let short = types.int(IntKind::Short);
213 let alias = types.typedef(interner.intern("word"), short);
214 let unsigned_char = types.int(IntKind::UChar);
215 let atomic = types.atomic(unsigned_char);
216
217 let shape = |ty| integer_info(&types, ty, &target).expect("an integer type");
218 assert_eq!(shape(boolean), IntegerInfo::new(false, 1));
219 assert_eq!(shape(bits), IntegerInfo::new(true, 37));
220 assert_eq!(shape(types.int(IntKind::Int)), IntegerInfo::new(true, 32));
221 assert_eq!(shape(types.int(IntKind::ULong)), IntegerInfo::new(false, 64));
222 assert_eq!(shape(alias), IntegerInfo::new(true, 16));
223 assert_eq!(shape(atomic), IntegerInfo::new(false, 8));
224
225 assert_eq!(integer_info(&types, types.float(FloatKind::Double), &target), None);
226 }
227
228 #[test]
229 fn an_enumeration_answers_with_the_type_the_enumerators_are_kept_in() {
230 let mut interner = Interner::new();
231 let mut types = Types::new();
232 let target = linux();
233
234 let colour = types.declare_enum(Some(interner.intern("colour")));
237 let ty = types.enumeration(colour);
238 assert_eq!(integer_info(&types, ty, &target), None);
239
240 let underlying = types.int(IntKind::ULong);
241 types.complete_enum(colour, underlying, true);
242 assert_eq!(integer_info(&types, ty, &target), Some(IntegerInfo::new(false, 64)));
243 }
244
245 #[test]
246 fn a_value_stored_in_an_integer_type_keeps_the_bits_the_type_has_room_for() {
247 let char_type = IntegerInfo::new(true, 8);
248 assert_eq!(char_type.wrap(300), 44);
249 assert!(!char_type.holds(300));
250 assert!(char_type.holds(-128));
251
252 assert_eq!(IntegerInfo::new(false, 32).wrap(-1), 4_294_967_295);
253 assert_eq!(IntegerInfo::new(false, 8).wrap(-1), 255);
254
255 assert!(IntegerInfo::new(false, 128).holds(i128::MIN));
258 assert!(IntegerInfo::new(true, 128).holds(i128::MIN));
259 assert_eq!(IntegerInfo::new(true, 128).wrap(i128::MAX), i128::MAX);
260 }
261
262 #[test]
263 fn a_long_double_has_a_format_the_size_does_not_give_away() {
264 let target = linux();
265 assert_eq!(float_width(FloatKind::LongDouble, &target), 128);
268 assert_eq!(
269 float_format(FloatKind::LongDouble, &target),
270 rucc_base::float::Format::X87Extended
271 );
272 assert_eq!(float_format(FloatKind::Float, &target), rucc_base::float::Format::Single);
273 }
274
275 #[test]
276 fn an_interchange_type_names_a_format_and_an_extended_one_names_the_target() {
277 use rucc_base::float::Format;
278
279 for target in [&linux(), &target("aarch64-apple-darwin")] {
282 assert_eq!(float_format(FloatKind::Float16, target), Format::Half);
283 assert_eq!(float_format(FloatKind::Float32, target), Format::Single);
284 assert_eq!(float_format(FloatKind::Float64, target), Format::Double);
285 assert_eq!(float_format(FloatKind::Float128, target), Format::Quad);
286 assert_eq!(float_width(FloatKind::Float16, target), 16);
287 assert_eq!(float_width(FloatKind::Float32, target), 32);
288 assert_eq!(float_width(FloatKind::Float64, target), 64);
289 assert_eq!(float_width(FloatKind::Float128, target), 128);
290 assert_eq!(float_format(FloatKind::Float32x, target), Format::Double);
292 }
293
294 let x86 = linux();
298 assert_eq!(float_format(FloatKind::Float64x, &x86), Format::X87Extended);
299 assert_eq!(float_format(FloatKind::LongDouble, &x86), Format::X87Extended);
300 let mac = target("aarch64-apple-darwin");
301 assert_eq!(float_format(FloatKind::Float64x, &mac), Format::Quad);
302 assert_eq!(float_format(FloatKind::LongDouble, &mac), Format::Double);
303 assert_eq!(float_width(FloatKind::Float64x, &x86), 128);
306 assert_eq!(float_width(FloatKind::Float64x, &mac), 128);
307 }
308
309 #[test]
310 fn every_floating_type_is_as_wide_as_the_format_it_is_stored_in() {
311 let types = Types::new();
312 let sizes = |target: &TargetInfo| -> Vec<(u64, u64)> {
313 FloatKind::ALL
314 .iter()
315 .map(|&kind| {
316 let found = layout(&types, types.float(kind), target).expect("a complete type");
317 (found.size, found.align)
318 })
319 .collect()
320 };
321 assert_eq!(
325 sizes(&linux()),
326 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16), (16, 16)]
327 );
328 assert_eq!(
329 sizes(&target("aarch64-apple-darwin")),
330 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16)]
331 );
332 }
333
334 #[test]
335 fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
336 let types = Types::new();
339 let mut seen = Vec::new();
340 for kind in FloatKind::ALL {
341 seen.push(types.float(kind));
342 }
343 let mut sorted = seen.clone();
344 sorted.sort_unstable();
345 sorted.dedup();
346 assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
347
348 let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
349 assert_eq!(
350 names,
351 [
352 "_Float16",
353 "float",
354 "_Float32",
355 "double",
356 "_Float32x",
357 "_Float64",
358 "long double",
359 "_Float64x",
360 "_Float128",
361 ]
362 );
363 }
364
365 #[test]
366 fn the_same_type_asked_for_twice_is_the_same_id() {
367 let mut types = Types::new();
368 let a = types.pointer(types.int(IntKind::Int));
369 let b = types.pointer(types.int(IntKind::Int));
370 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
371 let c = types.pointer(types.int(IntKind::Long));
372 assert_ne!(a, c);
373 }
374
375 #[test]
376 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
377 let mut types = Types::new();
378 let int = types.int(IntKind::Int);
379 let konst = types.qualified(int, Qualifiers::CONST);
380 assert_ne!(int, konst);
381 assert_eq!(types.kind(konst), types.kind(int));
382 assert!(types.quals(konst).has(Qualifiers::CONST));
383 assert_eq!(types.unqualified(konst), int);
384 }
385
386 #[test]
387 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
388 let mut types = Types::new();
389 let int = types.int(IntKind::Int);
390 let a = types.qualified(int, Qualifiers::CONST);
391 let a = types.qualified(a, Qualifiers::VOLATILE);
392 let b = types.qualified(int, Qualifiers::VOLATILE);
393 let b = types.qualified(b, Qualifiers::CONST);
394 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
395 }
396
397 #[test]
398 fn qualifying_an_array_qualifies_its_element() {
399 let mut types = Types::new();
402 let int = types.int(IntKind::Int);
403 let array = types.array(int, ArrayLen::Fixed(4));
404 let konst = types.qualified(array, Qualifiers::CONST);
405 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
406 let TypeKind::Array { elem, len } = types.kind(konst) else {
407 panic!("still an array");
408 };
409 assert_eq!(len, ArrayLen::Fixed(4));
410 assert!(types.quals(elem).has(Qualifiers::CONST));
411 }
412
413 #[test]
414 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
415 let mut interner = Interner::new();
416 let mut types = Types::new();
417 let int = types.int(IntKind::Int);
418 let name = types.typedef(interner.intern("int32_t"), int);
419 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
420 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
421 assert!(types.is_sugar(name));
422 assert!(!types.is_sugar(int));
423 }
424
425 #[test]
426 fn sugar_below_the_outermost_node_is_resolved_too() {
427 let mut interner = Interner::new();
430 let mut types = Types::new();
431 let int = types.int(IntKind::Int);
432 let name = types.typedef(interner.intern("int32_t"), int);
433 let sugar_pointer = types.pointer(name);
434 let plain_pointer = types.pointer(int);
435 assert_ne!(sugar_pointer, plain_pointer);
436 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
437
438 let sugar_array = types.array(name, ArrayLen::Fixed(3));
439 let plain_array = types.array(int, ArrayLen::Fixed(3));
440 assert_eq!(types.canonical(sugar_array), plain_array);
441 }
442
443 #[test]
444 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
445 let mut interner = Interner::new();
446 let mut types = Types::new();
447 let int = types.int(IntKind::Int);
448 let mut current = int;
449 for i in 0..8 {
450 current = types.typedef(interner.intern(&format!("t{i}")), current);
451 }
452 assert_eq!(types.canonical(current), int);
453 }
454
455 #[test]
456 fn a_typedef_that_asked_for_an_alignment_says_what_it_is_and_not_what_it_is_at_least() {
457 let mut interner = Interner::new();
462 let mut types = Types::new();
463 let target = linux();
464 let int = types.int(IntKind::Int);
465 let low = types.aligned_typedef(interner.intern("L"), int, NonZeroU32::new(2).unwrap());
466 let high = types.aligned_typedef(interner.intern("H"), int, NonZeroU32::new(16).unwrap());
467
468 assert_eq!(layout(&types, low, &target), Ok(Layout::new(4, 2)));
469 assert_eq!(layout(&types, high, &target), Ok(Layout::new(4, 16)));
470 assert_eq!(layout(&types, int, &target), Ok(Layout::new(4, 4)));
473
474 assert_ne!(low, high);
477
478 let outer = types.aligned_typedef(interner.intern("M"), low, NonZeroU32::new(8).unwrap());
481 assert_eq!(types.align_override(outer), NonZeroU32::new(8));
482 let plain = types.typedef(interner.intern("N"), low);
483 assert_eq!(types.align_override(plain), NonZeroU32::new(2));
484 assert_eq!(types.align_override(int), None);
486 }
487
488 #[test]
489 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
490 let mut interner = Interner::new();
491 let mut types = Types::new();
492 let int = types.int(IntKind::Int);
493 let name = types.typedef(interner.intern("int32_t"), int);
494 let konst = types.qualified(name, Qualifiers::CONST);
495 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
496 let want = types.qualified(int, Qualifiers::CONST);
497 assert_eq!(types.canonical(konst), want);
498 }
499
500 #[test]
501 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
502 let mut interner = Interner::new();
505 let mut types = Types::new();
506 let int = types.int(IntKind::Int);
507 let array = types.array(int, ArrayLen::Fixed(4));
508 let name = types.typedef(interner.intern("A"), array);
509 let konst = types.qualified(name, Qualifiers::CONST);
510 let konst_int = types.qualified(int, Qualifiers::CONST);
511 let want = types.array(konst_int, ArrayLen::Fixed(4));
512 assert_eq!(types.canonical(konst), want);
513 }
514
515 #[test]
516 fn a_function_type_is_deduplicated_by_its_signature() {
517 let mut types = Types::new();
518 let int = types.int(IntKind::Int);
519 let long = types.int(IntKind::Long);
520 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
521 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
522 };
523 let a = make(&mut types, vec![int, long], false);
524 let b = make(&mut types, vec![int, long], false);
525 assert_eq!(a, b);
526 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
527 assert_ne!(a, make(&mut types, vec![long, int], false));
528 }
529
530 #[test]
531 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
532 let mut interner = Interner::new();
533 let mut types = Types::new();
534 let int = types.int(IntKind::Int);
535 let name = types.typedef(interner.intern("int32_t"), int);
536 let sugar = types.function(FunctionType {
537 ret: name,
538 params: vec![name],
539 variadic: false,
540 prototyped: true,
541 });
542 let plain = types.function(FunctionType {
543 ret: int,
544 params: vec![int],
545 variadic: false,
546 prototyped: true,
547 });
548 assert_ne!(sugar, plain);
549 assert_eq!(types.canonical(sugar), plain);
550 }
551
552 #[test]
553 fn a_record_is_its_declaration_and_not_its_members() {
554 let mut interner = Interner::new();
558 let mut types = Types::new();
559 let tag = interner.intern("point");
560 let first = types.declare_record(RecordKind::Struct, Some(tag));
561 let second = types.declare_record(RecordKind::Struct, Some(tag));
562 assert_ne!(types.record(first), types.record(second));
563 assert_eq!(types.record(first), types.record(first));
564 }
565
566 #[test]
567 fn a_record_has_no_layout_until_it_has_been_completed() {
568 let mut types = Types::new();
569 let id = types.declare_record(RecordKind::Struct, None);
570 let ty = types.record(id);
571 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
572 let long_long = types.int(IntKind::LongLong);
573 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
574 types.complete_record(id, laid_out);
575 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
576 }
577
578 #[test]
579 fn an_enum_takes_the_layout_of_its_underlying_type() {
580 let mut types = Types::new();
581 let id = types.declare_enum(None);
582 let ty = types.enumeration(id);
583 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
584 let int = types.int(IntKind::Int);
585 types.complete_enum(id, int, false);
586 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
587 }
588
589 #[test]
590 fn the_scalar_widths_come_from_the_target() {
591 let mut types = Types::new();
592 let linux = linux();
593 let windows = target("x86_64-pc-windows-msvc");
594 let darwin = target("aarch64-apple-darwin");
595
596 let long = types.int(IntKind::Long);
597 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
598 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
599
600 let ldouble = types.float(FloatKind::LongDouble);
601 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
602 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
603
604 let pointer = types.pointer(types.void());
605 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
606
607 let boolean = types.boolean();
608 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
609 }
610
611 #[test]
612 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
613 let mut types = Types::new();
616 let linux = linux();
617 let cfloat = types.complex(FloatKind::Float);
618 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
619 let cdouble = types.complex(FloatKind::Double);
620 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
621 let cldouble = types.complex(FloatKind::LongDouble);
622 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
623 let darwin = target("aarch64-apple-darwin");
624 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
625 }
626
627 #[test]
628 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
629 let mut types = Types::new();
632 let linux = linux();
633 let long_long = types.int(IntKind::LongLong);
634 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
635 let atomic = types.atomic(plain);
636 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
637 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
638
639 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
641 let atomic_odd = types.atomic(odd);
642 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
643
644 let int = types.int(IntKind::Int);
645 let atomic_int = types.atomic(int);
646 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
647 }
648
649 #[test]
650 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
651 let mut types = Types::new();
654 let linux = linux();
655 let darwin = target("aarch64-apple-darwin");
656 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
657 for (width, size, align) in cases {
658 let ty = types.bit_int(true, width);
659 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
660 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
661 }
662 for width in [65, 96, 128] {
663 let ty = types.bit_int(false, width);
664 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
665 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
666 }
667 let wide = types.bit_int(true, 129);
668 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
669 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
670 }
671
672 #[test]
673 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
674 let mut types = Types::new();
675 let linux = linux();
676 let int = types.int(IntKind::Int);
677 let ty = types.array(int, ArrayLen::Fixed(10));
678 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
679 let nested = types.array(ty, ArrayLen::Fixed(3));
680 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
681 }
682
683 #[test]
684 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
685 let mut types = Types::new();
686 let linux = linux();
687 let int = types.int(IntKind::Int);
688 for len in [ArrayLen::Unknown, ArrayLen::Star, ArrayLen::Variable(VlaId(0))] {
689 let ty = types.array(int, len);
690 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
691 }
692 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
693 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
694 }
695
696 #[test]
697 fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
698 let mut types = Types::new();
702 let linux = linux();
703 let max = linux.max_object_size();
704 let ch = types.int(IntKind::Char);
705 let fits = types.array(ch, ArrayLen::Fixed(max));
706 assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
707 let over = types.array(ch, ArrayLen::Fixed(max + 1));
708 assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
709 }
710
711 #[test]
712 fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
713 let mut types = Types::new();
718 let linux = linux();
719 let max = linux.max_object_size();
720 let ch = types.int(IntKind::Char);
721 let int = types.int(IntKind::Int);
722 let short = types.int(IntKind::Short);
723
724 let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
725 let members = [member(huge), member(int), member(int), member(int), member(int)];
726 let laid_out = lay_out(&types, RecordKind::Struct, &members);
727 assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
728
729 let brim = types.array(ch, ArrayLen::Fixed(max));
730 let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
731 assert_eq!(laid_out.layout, Layout::new(max, 1));
732
733 let over = [member(brim), member(ch)];
734 let options = RecordOptions::default();
735 let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
736 assert_eq!(error, Err(RecordError::TooLarge));
737 }
738
739 #[test]
740 fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
741 let mut types = Types::new();
746 let linux = linux();
747 let ch = types.int(IntKind::Char);
748 let int = types.int(IntKind::Int);
749 let mut interner = Interner::new();
750 let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
751 let members = [member(buf), bits(&mut interner, "x", int, 1)];
752 let laid_out = lay_out(&types, RecordKind::Struct, &members);
753 assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
754 let last = laid_out.fields[1];
755 assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
756 assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
757 }
758
759 #[test]
760 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
761 let mut types = Types::new();
762 let int = types.int(IntKind::Int);
763 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
764 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
765 assert_ne!(a, b);
766 }
767
768 #[test]
769 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
770 let mut types = Types::new();
773 let linux = linux();
774 let int = types.int(IntKind::Int);
775 let four = types.vector(int, 4);
776 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
777 let three = types.vector(int, 3);
778 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
779 let three_chars = types.vector(types.int(IntKind::Char), 3);
780 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
781 }
782
783 #[test]
784 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
785 let mut types = Types::new();
788 let linux = linux();
789 let void = types.void();
790 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
791 let int = types.int(IntKind::Int);
792 let function = types.function(FunctionType {
793 ret: int,
794 params: Vec::new(),
795 variadic: false,
796 prototyped: true,
797 });
798 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
799 let pointer_to_function = types.pointer(function);
800 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
801 }
802
803 #[test]
804 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
805 let types = Types::new();
806 let char_ = types.int(IntKind::Char);
807 let int = types.int(IntKind::Int);
808 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
809 assert_eq!(laid_out.layout, Layout::new(8, 4));
810 assert_eq!(offsets(&laid_out), [0, 32]);
811 assert_eq!(laid_out.fields[1].offset, 4);
812
813 let long_long = types.int(IntKind::LongLong);
815 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
816 assert_eq!(laid_out.layout, Layout::new(16, 8));
817 }
818
819 #[test]
820 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
821 let mut types = Types::new();
822 let char_ = types.int(IntKind::Char);
823 let int = types.int(IntKind::Int);
824 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
825 assert_eq!(laid_out.layout, Layout::new(4, 4));
826 assert_eq!(offsets(&laid_out), [0, 0]);
827
828 let nine = types.array(char_, ArrayLen::Fixed(9));
831 let short = types.int(IntKind::Short);
832 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
833 assert_eq!(laid_out.layout, Layout::new(10, 2));
834 }
835
836 #[test]
837 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
838 let mut interner = Interner::new();
841 let types = Types::new();
842 let char_ = types.int(IntKind::Char);
843 let int = types.int(IntKind::Int);
844 let long_long = types.int(IntKind::LongLong);
845
846 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
847 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
848 assert_eq!(laid_out.layout, Layout::new(4, 4));
849 assert_eq!(offsets(&laid_out), [0, 3]);
850
851 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
853 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
854 assert_eq!(laid_out.layout, Layout::new(8, 4));
855 assert_eq!(offsets(&laid_out), [0, 32]);
856
857 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
860 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
861 assert_eq!(laid_out.layout, Layout::new(8, 8));
862 assert_eq!(offsets(&laid_out), [0, 8]);
863
864 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
866 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
867 assert_eq!(offsets(&laid_out), [0, 8]);
868 }
869
870 #[test]
871 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
872 let types = Types::new();
873 let char_ = types.int(IntKind::Char);
874 let int = types.int(IntKind::Int);
875 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
876 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
877 assert_eq!(laid_out.layout, Layout::new(5, 1));
880 assert_eq!(offsets(&laid_out), [0, 32, 32]);
881 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
882
883 let trailing = [member(char_), unnamed_bits(int, 0)];
887 assert_eq!(lay_out(&types, RecordKind::Struct, &trailing).layout, Layout::new(4, 1));
888
889 let only = [unnamed_bits(int, 0)];
892 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
893 }
894
895 #[test]
896 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
897 let mut interner = Interner::new();
898 let types = Types::new();
899 let char_ = types.int(IntKind::Char);
900 let int = types.int(IntKind::Int);
901
902 let unnamed = [member(char_), unnamed_bits(int, 20)];
903 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
904 assert_eq!(unnamed.layout, Layout::new(4, 1));
905
906 let named = [member(char_), bits(&mut interner, "b", int, 20)];
907 let named = lay_out(&types, RecordKind::Struct, &named);
908 assert_eq!(named.layout, Layout::new(4, 4));
909 assert_eq!(offsets(&named), [0, 8], "the same place either way");
910
911 let wider = [member(char_), unnamed_bits(int, 30)];
914 let wider = lay_out(&types, RecordKind::Struct, &wider);
915 assert_eq!(wider.layout, Layout::new(8, 1));
916 assert_eq!(offsets(&wider), [0, 32]);
917 }
918
919 #[test]
920 fn aapcs64_lets_an_unnamed_bit_field_raise_the_records_alignment() {
921 let types = Types::new();
922 let char_ = types.int(IntKind::Char);
923 let uint = types.int(IntKind::UInt);
924
925 let fields = [member(char_), unnamed_bits(uint, 20)];
927 let arm = lay_out_on(&aapcs(), &types, RecordKind::Struct, &fields);
928 assert_eq!(arm.layout, Layout::new(4, 4));
929
930 let only = [unnamed_bits(uint, 0)];
933 assert_eq!(
934 lay_out_on(&aapcs(), &types, RecordKind::Struct, &only).layout,
935 Layout::new(0, 4)
936 );
937 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
938
939 let pushed = [member(char_), unnamed_bits(uint, 0), member(char_)];
942 let pushed = lay_out_on(&aapcs(), &types, RecordKind::Struct, &pushed);
943 assert_eq!(pushed.layout, Layout::new(8, 4));
944 assert_eq!(offsets(&pushed), [0, 32, 32]);
945 }
946
947 #[test]
948 fn windows_allocates_a_bit_field_into_a_unit_of_its_declared_type() {
949 let mut interner = Interner::new();
950 let types = Types::new();
951 let char_ = types.int(IntKind::Char);
952 let uint = types.int(IntKind::UInt);
953 let ushort = types.int(IntKind::UShort);
954 let longlong = types.int(IntKind::LongLong);
955
956 let then_member = [bits(&mut interner, "m0", uint, 3), member(char_)];
959 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &then_member);
960 assert_eq!(ms.layout, Layout::new(8, 4));
961 assert_eq!(offsets(&ms), [0, 32]);
962 let itanium = lay_out(&types, RecordKind::Struct, &then_member);
963 assert_eq!(itanium.layout, Layout::new(4, 4));
964 assert_eq!(offsets(&itanium), [0, 8]);
965
966 let narrower = [bits(&mut interner, "m0", uint, 3), bits(&mut interner, "m1", ushort, 5)];
968 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &narrower);
969 assert_eq!(ms.layout, Layout::new(8, 4));
970 assert_eq!(offsets(&ms), [0, 32]);
971 assert_eq!(lay_out(&types, RecordKind::Struct, &narrower).layout, Layout::new(4, 4));
972
973 let wide = [member(char_), bits(&mut interner, "b", longlong, 33)];
976 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &wide);
977 assert_eq!(ms.layout, Layout::new(16, 8));
978 assert_eq!(offsets(&ms), [0, 64]);
979 let itanium = lay_out(&types, RecordKind::Struct, &wide);
980 assert_eq!(itanium.layout, Layout::new(8, 8));
981 assert_eq!(offsets(&itanium), [0, 8]);
982 }
983
984 #[test]
985 fn microsofts_zero_width_bit_field_closes_a_unit_and_does_nothing_without_one() {
986 let mut interner = Interner::new();
987 let types = Types::new();
988 let char_ = types.int(IntKind::Char);
989 let uint = types.int(IntKind::UInt);
990
991 let alone = [member(char_), unnamed_bits(uint, 0)];
993 assert_eq!(
994 lay_out_on(&windows(), &types, RecordKind::Struct, &alone).layout,
995 Layout::new(1, 1)
996 );
997 assert_eq!(lay_out(&types, RecordKind::Struct, &alone).layout, Layout::new(4, 1));
998
999 let between = [
1001 bits(&mut interner, "m0", uint, 3),
1002 unnamed_bits(uint, 0),
1003 bits(&mut interner, "m1", uint, 5),
1004 member(char_),
1005 ];
1006 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &between);
1007 assert_eq!(ms.layout, Layout::new(12, 4));
1008 assert_eq!(offsets(&ms), [0, 32, 32, 64]);
1009 let itanium = lay_out(&types, RecordKind::Struct, &between);
1010 assert_eq!(itanium.layout, Layout::new(8, 4));
1011 assert_eq!(offsets(&itanium), [0, 32, 32, 40]);
1012 }
1013
1014 #[test]
1015 fn microsoft_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1016 let mut interner = Interner::new();
1017 let types = Types::new();
1018 let char_ = types.int(IntKind::Char);
1019 let uint = types.int(IntKind::UInt);
1020
1021 let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1024 assert_eq!(
1025 lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1026 Layout::new(4, 1)
1027 );
1028 assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1029 }
1030
1031 #[test]
1032 fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1033 let mut types = Types::new();
1034 let uint = types.int(IntKind::UInt);
1035 let mingw = target("x86_64-pc-windows-gnu");
1036
1037 let none: [FieldDecl; 0] = [];
1039 let zero_width = [unnamed_bits(uint, 0)];
1040 let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1041 for fields in [&none[..], &zero_width[..], &flexible[..]] {
1042 let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1043 assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1044 assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1045 assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1046 }
1047
1048 assert_eq!(windows().empty_record_size, 4);
1052 assert_eq!(mingw.empty_record_size, 0);
1053 }
1054
1055 #[test]
1056 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
1057 let mut interner = Interner::new();
1058 let types = Types::new();
1059 let char_ = types.int(IntKind::Char);
1060 let int = types.int(IntKind::Int);
1061 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1062
1063 let fields = [member(char_), member(int)];
1064 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1065 .expect("a packed struct of two complete members");
1066 assert_eq!(laid_out.layout, Layout::new(5, 1));
1067 assert_eq!(offsets(&laid_out), [0, 8]);
1068
1069 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1070 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1071 .expect("a packed struct with a bit-field");
1072 assert_eq!(laid_out.layout, Layout::new(5, 1));
1073 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1074
1075 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1078 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1079 .expect("a packed struct with a zero width bit-field");
1080 assert_eq!(laid_out.layout, Layout::new(5, 1));
1081 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1082 }
1083
1084 #[test]
1085 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1086 let mut interner = Interner::new();
1087 let types = Types::new();
1088 let char_ = types.int(IntKind::Char);
1089 let int = types.int(IntKind::Int);
1090 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1091
1092 let fields = [member(char_), member(int)];
1093 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1094 .expect("a packed struct of two complete members");
1095 assert_eq!(laid_out.layout, Layout::new(6, 2));
1096 assert_eq!(offsets(&laid_out), [0, 16]);
1097
1098 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1102 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1103 .expect("a packed struct with a bit-field");
1104 assert_eq!(laid_out.layout, Layout::new(6, 2));
1105 assert_eq!(offsets(&laid_out), [0, 8]);
1106
1107 let fields = [member(char_), unnamed_bits(int, 30)];
1110 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1111 .expect("a packed struct with an unnamed bit-field");
1112 assert_eq!(laid_out.layout, Layout::new(5, 1));
1113 }
1114
1115 #[test]
1116 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1117 let types = Types::new();
1118 let char_ = types.int(IntKind::Char);
1119 let int = types.int(IntKind::Int);
1120
1121 let aligned = FieldDecl { align: Some(16), ..member(int) };
1122 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1123 assert_eq!(laid_out.layout, Layout::new(32, 16));
1124 assert_eq!(offsets(&laid_out), [0, 128]);
1125
1126 let options = RecordOptions { packed: true, align: Some(4), pack: None };
1129 let fields = [member(char_), member(int)];
1130 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1131 .expect("a packed struct with an alignment asked for");
1132 assert_eq!(laid_out.layout, Layout::new(8, 4));
1133 assert_eq!(offsets(&laid_out), [0, 8]);
1134 }
1135
1136 #[test]
1137 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1138 let mut types = Types::new();
1140 let char_ = types.int(IntKind::Char);
1141 let int = types.int(IntKind::Int);
1142 let long_long = types.int(IntKind::LongLong);
1143
1144 let chars = types.array(char_, ArrayLen::Unknown);
1145 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1146 assert_eq!(laid_out.layout, Layout::new(4, 4));
1147 assert_eq!(offsets(&laid_out), [0, 32]);
1148
1149 let longs = types.array(long_long, ArrayLen::Unknown);
1151 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1152 assert_eq!(laid_out.layout, Layout::new(8, 8));
1153 assert_eq!(offsets(&laid_out), [0, 64]);
1154
1155 let fields = [member(chars), member(int)];
1157 let error =
1158 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1159 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1160 }
1161
1162 #[test]
1163 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1164 let types = Types::new();
1166 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1167 assert_eq!(laid_out.layout, Layout::new(0, 1));
1168 }
1169
1170 #[test]
1171 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1172 let types = Types::new();
1173 let int = types.int(IntKind::Int);
1174 let fields = [unnamed_bits(int, 33)];
1175 let error =
1176 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1177 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1178 assert_eq!(error, Err(want));
1179 }
1180
1181 #[test]
1182 fn a_record_reports_its_members_once_it_has_been_completed() {
1183 let mut interner = Interner::new();
1184 let mut types = Types::new();
1185 let char_ = types.int(IntKind::Char);
1186 let int = types.int(IntKind::Int);
1187 let name = interner.intern("count");
1188 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1189 let id = types.declare_record(RecordKind::Struct, None);
1190 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1191 types.complete_record(id, laid_out);
1192 let ty = types.record(id);
1193 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1194 let field = types.field(id, name).expect("the member that was declared");
1195 assert_eq!(field.offset, 4);
1196 assert!(!field.is_bit_field());
1197 assert_eq!(types.field(id, interner.intern("missing")), None);
1198 }
1199
1200 #[test]
1201 fn a_nested_record_brings_its_own_alignment_with_it() {
1202 let mut types = Types::new();
1203 let char_ = types.int(IntKind::Char);
1204 let int = types.int(IntKind::Int);
1205 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1206 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1207 assert_eq!(laid_out.layout, Layout::new(8, 4));
1208 assert_eq!(offsets(&laid_out), [0, 32]);
1209
1210 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1213 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1214 assert_eq!(laid_out.layout, Layout::new(12, 4));
1215 assert_eq!(offsets(&laid_out), [0, 32]);
1216 }
1217
1218 #[test]
1219 fn everything_narrower_than_an_int_promotes_to_one() {
1220 let mut types = Types::new();
1224 let linux = linux();
1225 let int = types.int(IntKind::Int);
1226 let narrow =
1227 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1228 for kind in narrow {
1229 let ty = types.int(kind);
1230 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1231 }
1232 let boolean = types.boolean();
1233 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1234
1235 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1237 let ty = types.int(kind);
1238 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1239 }
1240 }
1241
1242 #[test]
1243 fn a_bit_int_is_not_promoted_at_all() {
1244 let mut types = Types::new();
1247 let linux = linux();
1248 let small = types.bit_int(true, 8);
1249 assert_eq!(promote(&mut types, small, &linux), small);
1250 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1251 }
1252
1253 #[test]
1254 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1255 let mut types = Types::new();
1256 let linux = linux();
1257 let int = types.int(IntKind::Int);
1258 let uint = types.int(IntKind::UInt);
1259 let ullong = types.int(IntKind::ULongLong);
1260
1261 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1263 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1265 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1267 let forty = types.bit_int(false, 40);
1272 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1273 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1275 }
1276
1277 #[test]
1278 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1279 let mut types = Types::new();
1280 let linux = linux();
1281 let int = types.int(IntKind::Int);
1282 let short = types.int(IntKind::Short);
1283 let uint = types.int(IntKind::UInt);
1284
1285 let fixed = types.declare_enum(None);
1287 types.complete_enum(fixed, short, true);
1288 let fixed = types.enumeration(fixed);
1289 assert_eq!(promote(&mut types, fixed, &linux), int);
1290
1291 let unsigned = types.declare_enum(None);
1294 types.complete_enum(unsigned, uint, false);
1295 let unsigned = types.enumeration(unsigned);
1296 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1297
1298 let undecided = types.declare_enum(None);
1301 let undecided = types.enumeration(undecided);
1302 assert_eq!(promote(&mut types, undecided, &linux), int);
1303 }
1304
1305 #[test]
1306 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1307 let mut types = Types::new();
1310 let linux = linux();
1311 let int = types.int(IntKind::Int);
1312 let konst = types.qualified(int, Qualifiers::CONST);
1313 let atomic = types.atomic(konst);
1314 assert_eq!(promote(&mut types, atomic, &linux), int);
1315 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1316 }
1317
1318 #[test]
1319 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1320 let mut types = Types::new();
1322 let linux = linux();
1323 let cases = [
1324 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1325 (IntKind::Int, IntKind::Long, IntKind::Long),
1326 (IntKind::UInt, IntKind::Long, IntKind::Long),
1327 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1328 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1329 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1330 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1331 (IntKind::Char, IntKind::Char, IntKind::Int),
1332 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1333 ];
1334 for (left, right, want) in cases {
1335 let left = types.int(left);
1336 let right = types.int(right);
1337 let want = types.int(want);
1338 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1339 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1340 }
1341 }
1342
1343 #[test]
1344 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1345 let mut types = Types::new();
1349 let linux = linux();
1350 let signed = types.int(IntKind::Int128);
1351 let unsigned = types.int(IntKind::UInt128);
1352 for id in [signed, unsigned] {
1353 let laid_out = layout(&types, id, &linux).expect("a complete type");
1354 assert_eq!(laid_out.size, 16);
1355 assert_eq!(laid_out.align, 16);
1356 }
1357
1358 let ull = types.int(IntKind::ULongLong);
1362 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1363 assert_eq!(promote(&mut types, signed, &linux), signed);
1365 }
1366
1367 #[test]
1368 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1369 let mut types = Types::new();
1372 let linux = linux();
1373 let int128 = types.int(IntKind::Int128);
1374 let bit_int = types.bit_int(true, 128);
1375 assert_ne!(int128, bit_int);
1376 assert!(!compatible(&types, int128, bit_int));
1377 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1378 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1379 }
1380
1381 #[test]
1382 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1383 let mut types = Types::new();
1387 let linux = linux();
1388 let ulong = types.int(IntKind::ULong);
1389 let long_long = types.int(IntKind::LongLong);
1390 let want = types.int(IntKind::ULongLong);
1391 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1392
1393 let windows = target("x86_64-pc-windows-msvc");
1397 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1398 }
1399
1400 #[test]
1401 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1402 let mut types = Types::new();
1404 let linux = linux();
1405 let b40 = types.bit_int(true, 40);
1406 let ub40 = types.bit_int(false, 40);
1407 let b8 = types.bit_int(true, 8);
1408 let b32 = types.bit_int(true, 32);
1409 let int = types.int(IntKind::Int);
1410 let uint = types.int(IntKind::UInt);
1411 let long = types.int(IntKind::Long);
1412 let char_ = types.int(IntKind::Char);
1413
1414 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1416 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1418 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1420 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1421 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1424 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1427 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1428 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1430 }
1431
1432 #[test]
1433 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1434 let mut types = Types::new();
1435 let linux = linux();
1436 let float = types.float(FloatKind::Float);
1437 let double = types.float(FloatKind::Double);
1438 let long_double = types.float(FloatKind::LongDouble);
1439 let ullong = types.int(IntKind::ULongLong);
1440 let int = types.int(IntKind::Int);
1441
1442 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1443 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1444 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1445 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1448 }
1449
1450 #[test]
1451 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1452 let mut types = Types::new();
1453 let linux = linux();
1454 let int = types.int(IntKind::Int);
1455 let float = types.float(FloatKind::Float);
1456 let short = types.int(IntKind::Short);
1457
1458 let four_ints = types.vector(int, 4);
1460 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1461
1462 let uint = types.int(IntKind::UInt);
1465 let four_uints = types.vector(uint, 4);
1466 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1467
1468 let four_floats = types.vector(float, 4);
1471 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1472
1473 let two_shorts = types.vector(short, 2);
1475 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1476
1477 assert_eq!(mask_of(&mut types, int, &linux), None);
1479 }
1480
1481 #[test]
1482 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1483 let mut types = Types::new();
1484 let linux = linux();
1485 let int = types.int(IntKind::Int);
1486 let uint = types.int(IntKind::UInt);
1487 let float = types.float(FloatKind::Float);
1488 let short = types.int(IntKind::Short);
1489
1490 let four_ints = types.vector(int, 4);
1491 let four_uints = types.vector(uint, 4);
1492 let four_floats = types.vector(float, 4);
1493 let eight_shorts = types.vector(short, 8);
1494 let two_ints = types.vector(int, 2);
1495
1496 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1499 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1501 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1503 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1505
1506 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1509 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1511 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1513 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1514 }
1515
1516 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1521 let mut types = Types::new();
1522 let left = types.float(a);
1523 let right = types.float(b);
1524 let want = types.float(expected);
1525 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1526 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1527 }
1528
1529 #[test]
1530 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1531 let x86 = linux();
1535 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1536 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1537 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1538 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1539 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1540 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1541 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1542 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1543 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1544 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1545 }
1546
1547 #[test]
1548 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1549 let mac = target("aarch64-apple-darwin");
1553 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1554 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1555 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1556 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1557 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1558 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1559 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1560 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1563 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1564 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1565 }
1566
1567 #[test]
1568 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1569 let mut types = Types::new();
1570 let linux = linux();
1571 let cfloat = types.complex(FloatKind::Float);
1572 let cdouble = types.complex(FloatKind::Double);
1573 let cldouble = types.complex(FloatKind::LongDouble);
1574 let double = types.float(FloatKind::Double);
1575 let long_double = types.float(FloatKind::LongDouble);
1576 let float = types.float(FloatKind::Float);
1577 let int = types.int(IntKind::Int);
1578
1579 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1580 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1581 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1582 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1583 }
1584
1585 #[test]
1586 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1587 let mut types = Types::new();
1589 let linux = linux();
1590 let int = types.int(IntKind::Int);
1591 let pointer = types.pointer(int);
1592 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1593 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1594 let void = types.void();
1595 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1596 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1599 }
1600
1601 #[test]
1602 fn the_conversions_read_through_sugar() {
1603 let mut interner = Interner::new();
1604 let mut types = Types::new();
1605 let linux = linux();
1606 let char_ = types.int(IntKind::Char);
1607 let name = types.typedef(interner.intern("byte"), char_);
1608 let int = types.int(IntKind::Int);
1609 assert_eq!(promote(&mut types, name, &linux), int);
1610 }
1611
1612 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1614 let ret = types.void();
1615 types.function(FunctionType { ret, params, variadic, prototyped: true })
1616 }
1617
1618 fn old_style(types: &mut Types) -> TypeId {
1620 let ret = types.void();
1621 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1622 }
1623
1624 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1626 let id = types.declare_record(RecordKind::Struct, Some(tag));
1627 let laid_out = lay_out(types, RecordKind::Struct, fields);
1628 types.complete_record(id, laid_out);
1629 id
1630 }
1631
1632 #[test]
1633 fn a_type_is_compatible_with_itself_however_it_was_written() {
1634 let mut interner = Interner::new();
1635 let mut types = Types::new();
1636 let int = types.int(IntKind::Int);
1637 let name = types.typedef(interner.intern("int32_t"), int);
1638 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1639 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1640
1641 let konst = types.qualified(int, Qualifiers::CONST);
1644 assert!(!compatible(&types, konst, int));
1645 let konst_pointer = types.pointer(konst);
1646 let pointer = types.pointer(int);
1647 assert!(!compatible(&types, konst_pointer, pointer));
1648 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1649
1650 let char_ = types.int(IntKind::Char);
1653 let schar = types.int(IntKind::SChar);
1654 assert!(!compatible(&types, char_, schar));
1655 let atomic = types.atomic(int);
1657 assert!(!compatible(&types, atomic, int));
1658 }
1659
1660 #[test]
1661 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1662 let mut types = Types::new();
1665 let uint = types.int(IntKind::UInt);
1666 let int = types.int(IntKind::Int);
1667 let id = types.declare_enum(None);
1668 types.complete_enum(id, uint, false);
1669 let e = types.enumeration(id);
1670 assert!(compatible(&types, e, uint));
1671 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1672 assert!(!compatible(&types, e, int));
1673
1674 let other = types.declare_enum(None);
1677 types.complete_enum(other, uint, false);
1678 let other = types.enumeration(other);
1679 assert!(!compatible(&types, e, other));
1680
1681 let undecided = types.declare_enum(None);
1684 let undecided = types.enumeration(undecided);
1685 assert!(!compatible(&types, undecided, uint));
1686 assert!(compatible(&types, undecided, undecided));
1687 }
1688
1689 #[test]
1690 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1691 let mut types = Types::new();
1694 let int = types.int(IntKind::Int);
1695 let unknown = types.array(int, ArrayLen::Unknown);
1696 let four = types.array(int, ArrayLen::Fixed(4));
1697 let five = types.array(int, ArrayLen::Fixed(5));
1698 assert!(compatible(&types, unknown, four));
1699 assert!(!compatible(&types, four, five));
1700 assert_eq!(composite(&mut types, unknown, four), Some(four));
1701 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1702 assert_eq!(composite(&mut types, four, five), None);
1703
1704 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1707 assert!(compatible(&types, vla, four));
1708 assert_eq!(composite(&mut types, vla, four), Some(four));
1709
1710 let long = types.int(IntKind::Long);
1712 let longs = types.array(long, ArrayLen::Fixed(4));
1713 assert!(!compatible(&types, four, longs));
1714 }
1715
1716 #[test]
1717 fn a_parameter_declared_as_an_array_is_a_pointer() {
1718 let mut types = Types::new();
1722 let int = types.int(IntKind::Int);
1723 let three = types.array(int, ArrayLen::Fixed(3));
1724 let pointer = types.pointer(int);
1725 assert_eq!(adjust_parameter(&mut types, three), pointer);
1726
1727 let function = prototype(&mut types, vec![int], false);
1729 let function_pointer = types.pointer(function);
1730 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1731
1732 let konst = types.qualified(int, Qualifiers::CONST);
1735 assert_eq!(adjust_parameter(&mut types, konst), int);
1736 let to_konst = types.pointer(konst);
1737 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1738 }
1739
1740 #[test]
1741 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1742 let mut types = Types::new();
1746 let old = old_style(&mut types);
1747 let int = types.int(IntKind::Int);
1748 let long = types.int(IntKind::Long);
1749 let char_ = types.int(IntKind::Char);
1750 let float = types.float(FloatKind::Float);
1751 let double = types.float(FloatKind::Double);
1752
1753 let takes_int = prototype(&mut types, vec![int], false);
1754 assert!(compatible(&types, old, takes_int));
1755 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1756 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1758
1759 let pointer = types.pointer(int);
1760 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1761 let ty = prototype(&mut types, params, false);
1762 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1763 }
1764
1765 for params in [vec![char_], vec![float], vec![int, char_]] {
1768 let ty = prototype(&mut types, params, false);
1769 assert!(!compatible(&types, old, ty));
1770 assert_eq!(composite(&mut types, old, ty), None);
1771 }
1772
1773 let variadic = prototype(&mut types, vec![int], true);
1775 assert!(!compatible(&types, old, variadic));
1776
1777 let uint = types.int(IntKind::UInt);
1779 let id = types.declare_enum(None);
1780 types.complete_enum(id, uint, false);
1781 let e = types.enumeration(id);
1782 let takes_enum = prototype(&mut types, vec![e], false);
1783 assert!(compatible(&types, old, takes_enum));
1784
1785 assert!(compatible(&types, old, old));
1787
1788 let returns_int = types.function(FunctionType {
1790 ret: int,
1791 params: Vec::new(),
1792 variadic: false,
1793 prototyped: false,
1794 });
1795 assert!(!compatible(&types, returns_int, takes_int));
1796 }
1797
1798 #[test]
1799 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1800 let mut types = Types::new();
1804 let int = types.int(IntKind::Int);
1805 let takes_int = prototype(&mut types, vec![int], false);
1806 let takes_nothing = prototype(&mut types, Vec::new(), false);
1807 let old = old_style(&mut types);
1808 assert!(!compatible(&types, takes_nothing, takes_int));
1809 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1810 }
1811
1812 #[test]
1813 fn two_prototypes_have_to_agree_about_everything() {
1814 let mut types = Types::new();
1815 let int = types.int(IntKind::Int);
1816 let long = types.int(IntKind::Long);
1817 let base = prototype(&mut types, vec![int, int], false);
1818 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1819 let other = prototype(&mut types, other, false);
1820 assert!(!compatible(&types, base, other));
1821 }
1822 let variadic = prototype(&mut types, vec![int, int], true);
1823 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1824
1825 let four = types.array(int, ArrayLen::Fixed(4));
1828 let unknown = types.array(int, ArrayLen::Unknown);
1829 let to_four = types.pointer(four);
1830 let to_unknown = types.pointer(unknown);
1831 let a = prototype(&mut types, vec![to_four], false);
1832 let b = prototype(&mut types, vec![to_unknown], false);
1833 assert!(compatible(&types, a, b));
1834 assert_eq!(composite(&mut types, a, b), Some(a));
1836 }
1837
1838 #[test]
1839 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1840 let mut types = Types::new();
1841 let int = types.int(IntKind::Int);
1842 let four = types.array(int, ArrayLen::Fixed(4));
1843 let unknown = types.array(int, ArrayLen::Unknown);
1844 let to_four = types.pointer(four);
1845 let to_unknown = types.pointer(unknown);
1846 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1847
1848 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1850 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1851 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1852 }
1853
1854 #[test]
1855 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1856 let mut interner = Interner::new();
1860 let mut types = Types::new();
1861 let tag = interner.intern("point");
1862 let x = interner.intern("x");
1863 let y = interner.intern("y");
1864 let int = types.int(IntKind::Int);
1865 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1866
1867 let first = tagged(&mut types, tag, &members);
1868 let second = tagged(&mut types, tag, &members);
1869 let first = types.record(first);
1870 let second = types.record(second);
1871 assert_ne!(first, second, "still two declarations and two types");
1872 assert!(compatible(&types, first, second));
1873
1874 let z = interner.intern("z");
1877 let long = types.int(IntKind::Long);
1878 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1879 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1880 for other in [&renamed[..], &retyped[..], &members[..1]] {
1881 let other = tagged(&mut types, tag, other);
1882 let other = types.record(other);
1883 assert!(!compatible(&types, first, other));
1884 }
1885 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1886 let elsewhere = types.record(elsewhere);
1887 assert!(!compatible(&types, first, elsewhere));
1888
1889 let anonymous = record(&mut types, RecordKind::Struct, &members);
1892 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1893 assert!(!compatible(&types, anonymous, also_anonymous));
1894
1895 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1897 let incomplete = types.record(incomplete);
1898 assert!(!compatible(&types, first, incomplete));
1899 assert!(compatible(&types, incomplete, incomplete));
1900 }
1901
1902 #[test]
1903 fn a_self_referential_record_is_compared_without_going_round_forever() {
1904 let mut interner = Interner::new();
1908 let mut types = Types::new();
1909 let tag = interner.intern("node");
1910 let value = interner.intern("value");
1911 let next = interner.intern("next");
1912 let int = types.int(IntKind::Int);
1913
1914 let node = |types: &mut Types| {
1915 let id = types.declare_record(RecordKind::Struct, Some(tag));
1916 let ty = types.record(id);
1917 let pointer = types.pointer(ty);
1918 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1919 let laid_out = lay_out(types, RecordKind::Struct, &members);
1920 types.complete_record(id, laid_out);
1921 ty
1922 };
1923 let first = node(&mut types);
1924 let second = node(&mut types);
1925 assert_ne!(first, second);
1926 assert!(compatible(&types, first, second));
1927
1928 let id = types.declare_record(RecordKind::Struct, Some(tag));
1931 let ty = types.record(id);
1932 let pointer = types.pointer(ty);
1933 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1934 let laid_out = lay_out(&types, RecordKind::Struct, &members);
1935 types.complete_record(id, laid_out);
1936 assert!(!compatible(&types, first, ty));
1937 }
1938
1939 #[test]
1940 fn layout_reads_through_sugar() {
1941 let mut interner = Interner::new();
1942 let mut types = Types::new();
1943 let long = types.int(IntKind::Long);
1944 let name = types.typedef(interner.intern("word"), long);
1945 let array = types.array(name, ArrayLen::Fixed(4));
1946 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1947 }
1948}