1#![doc(html_root_url = "https://docs.rs/rucc-types/0.10.78")]
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, align, float_format, float_width, int_width, integer_info,
110 layout,
111};
112pub use crate::print::{declare, spell};
113pub use crate::record::{
114 Extent, Field, FieldDecl, RecordError, RecordLayout, RecordOptions, VariableLayout,
115 layout_record,
116};
117pub use crate::types::{Alias, EnumInfo, Enumerator, RecordInfo, TypeId, Types};
118
119pub const MILESTONE: &str = "M2";
121
122#[cfg(test)]
123mod tests {
124 use std::num::NonZeroU32;
125
126 use rucc_base::{Interner, Symbol};
127 use rucc_target::{TargetInfo, Triple};
128
129 use super::*;
130
131 fn target(triple: &str) -> TargetInfo {
132 TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
133 }
134
135 fn linux() -> TargetInfo {
136 target("x86_64-unknown-linux-gnu")
137 }
138
139 fn windows() -> TargetInfo {
143 target("x86_64-pc-windows-msvc")
144 }
145
146 fn aapcs() -> TargetInfo {
150 target("aarch64-unknown-linux-gnu")
151 }
152
153 fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
155 lay_out_on(&linux(), types, kind, fields)
156 }
157
158 fn lay_out_on(
160 target: &TargetInfo,
161 types: &Types,
162 kind: RecordKind,
163 fields: &[FieldDecl],
164 ) -> RecordLayout {
165 layout_record(types, kind, fields, &RecordOptions::default(), target)
166 .expect("a record every member of which has a layout")
167 }
168
169 fn offsets(laid_out: &RecordLayout) -> Vec<u128> {
172 laid_out.fields.iter().map(Field::bit_offset).collect()
173 }
174
175 fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
177 let id = types.declare_record(kind, None);
178 let laid_out = lay_out(types, kind, fields);
179 types.complete_record(id, laid_out);
180 types.record(id)
181 }
182
183 fn member(ty: TypeId) -> FieldDecl {
185 FieldDecl::new(None, ty)
186 }
187
188 fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
191 FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
192 }
193
194 fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
196 FieldDecl::bit_field(None, ty, width)
197 }
198
199 #[test]
200 fn milestone_is_recorded() {
201 assert!(MILESTONE.starts_with('M'));
202 }
203
204 #[test]
205 fn an_integer_type_answers_with_the_width_of_its_value_and_not_of_its_object() {
206 let mut interner = Interner::new();
207 let mut types = Types::new();
208 let target = linux();
209
210 let boolean = types.boolean();
213 let bits = types.bit_int(true, 37);
214 let short = types.int(IntKind::Short);
216 let alias = types.typedef(interner.intern("word"), short);
217 let unsigned_char = types.int(IntKind::UChar);
218 let atomic = types.atomic(unsigned_char);
219
220 let shape = |ty| integer_info(&types, ty, &target).expect("an integer type");
221 assert_eq!(shape(boolean), IntegerInfo::new(false, 1));
222 assert_eq!(shape(bits), IntegerInfo::new(true, 37));
223 assert_eq!(shape(types.int(IntKind::Int)), IntegerInfo::new(true, 32));
224 assert_eq!(shape(types.int(IntKind::ULong)), IntegerInfo::new(false, 64));
225 assert_eq!(shape(alias), IntegerInfo::new(true, 16));
226 assert_eq!(shape(atomic), IntegerInfo::new(false, 8));
227
228 assert_eq!(integer_info(&types, types.float(FloatKind::Double), &target), None);
229 }
230
231 #[test]
232 fn an_enumeration_answers_with_the_type_the_enumerators_are_kept_in() {
233 let mut interner = Interner::new();
234 let mut types = Types::new();
235 let target = linux();
236
237 let colour = types.declare_enum(Some(interner.intern("colour")));
240 let ty = types.enumeration(colour);
241 assert_eq!(integer_info(&types, ty, &target), None);
242
243 let underlying = types.int(IntKind::ULong);
244 types.complete_enum(colour, underlying, true);
245 assert_eq!(integer_info(&types, ty, &target), Some(IntegerInfo::new(false, 64)));
246 }
247
248 #[test]
249 fn a_value_stored_in_an_integer_type_keeps_the_bits_the_type_has_room_for() {
250 let char_type = IntegerInfo::new(true, 8);
251 assert_eq!(char_type.wrap(300), 44);
252 assert!(!char_type.holds(300));
253 assert!(char_type.holds(-128));
254
255 assert_eq!(IntegerInfo::new(false, 32).wrap(-1), 4_294_967_295);
256 assert_eq!(IntegerInfo::new(false, 8).wrap(-1), 255);
257
258 assert!(IntegerInfo::new(false, 128).holds(i128::MIN));
261 assert!(IntegerInfo::new(true, 128).holds(i128::MIN));
262 assert_eq!(IntegerInfo::new(true, 128).wrap(i128::MAX), i128::MAX);
263 }
264
265 #[test]
266 fn a_long_double_has_a_format_the_size_does_not_give_away() {
267 let target = linux();
268 assert_eq!(float_width(FloatKind::LongDouble, &target), 128);
271 assert_eq!(
272 float_format(FloatKind::LongDouble, &target),
273 rucc_base::float::Format::X87Extended
274 );
275 assert_eq!(float_format(FloatKind::Float, &target), rucc_base::float::Format::Single);
276 }
277
278 #[test]
279 fn an_interchange_type_names_a_format_and_an_extended_one_names_the_target() {
280 use rucc_base::float::Format;
281
282 for target in [&linux(), &target("aarch64-apple-darwin")] {
285 assert_eq!(float_format(FloatKind::Float16, target), Format::Half);
286 assert_eq!(float_format(FloatKind::Float32, target), Format::Single);
287 assert_eq!(float_format(FloatKind::Float64, target), Format::Double);
288 assert_eq!(float_format(FloatKind::Float128, target), Format::Quad);
289 assert_eq!(float_width(FloatKind::Float16, target), 16);
290 assert_eq!(float_width(FloatKind::Float32, target), 32);
291 assert_eq!(float_width(FloatKind::Float64, target), 64);
292 assert_eq!(float_width(FloatKind::Float128, target), 128);
293 assert_eq!(float_format(FloatKind::Float32x, target), Format::Double);
295 }
296
297 let x86 = linux();
301 assert_eq!(float_format(FloatKind::Float64x, &x86), Format::X87Extended);
302 assert_eq!(float_format(FloatKind::LongDouble, &x86), Format::X87Extended);
303 let mac = target("aarch64-apple-darwin");
304 assert_eq!(float_format(FloatKind::Float64x, &mac), Format::Quad);
305 assert_eq!(float_format(FloatKind::LongDouble, &mac), Format::Double);
306 assert_eq!(float_width(FloatKind::Float64x, &x86), 128);
309 assert_eq!(float_width(FloatKind::Float64x, &mac), 128);
310 }
311
312 #[test]
313 fn every_floating_type_is_as_wide_as_the_format_it_is_stored_in() {
314 let types = Types::new();
315 let sizes = |target: &TargetInfo| -> Vec<(u64, u64)> {
316 FloatKind::ALL
317 .iter()
318 .map(|&kind| {
319 let found = layout(&types, types.float(kind), target).expect("a complete type");
320 (found.size, found.align)
321 })
322 .collect()
323 };
324 assert_eq!(
328 sizes(&linux()),
329 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16), (16, 16)]
330 );
331 assert_eq!(
332 sizes(&target("aarch64-apple-darwin")),
333 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16)]
334 );
335 }
336
337 #[test]
338 fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
339 let types = Types::new();
342 let mut seen = Vec::new();
343 for kind in FloatKind::ALL {
344 seen.push(types.float(kind));
345 }
346 let mut sorted = seen.clone();
347 sorted.sort_unstable();
348 sorted.dedup();
349 assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
350
351 let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
352 assert_eq!(
353 names,
354 [
355 "_Float16",
356 "float",
357 "_Float32",
358 "double",
359 "_Float32x",
360 "_Float64",
361 "long double",
362 "_Float64x",
363 "_Float128",
364 ]
365 );
366 }
367
368 #[test]
369 fn the_same_type_asked_for_twice_is_the_same_id() {
370 let mut types = Types::new();
371 let a = types.pointer(types.int(IntKind::Int));
372 let b = types.pointer(types.int(IntKind::Int));
373 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
374 let c = types.pointer(types.int(IntKind::Long));
375 assert_ne!(a, c);
376 }
377
378 #[test]
379 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
380 let mut types = Types::new();
381 let int = types.int(IntKind::Int);
382 let konst = types.qualified(int, Qualifiers::CONST);
383 assert_ne!(int, konst);
384 assert_eq!(types.kind(konst), types.kind(int));
385 assert!(types.quals(konst).has(Qualifiers::CONST));
386 assert_eq!(types.unqualified(konst), int);
387 }
388
389 #[test]
390 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
391 let mut types = Types::new();
392 let int = types.int(IntKind::Int);
393 let a = types.qualified(int, Qualifiers::CONST);
394 let a = types.qualified(a, Qualifiers::VOLATILE);
395 let b = types.qualified(int, Qualifiers::VOLATILE);
396 let b = types.qualified(b, Qualifiers::CONST);
397 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
398 }
399
400 #[test]
401 fn qualifying_an_array_qualifies_its_element() {
402 let mut types = Types::new();
405 let int = types.int(IntKind::Int);
406 let array = types.array(int, ArrayLen::Fixed(4));
407 let konst = types.qualified(array, Qualifiers::CONST);
408 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
409 let TypeKind::Array { elem, len } = types.kind(konst) else {
410 panic!("still an array");
411 };
412 assert_eq!(len, ArrayLen::Fixed(4));
413 assert!(types.quals(elem).has(Qualifiers::CONST));
414 }
415
416 #[test]
417 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
418 let mut interner = Interner::new();
419 let mut types = Types::new();
420 let int = types.int(IntKind::Int);
421 let name = types.typedef(interner.intern("int32_t"), int);
422 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
423 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
424 assert!(types.is_sugar(name));
425 assert!(!types.is_sugar(int));
426 }
427
428 #[test]
434 fn a_typedef_name_is_recorded_without_making_a_type_of_its_own() {
435 let mut interner = Interner::new();
436 let mut types = Types::new();
437 let int = types.int(IntKind::Int);
438 types.alias(interner.intern("int32_t"), int);
439 types.alias(interner.intern("word"), int);
440 types.alias(interner.intern("int32_t"), int);
441 let names: Vec<_> =
442 types.aliases().iter().map(|had| interner.resolve(had.name).to_owned()).collect();
443 assert_eq!(names, ["int32_t", "word"], "the same name twice is one entry");
444 assert!(types.aliases().iter().all(|had| had.of == int));
445 assert_eq!(types.int(IntKind::Int), int, "and the type is the type it was");
446 }
447
448 #[test]
449 fn sugar_below_the_outermost_node_is_resolved_too() {
450 let mut interner = Interner::new();
453 let mut types = Types::new();
454 let int = types.int(IntKind::Int);
455 let name = types.typedef(interner.intern("int32_t"), int);
456 let sugar_pointer = types.pointer(name);
457 let plain_pointer = types.pointer(int);
458 assert_ne!(sugar_pointer, plain_pointer);
459 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
460
461 let sugar_array = types.array(name, ArrayLen::Fixed(3));
462 let plain_array = types.array(int, ArrayLen::Fixed(3));
463 assert_eq!(types.canonical(sugar_array), plain_array);
464 }
465
466 #[test]
467 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
468 let mut interner = Interner::new();
469 let mut types = Types::new();
470 let int = types.int(IntKind::Int);
471 let mut current = int;
472 for i in 0..8 {
473 current = types.typedef(interner.intern(&format!("t{i}")), current);
474 }
475 assert_eq!(types.canonical(current), int);
476 }
477
478 #[test]
479 fn a_typedef_that_asked_for_an_alignment_says_what_it_is_and_not_what_it_is_at_least() {
480 let mut interner = Interner::new();
485 let mut types = Types::new();
486 let target = linux();
487 let int = types.int(IntKind::Int);
488 let low = types.aligned_typedef(interner.intern("L"), int, NonZeroU32::new(2).unwrap());
489 let high = types.aligned_typedef(interner.intern("H"), int, NonZeroU32::new(16).unwrap());
490
491 assert_eq!(layout(&types, low, &target), Ok(Layout::new(4, 2)));
492 assert_eq!(layout(&types, high, &target), Ok(Layout::new(4, 16)));
493 assert_eq!(layout(&types, int, &target), Ok(Layout::new(4, 4)));
496
497 assert_ne!(low, high);
500
501 let outer = types.aligned_typedef(interner.intern("M"), low, NonZeroU32::new(8).unwrap());
504 assert_eq!(types.align_override(outer), NonZeroU32::new(8));
505 let plain = types.typedef(interner.intern("N"), low);
506 assert_eq!(types.align_override(plain), NonZeroU32::new(2));
507 assert_eq!(types.align_override(int), None);
509 }
510
511 #[test]
512 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
513 let mut interner = Interner::new();
514 let mut types = Types::new();
515 let int = types.int(IntKind::Int);
516 let name = types.typedef(interner.intern("int32_t"), int);
517 let konst = types.qualified(name, Qualifiers::CONST);
518 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
519 let want = types.qualified(int, Qualifiers::CONST);
520 assert_eq!(types.canonical(konst), want);
521 }
522
523 #[test]
524 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
525 let mut interner = Interner::new();
528 let mut types = Types::new();
529 let int = types.int(IntKind::Int);
530 let array = types.array(int, ArrayLen::Fixed(4));
531 let name = types.typedef(interner.intern("A"), array);
532 let konst = types.qualified(name, Qualifiers::CONST);
533 let konst_int = types.qualified(int, Qualifiers::CONST);
534 let want = types.array(konst_int, ArrayLen::Fixed(4));
535 assert_eq!(types.canonical(konst), want);
536 }
537
538 #[test]
539 fn a_function_type_is_deduplicated_by_its_signature() {
540 let mut types = Types::new();
541 let int = types.int(IntKind::Int);
542 let long = types.int(IntKind::Long);
543 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
544 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
545 };
546 let a = make(&mut types, vec![int, long], false);
547 let b = make(&mut types, vec![int, long], false);
548 assert_eq!(a, b);
549 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
550 assert_ne!(a, make(&mut types, vec![long, int], false));
551 }
552
553 #[test]
554 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
555 let mut interner = Interner::new();
556 let mut types = Types::new();
557 let int = types.int(IntKind::Int);
558 let name = types.typedef(interner.intern("int32_t"), int);
559 let sugar = types.function(FunctionType {
560 ret: name,
561 params: vec![name],
562 variadic: false,
563 prototyped: true,
564 });
565 let plain = types.function(FunctionType {
566 ret: int,
567 params: vec![int],
568 variadic: false,
569 prototyped: true,
570 });
571 assert_ne!(sugar, plain);
572 assert_eq!(types.canonical(sugar), plain);
573 }
574
575 #[test]
576 fn a_record_is_its_declaration_and_not_its_members() {
577 let mut interner = Interner::new();
581 let mut types = Types::new();
582 let tag = interner.intern("point");
583 let first = types.declare_record(RecordKind::Struct, Some(tag));
584 let second = types.declare_record(RecordKind::Struct, Some(tag));
585 assert_ne!(types.record(first), types.record(second));
586 assert_eq!(types.record(first), types.record(first));
587 }
588
589 #[test]
590 fn a_record_has_no_layout_until_it_has_been_completed() {
591 let mut types = Types::new();
592 let id = types.declare_record(RecordKind::Struct, None);
593 let ty = types.record(id);
594 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
595 let long_long = types.int(IntKind::LongLong);
596 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
597 types.complete_record(id, laid_out);
598 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
599 }
600
601 #[test]
602 fn an_enum_takes_the_layout_of_its_underlying_type() {
603 let mut types = Types::new();
604 let id = types.declare_enum(None);
605 let ty = types.enumeration(id);
606 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
607 let int = types.int(IntKind::Int);
608 types.complete_enum(id, int, false);
609 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
610 }
611
612 #[test]
613 fn the_scalar_widths_come_from_the_target() {
614 let mut types = Types::new();
615 let linux = linux();
616 let windows = target("x86_64-pc-windows-msvc");
617 let darwin = target("aarch64-apple-darwin");
618
619 let long = types.int(IntKind::Long);
620 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
621 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
622
623 let ldouble = types.float(FloatKind::LongDouble);
624 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
625 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
626
627 let pointer = types.pointer(types.void());
628 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
629
630 let boolean = types.boolean();
631 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
632 }
633
634 #[test]
635 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
636 let mut types = Types::new();
639 let linux = linux();
640 let cfloat = types.complex_float(FloatKind::Float);
641 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
642 let cdouble = types.complex_float(FloatKind::Double);
643 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
644 let cldouble = types.complex_float(FloatKind::LongDouble);
645 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
646 let darwin = target("aarch64-apple-darwin");
647 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
648 }
649
650 #[test]
651 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
652 let mut types = Types::new();
655 let linux = linux();
656 let long_long = types.int(IntKind::LongLong);
657 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
658 let atomic = types.atomic(plain);
659 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
660 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
661
662 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
664 let atomic_odd = types.atomic(odd);
665 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
666
667 let int = types.int(IntKind::Int);
668 let atomic_int = types.atomic(int);
669 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
670 }
671
672 #[test]
673 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
674 let mut types = Types::new();
677 let linux = linux();
678 let darwin = target("aarch64-apple-darwin");
679 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
680 for (width, size, align) in cases {
681 let ty = types.bit_int(true, width);
682 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
683 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
684 }
685 for width in [65, 96, 128] {
686 let ty = types.bit_int(false, width);
687 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
688 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
689 }
690 let wide = types.bit_int(true, 129);
691 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
692 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
693 }
694
695 #[test]
696 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
697 let mut types = Types::new();
698 let linux = linux();
699 let int = types.int(IntKind::Int);
700 let ty = types.array(int, ArrayLen::Fixed(10));
701 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
702 let nested = types.array(ty, ArrayLen::Fixed(3));
703 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
704 }
705
706 #[test]
707 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
708 let mut types = Types::new();
709 let linux = linux();
710 let int = types.int(IntKind::Int);
711 for len in [ArrayLen::Unknown, ArrayLen::Star] {
712 let ty = types.array(int, len);
713 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
714 }
715 let measured = types.array(int, ArrayLen::Variable(VlaId(0)));
720 assert_eq!(layout(&types, measured, &linux), Err(LayoutError::Variable));
721 assert_eq!(align(&types, measured, &linux), Ok(4));
722 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
723 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
724 }
725
726 #[test]
727 fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
728 let mut types = Types::new();
732 let linux = linux();
733 let max = linux.max_object_size();
734 let ch = types.int(IntKind::Char);
735 let fits = types.array(ch, ArrayLen::Fixed(max));
736 assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
737 let over = types.array(ch, ArrayLen::Fixed(max + 1));
738 assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
739 }
740
741 #[test]
742 fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
743 let mut types = Types::new();
748 let linux = linux();
749 let max = linux.max_object_size();
750 let ch = types.int(IntKind::Char);
751 let int = types.int(IntKind::Int);
752 let short = types.int(IntKind::Short);
753
754 let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
755 let members = [member(huge), member(int), member(int), member(int), member(int)];
756 let laid_out = lay_out(&types, RecordKind::Struct, &members);
757 assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
758
759 let brim = types.array(ch, ArrayLen::Fixed(max));
760 let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
761 assert_eq!(laid_out.layout, Layout::new(max, 1));
762
763 let over = [member(brim), member(ch)];
764 let options = RecordOptions::default();
765 let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
766 assert_eq!(error, Err(RecordError::TooLarge));
767 }
768
769 #[test]
770 fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
771 let mut types = Types::new();
776 let linux = linux();
777 let ch = types.int(IntKind::Char);
778 let int = types.int(IntKind::Int);
779 let mut interner = Interner::new();
780 let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
781 let members = [member(buf), bits(&mut interner, "x", int, 1)];
782 let laid_out = lay_out(&types, RecordKind::Struct, &members);
783 assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
784 let last = laid_out.fields[1];
785 assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
786 assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
787 }
788
789 #[test]
790 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
791 let mut types = Types::new();
792 let int = types.int(IntKind::Int);
793 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
794 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
795 assert_ne!(a, b);
796 }
797
798 #[test]
799 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
800 let mut types = Types::new();
803 let linux = linux();
804 let int = types.int(IntKind::Int);
805 let four = types.vector(int, 4);
806 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
807 let three = types.vector(int, 3);
808 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
809 let three_chars = types.vector(types.int(IntKind::Char), 3);
810 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
811 }
812
813 #[test]
814 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
815 let mut types = Types::new();
818 let linux = linux();
819 let void = types.void();
820 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
821 let int = types.int(IntKind::Int);
822 let function = types.function(FunctionType {
823 ret: int,
824 params: Vec::new(),
825 variadic: false,
826 prototyped: true,
827 });
828 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
829 let pointer_to_function = types.pointer(function);
830 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
831 }
832
833 #[test]
834 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
835 let types = Types::new();
836 let char_ = types.int(IntKind::Char);
837 let int = types.int(IntKind::Int);
838 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
839 assert_eq!(laid_out.layout, Layout::new(8, 4));
840 assert_eq!(offsets(&laid_out), [0, 32]);
841 assert_eq!(laid_out.fields[1].offset, 4);
842
843 let long_long = types.int(IntKind::LongLong);
845 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
846 assert_eq!(laid_out.layout, Layout::new(16, 8));
847 }
848
849 #[test]
850 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
851 let mut types = Types::new();
852 let char_ = types.int(IntKind::Char);
853 let int = types.int(IntKind::Int);
854 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
855 assert_eq!(laid_out.layout, Layout::new(4, 4));
856 assert_eq!(offsets(&laid_out), [0, 0]);
857
858 let nine = types.array(char_, ArrayLen::Fixed(9));
861 let short = types.int(IntKind::Short);
862 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
863 assert_eq!(laid_out.layout, Layout::new(10, 2));
864 }
865
866 #[test]
867 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
868 let mut interner = Interner::new();
871 let types = Types::new();
872 let char_ = types.int(IntKind::Char);
873 let int = types.int(IntKind::Int);
874 let long_long = types.int(IntKind::LongLong);
875
876 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
877 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
878 assert_eq!(laid_out.layout, Layout::new(4, 4));
879 assert_eq!(offsets(&laid_out), [0, 3]);
880
881 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
883 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
884 assert_eq!(laid_out.layout, Layout::new(8, 4));
885 assert_eq!(offsets(&laid_out), [0, 32]);
886
887 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
890 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
891 assert_eq!(laid_out.layout, Layout::new(8, 8));
892 assert_eq!(offsets(&laid_out), [0, 8]);
893
894 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
896 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
897 assert_eq!(offsets(&laid_out), [0, 8]);
898 }
899
900 #[test]
901 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
902 let types = Types::new();
903 let char_ = types.int(IntKind::Char);
904 let int = types.int(IntKind::Int);
905 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
906 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
907 assert_eq!(laid_out.layout, Layout::new(5, 1));
910 assert_eq!(offsets(&laid_out), [0, 32, 32]);
911 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
912
913 let trailing = [member(char_), unnamed_bits(int, 0)];
917 assert_eq!(lay_out(&types, RecordKind::Struct, &trailing).layout, Layout::new(4, 1));
918
919 let only = [unnamed_bits(int, 0)];
922 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
923 }
924
925 #[test]
926 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
927 let mut interner = Interner::new();
928 let types = Types::new();
929 let char_ = types.int(IntKind::Char);
930 let int = types.int(IntKind::Int);
931
932 let unnamed = [member(char_), unnamed_bits(int, 20)];
933 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
934 assert_eq!(unnamed.layout, Layout::new(4, 1));
935
936 let named = [member(char_), bits(&mut interner, "b", int, 20)];
937 let named = lay_out(&types, RecordKind::Struct, &named);
938 assert_eq!(named.layout, Layout::new(4, 4));
939 assert_eq!(offsets(&named), [0, 8], "the same place either way");
940
941 let wider = [member(char_), unnamed_bits(int, 30)];
944 let wider = lay_out(&types, RecordKind::Struct, &wider);
945 assert_eq!(wider.layout, Layout::new(8, 1));
946 assert_eq!(offsets(&wider), [0, 32]);
947 }
948
949 #[test]
950 fn aapcs64_lets_an_unnamed_bit_field_raise_the_records_alignment() {
951 let types = Types::new();
952 let char_ = types.int(IntKind::Char);
953 let uint = types.int(IntKind::UInt);
954
955 let fields = [member(char_), unnamed_bits(uint, 20)];
957 let arm = lay_out_on(&aapcs(), &types, RecordKind::Struct, &fields);
958 assert_eq!(arm.layout, Layout::new(4, 4));
959
960 let only = [unnamed_bits(uint, 0)];
963 assert_eq!(
964 lay_out_on(&aapcs(), &types, RecordKind::Struct, &only).layout,
965 Layout::new(0, 4)
966 );
967 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
968
969 let pushed = [member(char_), unnamed_bits(uint, 0), member(char_)];
972 let pushed = lay_out_on(&aapcs(), &types, RecordKind::Struct, &pushed);
973 assert_eq!(pushed.layout, Layout::new(8, 4));
974 assert_eq!(offsets(&pushed), [0, 32, 32]);
975 }
976
977 #[test]
978 fn windows_allocates_a_bit_field_into_a_unit_of_its_declared_type() {
979 let mut interner = Interner::new();
980 let types = Types::new();
981 let char_ = types.int(IntKind::Char);
982 let uint = types.int(IntKind::UInt);
983 let ushort = types.int(IntKind::UShort);
984 let longlong = types.int(IntKind::LongLong);
985
986 let then_member = [bits(&mut interner, "m0", uint, 3), member(char_)];
989 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &then_member);
990 assert_eq!(ms.layout, Layout::new(8, 4));
991 assert_eq!(offsets(&ms), [0, 32]);
992 let itanium = lay_out(&types, RecordKind::Struct, &then_member);
993 assert_eq!(itanium.layout, Layout::new(4, 4));
994 assert_eq!(offsets(&itanium), [0, 8]);
995
996 let narrower = [bits(&mut interner, "m0", uint, 3), bits(&mut interner, "m1", ushort, 5)];
998 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &narrower);
999 assert_eq!(ms.layout, Layout::new(8, 4));
1000 assert_eq!(offsets(&ms), [0, 32]);
1001 assert_eq!(lay_out(&types, RecordKind::Struct, &narrower).layout, Layout::new(4, 4));
1002
1003 let wide = [member(char_), bits(&mut interner, "b", longlong, 33)];
1006 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &wide);
1007 assert_eq!(ms.layout, Layout::new(16, 8));
1008 assert_eq!(offsets(&ms), [0, 64]);
1009 let itanium = lay_out(&types, RecordKind::Struct, &wide);
1010 assert_eq!(itanium.layout, Layout::new(8, 8));
1011 assert_eq!(offsets(&itanium), [0, 8]);
1012 }
1013
1014 #[test]
1015 fn microsofts_zero_width_bit_field_closes_a_unit_and_does_nothing_without_one() {
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 alone = [member(char_), unnamed_bits(uint, 0)];
1023 assert_eq!(
1024 lay_out_on(&windows(), &types, RecordKind::Struct, &alone).layout,
1025 Layout::new(1, 1)
1026 );
1027 assert_eq!(lay_out(&types, RecordKind::Struct, &alone).layout, Layout::new(4, 1));
1028
1029 let between = [
1031 bits(&mut interner, "m0", uint, 3),
1032 unnamed_bits(uint, 0),
1033 bits(&mut interner, "m1", uint, 5),
1034 member(char_),
1035 ];
1036 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &between);
1037 assert_eq!(ms.layout, Layout::new(12, 4));
1038 assert_eq!(offsets(&ms), [0, 32, 32, 64]);
1039 let itanium = lay_out(&types, RecordKind::Struct, &between);
1040 assert_eq!(itanium.layout, Layout::new(8, 4));
1041 assert_eq!(offsets(&itanium), [0, 32, 32, 40]);
1042 }
1043
1044 #[test]
1045 fn microsoft_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1046 let mut interner = Interner::new();
1047 let types = Types::new();
1048 let char_ = types.int(IntKind::Char);
1049 let uint = types.int(IntKind::UInt);
1050
1051 let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1054 assert_eq!(
1055 lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1056 Layout::new(4, 1)
1057 );
1058 assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1059 }
1060
1061 #[test]
1062 fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1063 let mut types = Types::new();
1064 let uint = types.int(IntKind::UInt);
1065 let mingw = target("x86_64-pc-windows-gnu");
1066
1067 let none: [FieldDecl; 0] = [];
1069 let zero_width = [unnamed_bits(uint, 0)];
1070 let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1071 for fields in [&none[..], &zero_width[..], &flexible[..]] {
1072 let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1073 assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1074 assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1075 assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1076 }
1077
1078 assert_eq!(windows().empty_record_size, 4);
1082 assert_eq!(mingw.empty_record_size, 0);
1083 }
1084
1085 #[test]
1086 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
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 packed = RecordOptions { packed: true, ..RecordOptions::default() };
1092
1093 let fields = [member(char_), member(int)];
1094 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1095 .expect("a packed struct of two complete members");
1096 assert_eq!(laid_out.layout, Layout::new(5, 1));
1097 assert_eq!(offsets(&laid_out), [0, 8]);
1098
1099 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1100 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1101 .expect("a packed struct with a bit-field");
1102 assert_eq!(laid_out.layout, Layout::new(5, 1));
1103 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1104
1105 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1108 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1109 .expect("a packed struct with a zero width bit-field");
1110 assert_eq!(laid_out.layout, Layout::new(5, 1));
1111 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1112 }
1113
1114 #[test]
1115 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1116 let mut interner = Interner::new();
1117 let types = Types::new();
1118 let char_ = types.int(IntKind::Char);
1119 let int = types.int(IntKind::Int);
1120 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1121
1122 let fields = [member(char_), member(int)];
1123 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1124 .expect("a packed struct of two complete members");
1125 assert_eq!(laid_out.layout, Layout::new(6, 2));
1126 assert_eq!(offsets(&laid_out), [0, 16]);
1127
1128 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1132 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1133 .expect("a packed struct with a bit-field");
1134 assert_eq!(laid_out.layout, Layout::new(6, 2));
1135 assert_eq!(offsets(&laid_out), [0, 8]);
1136
1137 let fields = [member(char_), unnamed_bits(int, 30)];
1140 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1141 .expect("a packed struct with an unnamed bit-field");
1142 assert_eq!(laid_out.layout, Layout::new(5, 1));
1143 }
1144
1145 #[test]
1146 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1147 let types = Types::new();
1148 let char_ = types.int(IntKind::Char);
1149 let int = types.int(IntKind::Int);
1150
1151 let aligned = FieldDecl { align: Some(16), ..member(int) };
1152 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1153 assert_eq!(laid_out.layout, Layout::new(32, 16));
1154 assert_eq!(offsets(&laid_out), [0, 128]);
1155
1156 let options = RecordOptions { packed: true, align: Some(4), pack: None };
1159 let fields = [member(char_), member(int)];
1160 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1161 .expect("a packed struct with an alignment asked for");
1162 assert_eq!(laid_out.layout, Layout::new(8, 4));
1163 assert_eq!(offsets(&laid_out), [0, 8]);
1164 }
1165
1166 #[test]
1167 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1168 let mut types = Types::new();
1170 let char_ = types.int(IntKind::Char);
1171 let int = types.int(IntKind::Int);
1172 let long_long = types.int(IntKind::LongLong);
1173
1174 let chars = types.array(char_, ArrayLen::Unknown);
1175 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1176 assert_eq!(laid_out.layout, Layout::new(4, 4));
1177 assert_eq!(offsets(&laid_out), [0, 32]);
1178
1179 let longs = types.array(long_long, ArrayLen::Unknown);
1181 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1182 assert_eq!(laid_out.layout, Layout::new(8, 8));
1183 assert_eq!(offsets(&laid_out), [0, 64]);
1184
1185 let fields = [member(chars), member(int)];
1187 let error =
1188 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1189 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1190 }
1191
1192 #[test]
1193 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1194 let types = Types::new();
1196 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1197 assert_eq!(laid_out.layout, Layout::new(0, 1));
1198 }
1199
1200 #[test]
1201 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1202 let types = Types::new();
1203 let int = types.int(IntKind::Int);
1204 let fields = [unnamed_bits(int, 33)];
1205 let error =
1206 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1207 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1208 assert_eq!(error, Err(want));
1209 }
1210
1211 #[test]
1212 fn a_record_reports_its_members_once_it_has_been_completed() {
1213 let mut interner = Interner::new();
1214 let mut types = Types::new();
1215 let char_ = types.int(IntKind::Char);
1216 let int = types.int(IntKind::Int);
1217 let name = interner.intern("count");
1218 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1219 let id = types.declare_record(RecordKind::Struct, None);
1220 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1221 types.complete_record(id, laid_out);
1222 let ty = types.record(id);
1223 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1224 let field = types.field(id, name).expect("the member that was declared");
1225 assert_eq!(field.offset, 4);
1226 assert!(!field.is_bit_field());
1227 assert_eq!(types.field(id, interner.intern("missing")), None);
1228 }
1229
1230 #[test]
1231 fn a_nested_record_brings_its_own_alignment_with_it() {
1232 let mut types = Types::new();
1233 let char_ = types.int(IntKind::Char);
1234 let int = types.int(IntKind::Int);
1235 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1236 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1237 assert_eq!(laid_out.layout, Layout::new(8, 4));
1238 assert_eq!(offsets(&laid_out), [0, 32]);
1239
1240 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1243 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1244 assert_eq!(laid_out.layout, Layout::new(12, 4));
1245 assert_eq!(offsets(&laid_out), [0, 32]);
1246 }
1247
1248 #[test]
1249 fn everything_narrower_than_an_int_promotes_to_one() {
1250 let mut types = Types::new();
1254 let linux = linux();
1255 let int = types.int(IntKind::Int);
1256 let narrow =
1257 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1258 for kind in narrow {
1259 let ty = types.int(kind);
1260 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1261 }
1262 let boolean = types.boolean();
1263 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1264
1265 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1267 let ty = types.int(kind);
1268 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1269 }
1270 }
1271
1272 #[test]
1273 fn a_bit_int_is_not_promoted_at_all() {
1274 let mut types = Types::new();
1277 let linux = linux();
1278 let small = types.bit_int(true, 8);
1279 assert_eq!(promote(&mut types, small, &linux), small);
1280 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1281 }
1282
1283 #[test]
1284 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1285 let mut types = Types::new();
1286 let linux = linux();
1287 let int = types.int(IntKind::Int);
1288 let uint = types.int(IntKind::UInt);
1289 let ullong = types.int(IntKind::ULongLong);
1290
1291 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1293 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1295 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1297 let forty = types.bit_int(false, 40);
1302 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1303 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1305 }
1306
1307 #[test]
1308 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1309 let mut types = Types::new();
1310 let linux = linux();
1311 let int = types.int(IntKind::Int);
1312 let short = types.int(IntKind::Short);
1313 let uint = types.int(IntKind::UInt);
1314
1315 let fixed = types.declare_enum(None);
1317 types.complete_enum(fixed, short, true);
1318 let fixed = types.enumeration(fixed);
1319 assert_eq!(promote(&mut types, fixed, &linux), int);
1320
1321 let unsigned = types.declare_enum(None);
1324 types.complete_enum(unsigned, uint, false);
1325 let unsigned = types.enumeration(unsigned);
1326 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1327
1328 let undecided = types.declare_enum(None);
1331 let undecided = types.enumeration(undecided);
1332 assert_eq!(promote(&mut types, undecided, &linux), int);
1333 }
1334
1335 #[test]
1336 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1337 let mut types = Types::new();
1340 let linux = linux();
1341 let int = types.int(IntKind::Int);
1342 let konst = types.qualified(int, Qualifiers::CONST);
1343 let atomic = types.atomic(konst);
1344 assert_eq!(promote(&mut types, atomic, &linux), int);
1345 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1346 }
1347
1348 #[test]
1349 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1350 let mut types = Types::new();
1352 let linux = linux();
1353 let cases = [
1354 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1355 (IntKind::Int, IntKind::Long, IntKind::Long),
1356 (IntKind::UInt, IntKind::Long, IntKind::Long),
1357 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1358 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1359 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1360 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1361 (IntKind::Char, IntKind::Char, IntKind::Int),
1362 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1363 ];
1364 for (left, right, want) in cases {
1365 let left = types.int(left);
1366 let right = types.int(right);
1367 let want = types.int(want);
1368 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1369 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1370 }
1371 }
1372
1373 #[test]
1374 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1375 let mut types = Types::new();
1379 let linux = linux();
1380 let signed = types.int(IntKind::Int128);
1381 let unsigned = types.int(IntKind::UInt128);
1382 for id in [signed, unsigned] {
1383 let laid_out = layout(&types, id, &linux).expect("a complete type");
1384 assert_eq!(laid_out.size, 16);
1385 assert_eq!(laid_out.align, 16);
1386 }
1387
1388 let ull = types.int(IntKind::ULongLong);
1392 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1393 assert_eq!(promote(&mut types, signed, &linux), signed);
1395 }
1396
1397 #[test]
1398 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1399 let mut types = Types::new();
1402 let linux = linux();
1403 let int128 = types.int(IntKind::Int128);
1404 let bit_int = types.bit_int(true, 128);
1405 assert_ne!(int128, bit_int);
1406 assert!(!compatible(&types, int128, bit_int));
1407 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1408 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1409 }
1410
1411 #[test]
1412 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1413 let mut types = Types::new();
1417 let linux = linux();
1418 let ulong = types.int(IntKind::ULong);
1419 let long_long = types.int(IntKind::LongLong);
1420 let want = types.int(IntKind::ULongLong);
1421 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1422
1423 let windows = target("x86_64-pc-windows-msvc");
1427 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1428 }
1429
1430 #[test]
1431 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1432 let mut types = Types::new();
1434 let linux = linux();
1435 let b40 = types.bit_int(true, 40);
1436 let ub40 = types.bit_int(false, 40);
1437 let b8 = types.bit_int(true, 8);
1438 let b32 = types.bit_int(true, 32);
1439 let int = types.int(IntKind::Int);
1440 let uint = types.int(IntKind::UInt);
1441 let long = types.int(IntKind::Long);
1442 let char_ = types.int(IntKind::Char);
1443
1444 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1446 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1448 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1450 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1451 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1454 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1457 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1458 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1460 }
1461
1462 #[test]
1463 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1464 let mut types = Types::new();
1465 let linux = linux();
1466 let float = types.float(FloatKind::Float);
1467 let double = types.float(FloatKind::Double);
1468 let long_double = types.float(FloatKind::LongDouble);
1469 let ullong = types.int(IntKind::ULongLong);
1470 let int = types.int(IntKind::Int);
1471
1472 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1473 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1474 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1475 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1478 }
1479
1480 #[test]
1481 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1482 let mut types = Types::new();
1483 let linux = linux();
1484 let int = types.int(IntKind::Int);
1485 let float = types.float(FloatKind::Float);
1486 let short = types.int(IntKind::Short);
1487
1488 let four_ints = types.vector(int, 4);
1490 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1491
1492 let uint = types.int(IntKind::UInt);
1495 let four_uints = types.vector(uint, 4);
1496 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1497
1498 let four_floats = types.vector(float, 4);
1501 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1502
1503 let two_shorts = types.vector(short, 2);
1505 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1506
1507 assert_eq!(mask_of(&mut types, int, &linux), None);
1509 }
1510
1511 #[test]
1512 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1513 let mut types = Types::new();
1514 let linux = linux();
1515 let int = types.int(IntKind::Int);
1516 let uint = types.int(IntKind::UInt);
1517 let float = types.float(FloatKind::Float);
1518 let short = types.int(IntKind::Short);
1519
1520 let four_ints = types.vector(int, 4);
1521 let four_uints = types.vector(uint, 4);
1522 let four_floats = types.vector(float, 4);
1523 let eight_shorts = types.vector(short, 8);
1524 let two_ints = types.vector(int, 2);
1525
1526 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1529 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1531 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1533 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1535
1536 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1539 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1541 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1543 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1544 }
1545
1546 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1551 let mut types = Types::new();
1552 let left = types.float(a);
1553 let right = types.float(b);
1554 let want = types.float(expected);
1555 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1556 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1557 }
1558
1559 #[test]
1560 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1561 let x86 = linux();
1565 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1566 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1567 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1568 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1569 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1570 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1571 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1572 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1573 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1574 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1575 }
1576
1577 #[test]
1578 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1579 let mac = target("aarch64-apple-darwin");
1583 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1584 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1585 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1586 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1587 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1588 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1589 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1590 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1593 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1594 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1595 }
1596
1597 #[test]
1598 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1599 let mut types = Types::new();
1600 let linux = linux();
1601 let cfloat = types.complex_float(FloatKind::Float);
1602 let cdouble = types.complex_float(FloatKind::Double);
1603 let cldouble = types.complex_float(FloatKind::LongDouble);
1604 let double = types.float(FloatKind::Double);
1605 let long_double = types.float(FloatKind::LongDouble);
1606 let float = types.float(FloatKind::Float);
1607 let int = types.int(IntKind::Int);
1608
1609 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1610 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1611 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1612 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1613 }
1614
1615 #[test]
1616 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1617 let mut types = Types::new();
1619 let linux = linux();
1620 let int = types.int(IntKind::Int);
1621 let pointer = types.pointer(int);
1622 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1623 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1624 let void = types.void();
1625 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1626 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1629 }
1630
1631 #[test]
1632 fn the_conversions_read_through_sugar() {
1633 let mut interner = Interner::new();
1634 let mut types = Types::new();
1635 let linux = linux();
1636 let char_ = types.int(IntKind::Char);
1637 let name = types.typedef(interner.intern("byte"), char_);
1638 let int = types.int(IntKind::Int);
1639 assert_eq!(promote(&mut types, name, &linux), int);
1640 }
1641
1642 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1644 let ret = types.void();
1645 types.function(FunctionType { ret, params, variadic, prototyped: true })
1646 }
1647
1648 fn old_style(types: &mut Types) -> TypeId {
1650 let ret = types.void();
1651 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1652 }
1653
1654 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1656 let id = types.declare_record(RecordKind::Struct, Some(tag));
1657 let laid_out = lay_out(types, RecordKind::Struct, fields);
1658 types.complete_record(id, laid_out);
1659 id
1660 }
1661
1662 #[test]
1663 fn a_type_is_compatible_with_itself_however_it_was_written() {
1664 let mut interner = Interner::new();
1665 let mut types = Types::new();
1666 let int = types.int(IntKind::Int);
1667 let name = types.typedef(interner.intern("int32_t"), int);
1668 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1669 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1670
1671 let konst = types.qualified(int, Qualifiers::CONST);
1674 assert!(!compatible(&types, konst, int));
1675 let konst_pointer = types.pointer(konst);
1676 let pointer = types.pointer(int);
1677 assert!(!compatible(&types, konst_pointer, pointer));
1678 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1679
1680 let char_ = types.int(IntKind::Char);
1683 let schar = types.int(IntKind::SChar);
1684 assert!(!compatible(&types, char_, schar));
1685 let atomic = types.atomic(int);
1687 assert!(!compatible(&types, atomic, int));
1688 }
1689
1690 #[test]
1691 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1692 let mut types = Types::new();
1695 let uint = types.int(IntKind::UInt);
1696 let int = types.int(IntKind::Int);
1697 let id = types.declare_enum(None);
1698 types.complete_enum(id, uint, false);
1699 let e = types.enumeration(id);
1700 assert!(compatible(&types, e, uint));
1701 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1702 assert!(!compatible(&types, e, int));
1703
1704 let other = types.declare_enum(None);
1707 types.complete_enum(other, uint, false);
1708 let other = types.enumeration(other);
1709 assert!(!compatible(&types, e, other));
1710
1711 let undecided = types.declare_enum(None);
1714 let undecided = types.enumeration(undecided);
1715 assert!(!compatible(&types, undecided, uint));
1716 assert!(compatible(&types, undecided, undecided));
1717 }
1718
1719 #[test]
1720 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1721 let mut types = Types::new();
1724 let int = types.int(IntKind::Int);
1725 let unknown = types.array(int, ArrayLen::Unknown);
1726 let four = types.array(int, ArrayLen::Fixed(4));
1727 let five = types.array(int, ArrayLen::Fixed(5));
1728 assert!(compatible(&types, unknown, four));
1729 assert!(!compatible(&types, four, five));
1730 assert_eq!(composite(&mut types, unknown, four), Some(four));
1731 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1732 assert_eq!(composite(&mut types, four, five), None);
1733
1734 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1737 assert!(compatible(&types, vla, four));
1738 assert_eq!(composite(&mut types, vla, four), Some(four));
1739
1740 let long = types.int(IntKind::Long);
1742 let longs = types.array(long, ArrayLen::Fixed(4));
1743 assert!(!compatible(&types, four, longs));
1744 }
1745
1746 #[test]
1747 fn a_parameter_declared_as_an_array_is_a_pointer() {
1748 let mut types = Types::new();
1752 let int = types.int(IntKind::Int);
1753 let three = types.array(int, ArrayLen::Fixed(3));
1754 let pointer = types.pointer(int);
1755 assert_eq!(adjust_parameter(&mut types, three), pointer);
1756
1757 let function = prototype(&mut types, vec![int], false);
1759 let function_pointer = types.pointer(function);
1760 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1761
1762 let konst = types.qualified(int, Qualifiers::CONST);
1765 assert_eq!(adjust_parameter(&mut types, konst), int);
1766 let to_konst = types.pointer(konst);
1767 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1768 }
1769
1770 #[test]
1771 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1772 let mut types = Types::new();
1776 let old = old_style(&mut types);
1777 let int = types.int(IntKind::Int);
1778 let long = types.int(IntKind::Long);
1779 let char_ = types.int(IntKind::Char);
1780 let float = types.float(FloatKind::Float);
1781 let double = types.float(FloatKind::Double);
1782
1783 let takes_int = prototype(&mut types, vec![int], false);
1784 assert!(compatible(&types, old, takes_int));
1785 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1786 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1788
1789 let pointer = types.pointer(int);
1790 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1791 let ty = prototype(&mut types, params, false);
1792 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1793 }
1794
1795 for params in [vec![char_], vec![float], vec![int, char_]] {
1798 let ty = prototype(&mut types, params, false);
1799 assert!(!compatible(&types, old, ty));
1800 assert_eq!(composite(&mut types, old, ty), None);
1801 }
1802
1803 let variadic = prototype(&mut types, vec![int], true);
1805 assert!(!compatible(&types, old, variadic));
1806
1807 let uint = types.int(IntKind::UInt);
1809 let id = types.declare_enum(None);
1810 types.complete_enum(id, uint, false);
1811 let e = types.enumeration(id);
1812 let takes_enum = prototype(&mut types, vec![e], false);
1813 assert!(compatible(&types, old, takes_enum));
1814
1815 assert!(compatible(&types, old, old));
1817
1818 let returns_int = types.function(FunctionType {
1820 ret: int,
1821 params: Vec::new(),
1822 variadic: false,
1823 prototyped: false,
1824 });
1825 assert!(!compatible(&types, returns_int, takes_int));
1826 }
1827
1828 #[test]
1829 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1830 let mut types = Types::new();
1834 let int = types.int(IntKind::Int);
1835 let takes_int = prototype(&mut types, vec![int], false);
1836 let takes_nothing = prototype(&mut types, Vec::new(), false);
1837 let old = old_style(&mut types);
1838 assert!(!compatible(&types, takes_nothing, takes_int));
1839 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1840 }
1841
1842 #[test]
1843 fn two_prototypes_have_to_agree_about_everything() {
1844 let mut types = Types::new();
1845 let int = types.int(IntKind::Int);
1846 let long = types.int(IntKind::Long);
1847 let base = prototype(&mut types, vec![int, int], false);
1848 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1849 let other = prototype(&mut types, other, false);
1850 assert!(!compatible(&types, base, other));
1851 }
1852 let variadic = prototype(&mut types, vec![int, int], true);
1853 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1854
1855 let four = types.array(int, ArrayLen::Fixed(4));
1858 let unknown = types.array(int, ArrayLen::Unknown);
1859 let to_four = types.pointer(four);
1860 let to_unknown = types.pointer(unknown);
1861 let a = prototype(&mut types, vec![to_four], false);
1862 let b = prototype(&mut types, vec![to_unknown], false);
1863 assert!(compatible(&types, a, b));
1864 assert_eq!(composite(&mut types, a, b), Some(a));
1866 }
1867
1868 #[test]
1869 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1870 let mut types = Types::new();
1871 let int = types.int(IntKind::Int);
1872 let four = types.array(int, ArrayLen::Fixed(4));
1873 let unknown = types.array(int, ArrayLen::Unknown);
1874 let to_four = types.pointer(four);
1875 let to_unknown = types.pointer(unknown);
1876 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1877
1878 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1880 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1881 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1882 }
1883
1884 #[test]
1885 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1886 let mut interner = Interner::new();
1890 let mut types = Types::new();
1891 let tag = interner.intern("point");
1892 let x = interner.intern("x");
1893 let y = interner.intern("y");
1894 let int = types.int(IntKind::Int);
1895 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1896
1897 let first = tagged(&mut types, tag, &members);
1898 let second = tagged(&mut types, tag, &members);
1899 let first = types.record(first);
1900 let second = types.record(second);
1901 assert_ne!(first, second, "still two declarations and two types");
1902 assert!(compatible(&types, first, second));
1903
1904 let z = interner.intern("z");
1907 let long = types.int(IntKind::Long);
1908 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1909 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1910 for other in [&renamed[..], &retyped[..], &members[..1]] {
1911 let other = tagged(&mut types, tag, other);
1912 let other = types.record(other);
1913 assert!(!compatible(&types, first, other));
1914 }
1915 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1916 let elsewhere = types.record(elsewhere);
1917 assert!(!compatible(&types, first, elsewhere));
1918
1919 let anonymous = record(&mut types, RecordKind::Struct, &members);
1922 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1923 assert!(!compatible(&types, anonymous, also_anonymous));
1924
1925 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1927 let incomplete = types.record(incomplete);
1928 assert!(!compatible(&types, first, incomplete));
1929 assert!(compatible(&types, incomplete, incomplete));
1930 }
1931
1932 #[test]
1933 fn a_self_referential_record_is_compared_without_going_round_forever() {
1934 let mut interner = Interner::new();
1938 let mut types = Types::new();
1939 let tag = interner.intern("node");
1940 let value = interner.intern("value");
1941 let next = interner.intern("next");
1942 let int = types.int(IntKind::Int);
1943
1944 let node = |types: &mut Types| {
1945 let id = types.declare_record(RecordKind::Struct, Some(tag));
1946 let ty = types.record(id);
1947 let pointer = types.pointer(ty);
1948 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1949 let laid_out = lay_out(types, RecordKind::Struct, &members);
1950 types.complete_record(id, laid_out);
1951 ty
1952 };
1953 let first = node(&mut types);
1954 let second = node(&mut types);
1955 assert_ne!(first, second);
1956 assert!(compatible(&types, first, second));
1957
1958 let id = types.declare_record(RecordKind::Struct, Some(tag));
1961 let ty = types.record(id);
1962 let pointer = types.pointer(ty);
1963 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1964 let laid_out = lay_out(&types, RecordKind::Struct, &members);
1965 types.complete_record(id, laid_out);
1966 assert!(!compatible(&types, first, ty));
1967 }
1968
1969 #[test]
1970 fn layout_reads_through_sugar() {
1971 let mut interner = Interner::new();
1972 let mut types = Types::new();
1973 let long = types.int(IntKind::Long);
1974 let name = types.typedef(interner.intern("word"), long);
1975 let array = types.array(name, ArrayLen::Fixed(4));
1976 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1977 }
1978
1979 fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
1985 match recipe {
1986 Extent::Bytes(count) => *count,
1987 Extent::Member(index) => sizes[*index as usize],
1988 Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
1989 Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
1990 Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
1991 }
1992 }
1993
1994 fn measured(types: &mut Types, which: u32) -> TypeId {
1996 let int = types.int(IntKind::Int);
1997 types.array(int, ArrayLen::Variable(VlaId(which)))
1998 }
1999
2000 #[test]
2001 fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2002 let mut types = Types::new();
2003 let int = types.int(IntKind::Int);
2004 let rows = measured(&mut types, 0);
2005 let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2006
2007 assert_eq!(laid_out.layout, Layout::new(0, 4));
2010 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2011 assert_eq!(variable.offsets[0], None);
2015 let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2016 for count in 0..6u64 {
2017 let sizes = [4 * count, 4];
2018 assert_eq!(work_out(after, &sizes), 4 * count);
2019 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2020 }
2021 assert_eq!(laid_out.fields[1].align, 4);
2022 }
2023
2024 #[test]
2025 fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2026 let mut types = Types::new();
2027 let char_ty = types.int(IntKind::Char);
2028 let rows = measured(&mut types, 0);
2029 let double = types.float(FloatKind::Double);
2030 let fields = [member(char_ty), member(rows), member(double)];
2031 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2032
2033 assert_eq!(laid_out.layout, Layout::new(0, 8));
2034 assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2035 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2036 assert_eq!(variable.offsets[..2], [None, None]);
2037 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2038 for count in 0..6u64 {
2039 let sizes = [1, 4 * count, 8];
2040 let at = (4 + 4 * count).next_multiple_of(8);
2041 assert_eq!(work_out(after, &sizes), at);
2042 assert_eq!(work_out(&variable.size, &sizes), at + 8);
2043 }
2044 }
2045
2046 #[test]
2047 fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2048 let mut types = Types::new();
2049 let rows = measured(&mut types, 0);
2050 let double = types.float(FloatKind::Double);
2051 let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2052
2053 assert_eq!(laid_out.layout, Layout::new(0, 8));
2054 let variable = laid_out.variable.expect("a union with a member of no fixed size");
2055 assert!(variable.offsets.iter().all(Option::is_none));
2058 for count in 0..6u64 {
2059 let sizes = [4 * count, 8];
2060 let want = (4 * count).max(8).next_multiple_of(8);
2061 assert_eq!(work_out(&variable.size, &sizes), want);
2062 }
2063 }
2064
2065 #[test]
2066 fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2067 let mut types = Types::new();
2068 let char_ty = types.int(IntKind::Char);
2069 let int = types.int(IntKind::Int);
2070 let rows = measured(&mut types, 0);
2071 let fields = [member(char_ty), member(rows), member(int)];
2072 let options = RecordOptions { packed: true, ..RecordOptions::default() };
2073 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2074 .expect("a packed record with a member of no fixed size");
2075
2076 assert_eq!(laid_out.layout, Layout::new(0, 1));
2077 assert_eq!(laid_out.fields[2].align, 1);
2078 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2079 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2080 for count in 0..6u64 {
2081 let sizes = [1, 4 * count, 4];
2082 assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2083 assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2084 }
2085 }
2086
2087 #[test]
2088 fn a_bit_field_after_a_member_of_no_fixed_size_is_turned_down() {
2089 let mut interner = Interner::new();
2090 let mut types = Types::new();
2091 let int = types.int(IntKind::Int);
2092 let rows = measured(&mut types, 0);
2093 let fields = [member(rows), bits(&mut interner, "b", int, 3)];
2094 let options = RecordOptions::default();
2095 let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2096
2097 assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2101 }
2102}