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