1#![doc(html_root_url = "https://docs.rs/rucc-types/0.11.18")]
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, Spelled, 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 [
330 (2, 2),
331 (4, 4),
332 (4, 4),
333 (8, 8),
334 (8, 8),
335 (8, 8),
336 (16, 16),
337 (16, 16),
338 (16, 16),
339 (4, 4),
340 (8, 8),
341 (16, 16)
342 ]
343 );
344 assert_eq!(
345 sizes(&target("aarch64-apple-darwin")),
346 [
347 (2, 2),
348 (4, 4),
349 (4, 4),
350 (8, 8),
351 (8, 8),
352 (8, 8),
353 (8, 8),
354 (16, 16),
355 (16, 16),
356 (4, 4),
357 (8, 8),
358 (16, 16)
359 ]
360 );
361 }
362
363 #[test]
364 fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
365 let types = Types::new();
368 let mut seen = Vec::new();
369 for kind in FloatKind::ALL {
370 seen.push(types.float(kind));
371 }
372 let mut sorted = seen.clone();
373 sorted.sort_unstable();
374 sorted.dedup();
375 assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
376
377 let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
378 assert_eq!(
379 names,
380 [
381 "_Float16",
382 "float",
383 "_Float32",
384 "double",
385 "_Float32x",
386 "_Float64",
387 "long double",
388 "_Float64x",
389 "_Float128",
390 "_Decimal32",
391 "_Decimal64",
392 "_Decimal128",
393 ]
394 );
395 }
396
397 #[test]
398 fn the_same_type_asked_for_twice_is_the_same_id() {
399 let mut types = Types::new();
400 let a = types.pointer(types.int(IntKind::Int));
401 let b = types.pointer(types.int(IntKind::Int));
402 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
403 let c = types.pointer(types.int(IntKind::Long));
404 assert_ne!(a, c);
405 }
406
407 #[test]
408 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
409 let mut types = Types::new();
410 let int = types.int(IntKind::Int);
411 let konst = types.qualified(int, Qualifiers::CONST);
412 assert_ne!(int, konst);
413 assert_eq!(types.kind(konst), types.kind(int));
414 assert!(types.quals(konst).has(Qualifiers::CONST));
415 assert_eq!(types.unqualified(konst), int);
416 }
417
418 #[test]
419 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
420 let mut types = Types::new();
421 let int = types.int(IntKind::Int);
422 let a = types.qualified(int, Qualifiers::CONST);
423 let a = types.qualified(a, Qualifiers::VOLATILE);
424 let b = types.qualified(int, Qualifiers::VOLATILE);
425 let b = types.qualified(b, Qualifiers::CONST);
426 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
427 }
428
429 #[test]
430 fn qualifying_an_array_qualifies_its_element() {
431 let mut types = Types::new();
434 let int = types.int(IntKind::Int);
435 let array = types.array(int, ArrayLen::Fixed(4));
436 let konst = types.qualified(array, Qualifiers::CONST);
437 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
438 let TypeKind::Array { elem, len } = types.kind(konst) else {
439 panic!("still an array");
440 };
441 assert_eq!(len, ArrayLen::Fixed(4));
442 assert!(types.quals(elem).has(Qualifiers::CONST));
443 }
444
445 #[test]
446 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
447 let mut interner = Interner::new();
448 let mut types = Types::new();
449 let int = types.int(IntKind::Int);
450 let name = types.typedef(interner.intern("int32_t"), int);
451 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
452 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
453 assert!(types.is_sugar(name));
454 assert!(!types.is_sugar(int));
455 }
456
457 #[test]
463 fn a_typedef_name_is_recorded_without_making_a_type_of_its_own() {
464 let mut interner = Interner::new();
465 let mut types = Types::new();
466 let int = types.int(IntKind::Int);
467 types.alias(interner.intern("int32_t"), int);
468 types.alias(interner.intern("word"), int);
469 types.alias(interner.intern("int32_t"), int);
470 let names: Vec<_> =
471 types.aliases().iter().map(|had| interner.resolve(had.name).to_owned()).collect();
472 assert_eq!(names, ["int32_t", "word"], "the same name twice is one entry");
473 assert!(types.aliases().iter().all(|had| had.of == int));
474 assert_eq!(types.int(IntKind::Int), int, "and the type is the type it was");
475 }
476
477 #[test]
478 fn sugar_below_the_outermost_node_is_resolved_too() {
479 let mut interner = Interner::new();
482 let mut types = Types::new();
483 let int = types.int(IntKind::Int);
484 let name = types.typedef(interner.intern("int32_t"), int);
485 let sugar_pointer = types.pointer(name);
486 let plain_pointer = types.pointer(int);
487 assert_ne!(sugar_pointer, plain_pointer);
488 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
489
490 let sugar_array = types.array(name, ArrayLen::Fixed(3));
491 let plain_array = types.array(int, ArrayLen::Fixed(3));
492 assert_eq!(types.canonical(sugar_array), plain_array);
493 }
494
495 #[test]
496 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
497 let mut interner = Interner::new();
498 let mut types = Types::new();
499 let int = types.int(IntKind::Int);
500 let mut current = int;
501 for i in 0..8 {
502 current = types.typedef(interner.intern(&format!("t{i}")), current);
503 }
504 assert_eq!(types.canonical(current), int);
505 }
506
507 #[test]
508 fn a_typedef_that_asked_for_an_alignment_says_what_it_is_and_not_what_it_is_at_least() {
509 let mut interner = Interner::new();
514 let mut types = Types::new();
515 let target = linux();
516 let int = types.int(IntKind::Int);
517 let low = types.aligned_typedef(interner.intern("L"), int, NonZeroU32::new(2).unwrap());
518 let high = types.aligned_typedef(interner.intern("H"), int, NonZeroU32::new(16).unwrap());
519
520 assert_eq!(layout(&types, low, &target), Ok(Layout::new(4, 2)));
521 assert_eq!(layout(&types, high, &target), Ok(Layout::new(4, 16)));
522 assert_eq!(layout(&types, int, &target), Ok(Layout::new(4, 4)));
525
526 assert_ne!(low, high);
529
530 let outer = types.aligned_typedef(interner.intern("M"), low, NonZeroU32::new(8).unwrap());
533 assert_eq!(types.align_override(outer), NonZeroU32::new(8));
534 let plain = types.typedef(interner.intern("N"), low);
535 assert_eq!(types.align_override(plain), NonZeroU32::new(2));
536 assert_eq!(types.align_override(int), None);
538 }
539
540 #[test]
541 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
542 let mut interner = Interner::new();
543 let mut types = Types::new();
544 let int = types.int(IntKind::Int);
545 let name = types.typedef(interner.intern("int32_t"), int);
546 let konst = types.qualified(name, Qualifiers::CONST);
547 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
548 let want = types.qualified(int, Qualifiers::CONST);
549 assert_eq!(types.canonical(konst), want);
550 }
551
552 #[test]
553 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
554 let mut interner = Interner::new();
557 let mut types = Types::new();
558 let int = types.int(IntKind::Int);
559 let array = types.array(int, ArrayLen::Fixed(4));
560 let name = types.typedef(interner.intern("A"), array);
561 let konst = types.qualified(name, Qualifiers::CONST);
562 let konst_int = types.qualified(int, Qualifiers::CONST);
563 let want = types.array(konst_int, ArrayLen::Fixed(4));
564 assert_eq!(types.canonical(konst), want);
565 }
566
567 #[test]
568 fn a_function_type_is_deduplicated_by_its_signature() {
569 let mut types = Types::new();
570 let int = types.int(IntKind::Int);
571 let long = types.int(IntKind::Long);
572 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
573 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
574 };
575 let a = make(&mut types, vec![int, long], false);
576 let b = make(&mut types, vec![int, long], false);
577 assert_eq!(a, b);
578 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
579 assert_ne!(a, make(&mut types, vec![long, int], false));
580 }
581
582 #[test]
583 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
584 let mut interner = Interner::new();
585 let mut types = Types::new();
586 let int = types.int(IntKind::Int);
587 let name = types.typedef(interner.intern("int32_t"), int);
588 let sugar = types.function(FunctionType {
589 ret: name,
590 params: vec![name],
591 variadic: false,
592 prototyped: true,
593 });
594 let plain = types.function(FunctionType {
595 ret: int,
596 params: vec![int],
597 variadic: false,
598 prototyped: true,
599 });
600 assert_ne!(sugar, plain);
601 assert_eq!(types.canonical(sugar), plain);
602 }
603
604 #[test]
605 fn a_record_is_its_declaration_and_not_its_members() {
606 let mut interner = Interner::new();
610 let mut types = Types::new();
611 let tag = interner.intern("point");
612 let first = types.declare_record(RecordKind::Struct, Some(tag));
613 let second = types.declare_record(RecordKind::Struct, Some(tag));
614 assert_ne!(types.record(first), types.record(second));
615 assert_eq!(types.record(first), types.record(first));
616 }
617
618 #[test]
619 fn a_record_has_no_layout_until_it_has_been_completed() {
620 let mut types = Types::new();
621 let id = types.declare_record(RecordKind::Struct, None);
622 let ty = types.record(id);
623 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
624 let long_long = types.int(IntKind::LongLong);
625 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
626 types.complete_record(id, laid_out);
627 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
628 }
629
630 #[test]
631 fn an_enum_takes_the_layout_of_its_underlying_type() {
632 let mut types = Types::new();
633 let id = types.declare_enum(None);
634 let ty = types.enumeration(id);
635 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
636 let int = types.int(IntKind::Int);
637 types.complete_enum(id, int, false);
638 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
639 }
640
641 #[test]
642 fn the_scalar_widths_come_from_the_target() {
643 let mut types = Types::new();
644 let linux = linux();
645 let windows = target("x86_64-pc-windows-msvc");
646 let darwin = target("aarch64-apple-darwin");
647
648 let long = types.int(IntKind::Long);
649 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
650 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
651
652 let ldouble = types.float(FloatKind::LongDouble);
653 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
654 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
655
656 let pointer = types.pointer(types.void());
657 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
658
659 let boolean = types.boolean();
660 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
661 }
662
663 #[test]
664 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
665 let mut types = Types::new();
668 let linux = linux();
669 let cfloat = types.complex_float(FloatKind::Float);
670 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
671 let cdouble = types.complex_float(FloatKind::Double);
672 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
673 let cldouble = types.complex_float(FloatKind::LongDouble);
674 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
675 let darwin = target("aarch64-apple-darwin");
676 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
677 }
678
679 #[test]
680 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
681 let mut types = Types::new();
684 let linux = linux();
685 let long_long = types.int(IntKind::LongLong);
686 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
687 let atomic = types.atomic(plain);
688 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
689 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
690
691 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
693 let atomic_odd = types.atomic(odd);
694 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
695
696 let int = types.int(IntKind::Int);
697 let atomic_int = types.atomic(int);
698 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
699 }
700
701 #[test]
702 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
703 let mut types = Types::new();
706 let linux = linux();
707 let darwin = target("aarch64-apple-darwin");
708 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
709 for (width, size, align) in cases {
710 let ty = types.bit_int(true, width);
711 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
712 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
713 }
714 for width in [65, 96, 128] {
715 let ty = types.bit_int(false, width);
716 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
717 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
718 }
719 let wide = types.bit_int(true, 129);
720 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
721 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
722 }
723
724 #[test]
725 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
726 let mut types = Types::new();
727 let linux = linux();
728 let int = types.int(IntKind::Int);
729 let ty = types.array(int, ArrayLen::Fixed(10));
730 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
731 let nested = types.array(ty, ArrayLen::Fixed(3));
732 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
733 }
734
735 #[test]
736 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
737 let mut types = Types::new();
738 let linux = linux();
739 let int = types.int(IntKind::Int);
740 for len in [ArrayLen::Unknown, ArrayLen::Star] {
741 let ty = types.array(int, len);
742 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
743 }
744 let measured = types.array(int, ArrayLen::Variable(VlaId(0)));
749 assert_eq!(layout(&types, measured, &linux), Err(LayoutError::Variable));
750 assert_eq!(align(&types, measured, &linux), Ok(4));
751 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
752 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
753 }
754
755 #[test]
756 fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
757 let mut types = Types::new();
761 let linux = linux();
762 let max = linux.max_object_size();
763 let ch = types.int(IntKind::Char);
764 let fits = types.array(ch, ArrayLen::Fixed(max));
765 assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
766 let over = types.array(ch, ArrayLen::Fixed(max + 1));
767 assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
768 }
769
770 #[test]
771 fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
772 let mut types = Types::new();
777 let linux = linux();
778 let max = linux.max_object_size();
779 let ch = types.int(IntKind::Char);
780 let int = types.int(IntKind::Int);
781 let short = types.int(IntKind::Short);
782
783 let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
784 let members = [member(huge), member(int), member(int), member(int), member(int)];
785 let laid_out = lay_out(&types, RecordKind::Struct, &members);
786 assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
787
788 let brim = types.array(ch, ArrayLen::Fixed(max));
789 let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
790 assert_eq!(laid_out.layout, Layout::new(max, 1));
791
792 let over = [member(brim), member(ch)];
793 let options = RecordOptions::default();
794 let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
795 assert_eq!(error, Err(RecordError::TooLarge));
796 }
797
798 #[test]
799 fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
800 let mut types = Types::new();
805 let linux = linux();
806 let ch = types.int(IntKind::Char);
807 let int = types.int(IntKind::Int);
808 let mut interner = Interner::new();
809 let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
810 let members = [member(buf), bits(&mut interner, "x", int, 1)];
811 let laid_out = lay_out(&types, RecordKind::Struct, &members);
812 assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
813 let last = laid_out.fields[1];
814 assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
815 assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
816 }
817
818 #[test]
819 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
820 let mut types = Types::new();
821 let int = types.int(IntKind::Int);
822 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
823 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
824 assert_ne!(a, b);
825 }
826
827 #[test]
828 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
829 let mut types = Types::new();
832 let linux = linux();
833 let int = types.int(IntKind::Int);
834 let four = types.vector(int, 4);
835 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
836 let three = types.vector(int, 3);
837 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
838 let three_chars = types.vector(types.int(IntKind::Char), 3);
839 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
840 }
841
842 #[test]
843 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
844 let mut types = Types::new();
847 let linux = linux();
848 let void = types.void();
849 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
850 let int = types.int(IntKind::Int);
851 let function = types.function(FunctionType {
852 ret: int,
853 params: Vec::new(),
854 variadic: false,
855 prototyped: true,
856 });
857 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
858 let pointer_to_function = types.pointer(function);
859 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
860 }
861
862 #[test]
863 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
864 let types = Types::new();
865 let char_ = types.int(IntKind::Char);
866 let int = types.int(IntKind::Int);
867 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
868 assert_eq!(laid_out.layout, Layout::new(8, 4));
869 assert_eq!(offsets(&laid_out), [0, 32]);
870 assert_eq!(laid_out.fields[1].offset, 4);
871
872 let long_long = types.int(IntKind::LongLong);
874 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
875 assert_eq!(laid_out.layout, Layout::new(16, 8));
876 }
877
878 #[test]
879 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
880 let mut types = Types::new();
881 let char_ = types.int(IntKind::Char);
882 let int = types.int(IntKind::Int);
883 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
884 assert_eq!(laid_out.layout, Layout::new(4, 4));
885 assert_eq!(offsets(&laid_out), [0, 0]);
886
887 let nine = types.array(char_, ArrayLen::Fixed(9));
890 let short = types.int(IntKind::Short);
891 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
892 assert_eq!(laid_out.layout, Layout::new(10, 2));
893 }
894
895 #[test]
896 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
897 let mut interner = Interner::new();
900 let types = Types::new();
901 let char_ = types.int(IntKind::Char);
902 let int = types.int(IntKind::Int);
903 let long_long = types.int(IntKind::LongLong);
904
905 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
906 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
907 assert_eq!(laid_out.layout, Layout::new(4, 4));
908 assert_eq!(offsets(&laid_out), [0, 3]);
909
910 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
912 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
913 assert_eq!(laid_out.layout, Layout::new(8, 4));
914 assert_eq!(offsets(&laid_out), [0, 32]);
915
916 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
919 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
920 assert_eq!(laid_out.layout, Layout::new(8, 8));
921 assert_eq!(offsets(&laid_out), [0, 8]);
922
923 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
925 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
926 assert_eq!(offsets(&laid_out), [0, 8]);
927 }
928
929 #[test]
930 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
931 let types = Types::new();
932 let char_ = types.int(IntKind::Char);
933 let int = types.int(IntKind::Int);
934 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
935 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
936 assert_eq!(laid_out.layout, Layout::new(5, 1));
939 assert_eq!(offsets(&laid_out), [0, 32, 32]);
940 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
941
942 let trailing = [member(char_), unnamed_bits(int, 0)];
946 assert_eq!(lay_out(&types, RecordKind::Struct, &trailing).layout, Layout::new(4, 1));
947
948 let only = [unnamed_bits(int, 0)];
951 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
952 }
953
954 #[test]
955 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
956 let mut interner = Interner::new();
957 let types = Types::new();
958 let char_ = types.int(IntKind::Char);
959 let int = types.int(IntKind::Int);
960
961 let unnamed = [member(char_), unnamed_bits(int, 20)];
962 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
963 assert_eq!(unnamed.layout, Layout::new(4, 1));
964
965 let named = [member(char_), bits(&mut interner, "b", int, 20)];
966 let named = lay_out(&types, RecordKind::Struct, &named);
967 assert_eq!(named.layout, Layout::new(4, 4));
968 assert_eq!(offsets(&named), [0, 8], "the same place either way");
969
970 let wider = [member(char_), unnamed_bits(int, 30)];
973 let wider = lay_out(&types, RecordKind::Struct, &wider);
974 assert_eq!(wider.layout, Layout::new(8, 1));
975 assert_eq!(offsets(&wider), [0, 32]);
976 }
977
978 #[test]
979 fn aapcs64_lets_an_unnamed_bit_field_raise_the_records_alignment() {
980 let types = Types::new();
981 let char_ = types.int(IntKind::Char);
982 let uint = types.int(IntKind::UInt);
983
984 let fields = [member(char_), unnamed_bits(uint, 20)];
986 let arm = lay_out_on(&aapcs(), &types, RecordKind::Struct, &fields);
987 assert_eq!(arm.layout, Layout::new(4, 4));
988
989 let only = [unnamed_bits(uint, 0)];
992 assert_eq!(
993 lay_out_on(&aapcs(), &types, RecordKind::Struct, &only).layout,
994 Layout::new(0, 4)
995 );
996 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
997
998 let pushed = [member(char_), unnamed_bits(uint, 0), member(char_)];
1001 let pushed = lay_out_on(&aapcs(), &types, RecordKind::Struct, &pushed);
1002 assert_eq!(pushed.layout, Layout::new(8, 4));
1003 assert_eq!(offsets(&pushed), [0, 32, 32]);
1004 }
1005
1006 #[test]
1007 fn windows_allocates_a_bit_field_into_a_unit_of_its_declared_type() {
1008 let mut interner = Interner::new();
1009 let types = Types::new();
1010 let char_ = types.int(IntKind::Char);
1011 let uint = types.int(IntKind::UInt);
1012 let ushort = types.int(IntKind::UShort);
1013 let longlong = types.int(IntKind::LongLong);
1014
1015 let then_member = [bits(&mut interner, "m0", uint, 3), member(char_)];
1018 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &then_member);
1019 assert_eq!(ms.layout, Layout::new(8, 4));
1020 assert_eq!(offsets(&ms), [0, 32]);
1021 let itanium = lay_out(&types, RecordKind::Struct, &then_member);
1022 assert_eq!(itanium.layout, Layout::new(4, 4));
1023 assert_eq!(offsets(&itanium), [0, 8]);
1024
1025 let narrower = [bits(&mut interner, "m0", uint, 3), bits(&mut interner, "m1", ushort, 5)];
1027 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &narrower);
1028 assert_eq!(ms.layout, Layout::new(8, 4));
1029 assert_eq!(offsets(&ms), [0, 32]);
1030 assert_eq!(lay_out(&types, RecordKind::Struct, &narrower).layout, Layout::new(4, 4));
1031
1032 let wide = [member(char_), bits(&mut interner, "b", longlong, 33)];
1035 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &wide);
1036 assert_eq!(ms.layout, Layout::new(16, 8));
1037 assert_eq!(offsets(&ms), [0, 64]);
1038 let itanium = lay_out(&types, RecordKind::Struct, &wide);
1039 assert_eq!(itanium.layout, Layout::new(8, 8));
1040 assert_eq!(offsets(&itanium), [0, 8]);
1041 }
1042
1043 #[test]
1044 fn microsofts_zero_width_bit_field_closes_a_unit_and_does_nothing_without_one() {
1045 let mut interner = Interner::new();
1046 let types = Types::new();
1047 let char_ = types.int(IntKind::Char);
1048 let uint = types.int(IntKind::UInt);
1049
1050 let alone = [member(char_), unnamed_bits(uint, 0)];
1052 assert_eq!(
1053 lay_out_on(&windows(), &types, RecordKind::Struct, &alone).layout,
1054 Layout::new(1, 1)
1055 );
1056 assert_eq!(lay_out(&types, RecordKind::Struct, &alone).layout, Layout::new(4, 1));
1057
1058 let between = [
1060 bits(&mut interner, "m0", uint, 3),
1061 unnamed_bits(uint, 0),
1062 bits(&mut interner, "m1", uint, 5),
1063 member(char_),
1064 ];
1065 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &between);
1066 assert_eq!(ms.layout, Layout::new(12, 4));
1067 assert_eq!(offsets(&ms), [0, 32, 32, 64]);
1068 let itanium = lay_out(&types, RecordKind::Struct, &between);
1069 assert_eq!(itanium.layout, Layout::new(8, 4));
1070 assert_eq!(offsets(&itanium), [0, 32, 32, 40]);
1071 }
1072
1073 #[test]
1074 fn msvc_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1075 let mut interner = Interner::new();
1076 let types = Types::new();
1077 let char_ = types.int(IntKind::Char);
1078 let uint = types.int(IntKind::UInt);
1079
1080 let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1083 assert_eq!(
1084 lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1085 Layout::new(4, 1)
1086 );
1087 assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1088 let mingw = target("x86_64-pc-windows-gnu");
1091 assert_eq!(
1092 lay_out_on(&mingw, &types, RecordKind::Union, &fields).layout,
1093 Layout::new(4, 4)
1094 );
1095 }
1096
1097 #[test]
1098 fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1099 let mut types = Types::new();
1100 let uint = types.int(IntKind::UInt);
1101 let mingw = target("x86_64-pc-windows-gnu");
1102
1103 let none: [FieldDecl; 0] = [];
1105 let zero_width = [unnamed_bits(uint, 0)];
1106 let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1107 for fields in [&none[..], &zero_width[..], &flexible[..]] {
1108 let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1109 assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1110 assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1111 assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1112 }
1113
1114 assert_eq!(windows().empty_record_size, 4);
1118 assert_eq!(mingw.empty_record_size, 0);
1119 }
1120
1121 #[test]
1122 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
1123 let mut interner = Interner::new();
1124 let types = Types::new();
1125 let char_ = types.int(IntKind::Char);
1126 let int = types.int(IntKind::Int);
1127 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1128
1129 let fields = [member(char_), member(int)];
1130 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1131 .expect("a packed struct of two complete members");
1132 assert_eq!(laid_out.layout, Layout::new(5, 1));
1133 assert_eq!(offsets(&laid_out), [0, 8]);
1134
1135 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1136 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1137 .expect("a packed struct with a bit-field");
1138 assert_eq!(laid_out.layout, Layout::new(5, 1));
1139 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1140
1141 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1144 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1145 .expect("a packed struct with a zero width bit-field");
1146 assert_eq!(laid_out.layout, Layout::new(5, 1));
1147 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1148 }
1149
1150 #[test]
1151 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1152 let mut interner = Interner::new();
1153 let types = Types::new();
1154 let char_ = types.int(IntKind::Char);
1155 let int = types.int(IntKind::Int);
1156 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1157
1158 let fields = [member(char_), member(int)];
1159 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1160 .expect("a packed struct of two complete members");
1161 assert_eq!(laid_out.layout, Layout::new(6, 2));
1162 assert_eq!(offsets(&laid_out), [0, 16]);
1163
1164 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1168 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1169 .expect("a packed struct with a bit-field");
1170 assert_eq!(laid_out.layout, Layout::new(6, 2));
1171 assert_eq!(offsets(&laid_out), [0, 8]);
1172
1173 let fields = [member(char_), unnamed_bits(int, 30)];
1176 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1177 .expect("a packed struct with an unnamed bit-field");
1178 assert_eq!(laid_out.layout, Layout::new(5, 1));
1179 }
1180
1181 #[test]
1182 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1183 let types = Types::new();
1184 let char_ = types.int(IntKind::Char);
1185 let int = types.int(IntKind::Int);
1186
1187 let aligned = FieldDecl { align: Some(16), ..member(int) };
1188 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1189 assert_eq!(laid_out.layout, Layout::new(32, 16));
1190 assert_eq!(offsets(&laid_out), [0, 128]);
1191
1192 let options = RecordOptions { packed: true, align: Some(4), pack: None };
1195 let fields = [member(char_), member(int)];
1196 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1197 .expect("a packed struct with an alignment asked for");
1198 assert_eq!(laid_out.layout, Layout::new(8, 4));
1199 assert_eq!(offsets(&laid_out), [0, 8]);
1200 }
1201
1202 #[test]
1203 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1204 let mut types = Types::new();
1206 let char_ = types.int(IntKind::Char);
1207 let int = types.int(IntKind::Int);
1208 let long_long = types.int(IntKind::LongLong);
1209
1210 let chars = types.array(char_, ArrayLen::Unknown);
1211 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1212 assert_eq!(laid_out.layout, Layout::new(4, 4));
1213 assert_eq!(offsets(&laid_out), [0, 32]);
1214
1215 let longs = types.array(long_long, ArrayLen::Unknown);
1217 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1218 assert_eq!(laid_out.layout, Layout::new(8, 8));
1219 assert_eq!(offsets(&laid_out), [0, 64]);
1220
1221 let fields = [member(chars), member(int)];
1223 let error =
1224 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1225 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1226 }
1227
1228 #[test]
1229 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1230 let types = Types::new();
1232 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1233 assert_eq!(laid_out.layout, Layout::new(0, 1));
1234 }
1235
1236 #[test]
1237 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1238 let types = Types::new();
1239 let int = types.int(IntKind::Int);
1240 let fields = [unnamed_bits(int, 33)];
1241 let error =
1242 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1243 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1244 assert_eq!(error, Err(want));
1245 }
1246
1247 #[test]
1248 fn a_record_reports_its_members_once_it_has_been_completed() {
1249 let mut interner = Interner::new();
1250 let mut types = Types::new();
1251 let char_ = types.int(IntKind::Char);
1252 let int = types.int(IntKind::Int);
1253 let name = interner.intern("count");
1254 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1255 let id = types.declare_record(RecordKind::Struct, None);
1256 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1257 types.complete_record(id, laid_out);
1258 let ty = types.record(id);
1259 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1260 let field = types.field(id, name).expect("the member that was declared");
1261 assert_eq!(field.offset, 4);
1262 assert!(!field.is_bit_field());
1263 assert_eq!(types.field(id, interner.intern("missing")), None);
1264 }
1265
1266 #[test]
1267 fn a_nested_record_brings_its_own_alignment_with_it() {
1268 let mut types = Types::new();
1269 let char_ = types.int(IntKind::Char);
1270 let int = types.int(IntKind::Int);
1271 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1272 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1273 assert_eq!(laid_out.layout, Layout::new(8, 4));
1274 assert_eq!(offsets(&laid_out), [0, 32]);
1275
1276 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1279 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1280 assert_eq!(laid_out.layout, Layout::new(12, 4));
1281 assert_eq!(offsets(&laid_out), [0, 32]);
1282 }
1283
1284 #[test]
1285 fn everything_narrower_than_an_int_promotes_to_one() {
1286 let mut types = Types::new();
1290 let linux = linux();
1291 let int = types.int(IntKind::Int);
1292 let narrow =
1293 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1294 for kind in narrow {
1295 let ty = types.int(kind);
1296 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1297 }
1298 let boolean = types.boolean();
1299 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1300
1301 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1303 let ty = types.int(kind);
1304 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1305 }
1306 }
1307
1308 #[test]
1309 fn a_bit_int_is_not_promoted_at_all() {
1310 let mut types = Types::new();
1313 let linux = linux();
1314 let small = types.bit_int(true, 8);
1315 assert_eq!(promote(&mut types, small, &linux), small);
1316 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1317 }
1318
1319 #[test]
1320 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1321 let mut types = Types::new();
1322 let linux = linux();
1323 let int = types.int(IntKind::Int);
1324 let uint = types.int(IntKind::UInt);
1325 let ullong = types.int(IntKind::ULongLong);
1326
1327 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1329 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1331 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1333 let forty = types.bit_int(false, 40);
1338 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1339 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1341 }
1342
1343 #[test]
1344 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1345 let mut types = Types::new();
1346 let linux = linux();
1347 let int = types.int(IntKind::Int);
1348 let short = types.int(IntKind::Short);
1349 let uint = types.int(IntKind::UInt);
1350
1351 let fixed = types.declare_enum(None);
1353 types.complete_enum(fixed, short, true);
1354 let fixed = types.enumeration(fixed);
1355 assert_eq!(promote(&mut types, fixed, &linux), int);
1356
1357 let unsigned = types.declare_enum(None);
1360 types.complete_enum(unsigned, uint, false);
1361 let unsigned = types.enumeration(unsigned);
1362 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1363
1364 let undecided = types.declare_enum(None);
1367 let undecided = types.enumeration(undecided);
1368 assert_eq!(promote(&mut types, undecided, &linux), int);
1369 }
1370
1371 #[test]
1372 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1373 let mut types = Types::new();
1376 let linux = linux();
1377 let int = types.int(IntKind::Int);
1378 let konst = types.qualified(int, Qualifiers::CONST);
1379 let atomic = types.atomic(konst);
1380 assert_eq!(promote(&mut types, atomic, &linux), int);
1381 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1382 }
1383
1384 #[test]
1385 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1386 let mut types = Types::new();
1388 let linux = linux();
1389 let cases = [
1390 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1391 (IntKind::Int, IntKind::Long, IntKind::Long),
1392 (IntKind::UInt, IntKind::Long, IntKind::Long),
1393 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1394 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1395 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1396 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1397 (IntKind::Char, IntKind::Char, IntKind::Int),
1398 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1399 ];
1400 for (left, right, want) in cases {
1401 let left = types.int(left);
1402 let right = types.int(right);
1403 let want = types.int(want);
1404 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1405 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1406 }
1407 }
1408
1409 #[test]
1410 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1411 let mut types = Types::new();
1415 let linux = linux();
1416 let signed = types.int(IntKind::Int128);
1417 let unsigned = types.int(IntKind::UInt128);
1418 for id in [signed, unsigned] {
1419 let laid_out = layout(&types, id, &linux).expect("a complete type");
1420 assert_eq!(laid_out.size, 16);
1421 assert_eq!(laid_out.align, 16);
1422 }
1423
1424 let ull = types.int(IntKind::ULongLong);
1428 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1429 assert_eq!(promote(&mut types, signed, &linux), signed);
1431 }
1432
1433 #[test]
1434 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1435 let mut types = Types::new();
1438 let linux = linux();
1439 let int128 = types.int(IntKind::Int128);
1440 let bit_int = types.bit_int(true, 128);
1441 assert_ne!(int128, bit_int);
1442 assert!(!compatible(&types, int128, bit_int));
1443 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1444 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1445 }
1446
1447 #[test]
1448 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1449 let mut types = Types::new();
1453 let linux = linux();
1454 let ulong = types.int(IntKind::ULong);
1455 let long_long = types.int(IntKind::LongLong);
1456 let want = types.int(IntKind::ULongLong);
1457 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1458
1459 let windows = target("x86_64-pc-windows-msvc");
1463 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1464 }
1465
1466 #[test]
1467 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1468 let mut types = Types::new();
1470 let linux = linux();
1471 let b40 = types.bit_int(true, 40);
1472 let ub40 = types.bit_int(false, 40);
1473 let b8 = types.bit_int(true, 8);
1474 let b32 = types.bit_int(true, 32);
1475 let int = types.int(IntKind::Int);
1476 let uint = types.int(IntKind::UInt);
1477 let long = types.int(IntKind::Long);
1478 let char_ = types.int(IntKind::Char);
1479
1480 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1482 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1484 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1486 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1487 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1490 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1493 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1494 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1496 }
1497
1498 #[test]
1499 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1500 let mut types = Types::new();
1501 let linux = linux();
1502 let float = types.float(FloatKind::Float);
1503 let double = types.float(FloatKind::Double);
1504 let long_double = types.float(FloatKind::LongDouble);
1505 let ullong = types.int(IntKind::ULongLong);
1506 let int = types.int(IntKind::Int);
1507
1508 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1509 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1510 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1511 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1514 }
1515
1516 #[test]
1517 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1518 let mut types = Types::new();
1519 let linux = linux();
1520 let int = types.int(IntKind::Int);
1521 let float = types.float(FloatKind::Float);
1522 let short = types.int(IntKind::Short);
1523
1524 let four_ints = types.vector(int, 4);
1526 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1527
1528 let uint = types.int(IntKind::UInt);
1531 let four_uints = types.vector(uint, 4);
1532 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1533
1534 let four_floats = types.vector(float, 4);
1537 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1538
1539 let two_shorts = types.vector(short, 2);
1541 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1542
1543 assert_eq!(mask_of(&mut types, int, &linux), None);
1545 }
1546
1547 #[test]
1548 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1549 let mut types = Types::new();
1550 let linux = linux();
1551 let int = types.int(IntKind::Int);
1552 let uint = types.int(IntKind::UInt);
1553 let float = types.float(FloatKind::Float);
1554 let short = types.int(IntKind::Short);
1555
1556 let four_ints = types.vector(int, 4);
1557 let four_uints = types.vector(uint, 4);
1558 let four_floats = types.vector(float, 4);
1559 let eight_shorts = types.vector(short, 8);
1560 let two_ints = types.vector(int, 2);
1561
1562 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1565 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1567 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1569 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1571
1572 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1575 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1577 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1579 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1580 }
1581
1582 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1587 let mut types = Types::new();
1588 let left = types.float(a);
1589 let right = types.float(b);
1590 let want = types.float(expected);
1591 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1592 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1593 }
1594
1595 #[test]
1596 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1597 let x86 = linux();
1601 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1602 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1603 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1604 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1605 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1606 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1607 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1608 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1609 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1610 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1611 }
1612
1613 #[test]
1614 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1615 let mac = target("aarch64-apple-darwin");
1619 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1620 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1621 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1622 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1623 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1624 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1625 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1626 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1629 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1630 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1631 }
1632
1633 #[test]
1634 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1635 let mut types = Types::new();
1636 let linux = linux();
1637 let cfloat = types.complex_float(FloatKind::Float);
1638 let cdouble = types.complex_float(FloatKind::Double);
1639 let cldouble = types.complex_float(FloatKind::LongDouble);
1640 let double = types.float(FloatKind::Double);
1641 let long_double = types.float(FloatKind::LongDouble);
1642 let float = types.float(FloatKind::Float);
1643 let int = types.int(IntKind::Int);
1644
1645 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1646 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1647 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1648 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1649 }
1650
1651 #[test]
1652 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1653 let mut types = Types::new();
1655 let linux = linux();
1656 let int = types.int(IntKind::Int);
1657 let pointer = types.pointer(int);
1658 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1659 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1660 let void = types.void();
1661 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1662 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1665 }
1666
1667 #[test]
1668 fn the_conversions_read_through_sugar() {
1669 let mut interner = Interner::new();
1670 let mut types = Types::new();
1671 let linux = linux();
1672 let char_ = types.int(IntKind::Char);
1673 let name = types.typedef(interner.intern("byte"), char_);
1674 let int = types.int(IntKind::Int);
1675 assert_eq!(promote(&mut types, name, &linux), int);
1676 }
1677
1678 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1680 let ret = types.void();
1681 types.function(FunctionType { ret, params, variadic, prototyped: true })
1682 }
1683
1684 fn old_style(types: &mut Types) -> TypeId {
1686 let ret = types.void();
1687 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1688 }
1689
1690 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1692 let id = types.declare_record(RecordKind::Struct, Some(tag));
1693 let laid_out = lay_out(types, RecordKind::Struct, fields);
1694 types.complete_record(id, laid_out);
1695 id
1696 }
1697
1698 #[test]
1699 fn a_type_is_compatible_with_itself_however_it_was_written() {
1700 let mut interner = Interner::new();
1701 let mut types = Types::new();
1702 let int = types.int(IntKind::Int);
1703 let name = types.typedef(interner.intern("int32_t"), int);
1704 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1705 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1706
1707 let konst = types.qualified(int, Qualifiers::CONST);
1710 assert!(!compatible(&types, konst, int));
1711 let konst_pointer = types.pointer(konst);
1712 let pointer = types.pointer(int);
1713 assert!(!compatible(&types, konst_pointer, pointer));
1714 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1715
1716 let char_ = types.int(IntKind::Char);
1719 let schar = types.int(IntKind::SChar);
1720 assert!(!compatible(&types, char_, schar));
1721 let atomic = types.atomic(int);
1723 assert!(!compatible(&types, atomic, int));
1724 }
1725
1726 #[test]
1727 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1728 let mut types = Types::new();
1731 let uint = types.int(IntKind::UInt);
1732 let int = types.int(IntKind::Int);
1733 let id = types.declare_enum(None);
1734 types.complete_enum(id, uint, false);
1735 let e = types.enumeration(id);
1736 assert!(compatible(&types, e, uint));
1737 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1738 assert!(!compatible(&types, e, int));
1739
1740 let other = types.declare_enum(None);
1743 types.complete_enum(other, uint, false);
1744 let other = types.enumeration(other);
1745 assert!(!compatible(&types, e, other));
1746
1747 let undecided = types.declare_enum(None);
1750 let undecided = types.enumeration(undecided);
1751 assert!(!compatible(&types, undecided, uint));
1752 assert!(compatible(&types, undecided, undecided));
1753 }
1754
1755 #[test]
1756 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1757 let mut types = Types::new();
1760 let int = types.int(IntKind::Int);
1761 let unknown = types.array(int, ArrayLen::Unknown);
1762 let four = types.array(int, ArrayLen::Fixed(4));
1763 let five = types.array(int, ArrayLen::Fixed(5));
1764 assert!(compatible(&types, unknown, four));
1765 assert!(!compatible(&types, four, five));
1766 assert_eq!(composite(&mut types, unknown, four), Some(four));
1767 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1768 assert_eq!(composite(&mut types, four, five), None);
1769
1770 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1773 assert!(compatible(&types, vla, four));
1774 assert_eq!(composite(&mut types, vla, four), Some(four));
1775
1776 let long = types.int(IntKind::Long);
1778 let longs = types.array(long, ArrayLen::Fixed(4));
1779 assert!(!compatible(&types, four, longs));
1780 }
1781
1782 #[test]
1783 fn a_parameter_declared_as_an_array_is_a_pointer() {
1784 let mut types = Types::new();
1788 let int = types.int(IntKind::Int);
1789 let three = types.array(int, ArrayLen::Fixed(3));
1790 let pointer = types.pointer(int);
1791 assert_eq!(adjust_parameter(&mut types, three), pointer);
1792
1793 let function = prototype(&mut types, vec![int], false);
1795 let function_pointer = types.pointer(function);
1796 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1797
1798 let konst = types.qualified(int, Qualifiers::CONST);
1801 assert_eq!(adjust_parameter(&mut types, konst), int);
1802 let to_konst = types.pointer(konst);
1803 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1804 }
1805
1806 #[test]
1807 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1808 let mut types = Types::new();
1812 let old = old_style(&mut types);
1813 let int = types.int(IntKind::Int);
1814 let long = types.int(IntKind::Long);
1815 let char_ = types.int(IntKind::Char);
1816 let float = types.float(FloatKind::Float);
1817 let double = types.float(FloatKind::Double);
1818
1819 let takes_int = prototype(&mut types, vec![int], false);
1820 assert!(compatible(&types, old, takes_int));
1821 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1822 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1824
1825 let pointer = types.pointer(int);
1826 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1827 let ty = prototype(&mut types, params, false);
1828 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1829 }
1830
1831 for params in [vec![char_], vec![float], vec![int, char_]] {
1834 let ty = prototype(&mut types, params, false);
1835 assert!(!compatible(&types, old, ty));
1836 assert_eq!(composite(&mut types, old, ty), None);
1837 }
1838
1839 let variadic = prototype(&mut types, vec![int], true);
1841 assert!(!compatible(&types, old, variadic));
1842
1843 let uint = types.int(IntKind::UInt);
1845 let id = types.declare_enum(None);
1846 types.complete_enum(id, uint, false);
1847 let e = types.enumeration(id);
1848 let takes_enum = prototype(&mut types, vec![e], false);
1849 assert!(compatible(&types, old, takes_enum));
1850
1851 assert!(compatible(&types, old, old));
1853
1854 let returns_int = types.function(FunctionType {
1856 ret: int,
1857 params: Vec::new(),
1858 variadic: false,
1859 prototyped: false,
1860 });
1861 assert!(!compatible(&types, returns_int, takes_int));
1862 }
1863
1864 #[test]
1865 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1866 let mut types = Types::new();
1870 let int = types.int(IntKind::Int);
1871 let takes_int = prototype(&mut types, vec![int], false);
1872 let takes_nothing = prototype(&mut types, Vec::new(), false);
1873 let old = old_style(&mut types);
1874 assert!(!compatible(&types, takes_nothing, takes_int));
1875 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1876 }
1877
1878 #[test]
1879 fn two_prototypes_have_to_agree_about_everything() {
1880 let mut types = Types::new();
1881 let int = types.int(IntKind::Int);
1882 let long = types.int(IntKind::Long);
1883 let base = prototype(&mut types, vec![int, int], false);
1884 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1885 let other = prototype(&mut types, other, false);
1886 assert!(!compatible(&types, base, other));
1887 }
1888 let variadic = prototype(&mut types, vec![int, int], true);
1889 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1890
1891 let four = types.array(int, ArrayLen::Fixed(4));
1894 let unknown = types.array(int, ArrayLen::Unknown);
1895 let to_four = types.pointer(four);
1896 let to_unknown = types.pointer(unknown);
1897 let a = prototype(&mut types, vec![to_four], false);
1898 let b = prototype(&mut types, vec![to_unknown], false);
1899 assert!(compatible(&types, a, b));
1900 assert_eq!(composite(&mut types, a, b), Some(a));
1902 }
1903
1904 #[test]
1905 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1906 let mut types = Types::new();
1907 let int = types.int(IntKind::Int);
1908 let four = types.array(int, ArrayLen::Fixed(4));
1909 let unknown = types.array(int, ArrayLen::Unknown);
1910 let to_four = types.pointer(four);
1911 let to_unknown = types.pointer(unknown);
1912 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1913
1914 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1916 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1917 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1918 }
1919
1920 #[test]
1921 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1922 let mut interner = Interner::new();
1926 let mut types = Types::new();
1927 let tag = interner.intern("point");
1928 let x = interner.intern("x");
1929 let y = interner.intern("y");
1930 let int = types.int(IntKind::Int);
1931 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1932
1933 let first = tagged(&mut types, tag, &members);
1934 let second = tagged(&mut types, tag, &members);
1935 let first = types.record(first);
1936 let second = types.record(second);
1937 assert_ne!(first, second, "still two declarations and two types");
1938 assert!(compatible(&types, first, second));
1939
1940 let z = interner.intern("z");
1943 let long = types.int(IntKind::Long);
1944 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1945 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1946 for other in [&renamed[..], &retyped[..], &members[..1]] {
1947 let other = tagged(&mut types, tag, other);
1948 let other = types.record(other);
1949 assert!(!compatible(&types, first, other));
1950 }
1951 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1952 let elsewhere = types.record(elsewhere);
1953 assert!(!compatible(&types, first, elsewhere));
1954
1955 let anonymous = record(&mut types, RecordKind::Struct, &members);
1958 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1959 assert!(!compatible(&types, anonymous, also_anonymous));
1960
1961 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1963 let incomplete = types.record(incomplete);
1964 assert!(!compatible(&types, first, incomplete));
1965 assert!(compatible(&types, incomplete, incomplete));
1966 }
1967
1968 #[test]
1969 fn a_self_referential_record_is_compared_without_going_round_forever() {
1970 let mut interner = Interner::new();
1974 let mut types = Types::new();
1975 let tag = interner.intern("node");
1976 let value = interner.intern("value");
1977 let next = interner.intern("next");
1978 let int = types.int(IntKind::Int);
1979
1980 let node = |types: &mut Types| {
1981 let id = types.declare_record(RecordKind::Struct, Some(tag));
1982 let ty = types.record(id);
1983 let pointer = types.pointer(ty);
1984 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1985 let laid_out = lay_out(types, RecordKind::Struct, &members);
1986 types.complete_record(id, laid_out);
1987 ty
1988 };
1989 let first = node(&mut types);
1990 let second = node(&mut types);
1991 assert_ne!(first, second);
1992 assert!(compatible(&types, first, second));
1993
1994 let id = types.declare_record(RecordKind::Struct, Some(tag));
1997 let ty = types.record(id);
1998 let pointer = types.pointer(ty);
1999 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
2000 let laid_out = lay_out(&types, RecordKind::Struct, &members);
2001 types.complete_record(id, laid_out);
2002 assert!(!compatible(&types, first, ty));
2003 }
2004
2005 #[test]
2006 fn layout_reads_through_sugar() {
2007 let mut interner = Interner::new();
2008 let mut types = Types::new();
2009 let long = types.int(IntKind::Long);
2010 let name = types.typedef(interner.intern("word"), long);
2011 let array = types.array(name, ArrayLen::Fixed(4));
2012 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
2013 }
2014
2015 fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
2021 match recipe {
2022 Extent::Bytes(count) => *count,
2023 Extent::Member(index) => sizes[*index as usize],
2024 Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
2025 Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
2026 Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
2027 }
2028 }
2029
2030 fn measured(types: &mut Types, which: u32) -> TypeId {
2032 let int = types.int(IntKind::Int);
2033 types.array(int, ArrayLen::Variable(VlaId(which)))
2034 }
2035
2036 #[test]
2037 fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2038 let mut types = Types::new();
2039 let int = types.int(IntKind::Int);
2040 let rows = measured(&mut types, 0);
2041 let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2042
2043 assert_eq!(laid_out.layout, Layout::new(0, 4));
2046 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2047 assert_eq!(variable.offsets[0], None);
2051 let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2052 for count in 0..6u64 {
2053 let sizes = [4 * count, 4];
2054 assert_eq!(work_out(after, &sizes), 4 * count);
2055 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2056 }
2057 assert_eq!(laid_out.fields[1].align, 4);
2058 }
2059
2060 #[test]
2061 fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2062 let mut types = Types::new();
2063 let char_ty = types.int(IntKind::Char);
2064 let rows = measured(&mut types, 0);
2065 let double = types.float(FloatKind::Double);
2066 let fields = [member(char_ty), member(rows), member(double)];
2067 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2068
2069 assert_eq!(laid_out.layout, Layout::new(0, 8));
2070 assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2071 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2072 assert_eq!(variable.offsets[..2], [None, None]);
2073 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2074 for count in 0..6u64 {
2075 let sizes = [1, 4 * count, 8];
2076 let at = (4 + 4 * count).next_multiple_of(8);
2077 assert_eq!(work_out(after, &sizes), at);
2078 assert_eq!(work_out(&variable.size, &sizes), at + 8);
2079 }
2080 }
2081
2082 #[test]
2083 fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2084 let mut types = Types::new();
2085 let rows = measured(&mut types, 0);
2086 let double = types.float(FloatKind::Double);
2087 let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2088
2089 assert_eq!(laid_out.layout, Layout::new(0, 8));
2090 let variable = laid_out.variable.expect("a union with a member of no fixed size");
2091 assert!(variable.offsets.iter().all(Option::is_none));
2094 for count in 0..6u64 {
2095 let sizes = [4 * count, 8];
2096 let want = (4 * count).max(8).next_multiple_of(8);
2097 assert_eq!(work_out(&variable.size, &sizes), want);
2098 }
2099 }
2100
2101 #[test]
2102 fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2103 let mut types = Types::new();
2104 let char_ty = types.int(IntKind::Char);
2105 let int = types.int(IntKind::Int);
2106 let rows = measured(&mut types, 0);
2107 let fields = [member(char_ty), member(rows), member(int)];
2108 let options = RecordOptions { packed: true, ..RecordOptions::default() };
2109 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2110 .expect("a packed record with a member of no fixed size");
2111
2112 assert_eq!(laid_out.layout, Layout::new(0, 1));
2113 assert_eq!(laid_out.fields[2].align, 1);
2114 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2115 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2116 for count in 0..6u64 {
2117 let sizes = [1, 4 * count, 4];
2118 assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2119 assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2120 }
2121 }
2122
2123 #[test]
2124 fn bit_fields_after_a_member_of_no_fixed_size_are_placed_one_after_another() {
2125 let mut interner = Interner::new();
2126 let mut types = Types::new();
2127 let int = types.int(IntKind::Int);
2128 let char_ty = types.int(IntKind::Char);
2129 let rows = measured(&mut types, 0);
2130 let fields = [
2131 member(rows),
2132 bits(&mut interner, "b", int, 3),
2133 bits(&mut interner, "c", int, 30),
2134 member(char_ty),
2135 ];
2136 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2137
2138 assert_eq!((laid_out.fields[2].offset, laid_out.fields[2].bit), (0, 3));
2142 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2143 let after = variable.offsets[3].as_ref().expect("an offset the program works out");
2144 for count in 0..6u64 {
2145 let sizes = [4 * count, 4, 4, 1];
2146 assert_eq!(work_out(after, &sizes), 4 * count + 5);
2147 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 8);
2148 }
2149 }
2150
2151 #[test]
2152 fn a_zero_width_bit_field_that_needs_more_alignment_than_is_known_is_turned_down() {
2153 let mut types = Types::new();
2154 let int = types.int(IntKind::Int);
2155 let char_ty = types.int(IntKind::Char);
2156 let letters = types.array(char_ty, ArrayLen::Variable(VlaId(0)));
2157 let fields = [member(letters), unnamed_bits(int, 0)];
2158 let options = RecordOptions::default();
2159 let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2160
2161 assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2165 }
2166}