1#![doc(html_root_url = "https://docs.rs/rucc-types/0.12.2")]
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 let int_ = types.int(IntKind::Int);
1075 let narrow = [
1076 bits(&mut interner, "a", char_, 1),
1077 unnamed_bits(int_, 0),
1078 bits(&mut interner, "b", char_, 1),
1079 ];
1080 for target in [windows(), target("x86_64-pc-windows-gnu")] {
1081 let ms = lay_out_on(&target, &types, RecordKind::Struct, &narrow);
1082 assert_eq!(ms.layout, Layout::new(8, 4));
1083 assert_eq!(offsets(&ms), [0, 32, 32]);
1084 }
1085 }
1086
1087 #[test]
1088 fn msvc_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1089 let mut interner = Interner::new();
1090 let types = Types::new();
1091 let char_ = types.int(IntKind::Char);
1092 let uint = types.int(IntKind::UInt);
1093
1094 let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1097 assert_eq!(
1098 lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1099 Layout::new(4, 1)
1100 );
1101 assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1102 let mingw = target("x86_64-pc-windows-gnu");
1105 assert_eq!(
1106 lay_out_on(&mingw, &types, RecordKind::Union, &fields).layout,
1107 Layout::new(4, 4)
1108 );
1109 }
1110
1111 #[test]
1112 fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1113 let mut types = Types::new();
1114 let uint = types.int(IntKind::UInt);
1115 let mingw = target("x86_64-pc-windows-gnu");
1116
1117 let none: [FieldDecl; 0] = [];
1119 let zero_width = [unnamed_bits(uint, 0)];
1120 let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1121 for fields in [&none[..], &zero_width[..], &flexible[..]] {
1122 let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1123 assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1124 assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1125 assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1126 }
1127
1128 assert_eq!(windows().empty_record_size, 4);
1132 assert_eq!(mingw.empty_record_size, 0);
1133 }
1134
1135 #[test]
1136 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
1137 let mut interner = Interner::new();
1138 let types = Types::new();
1139 let char_ = types.int(IntKind::Char);
1140 let int = types.int(IntKind::Int);
1141 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1142
1143 let fields = [member(char_), member(int)];
1144 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1145 .expect("a packed struct of two complete members");
1146 assert_eq!(laid_out.layout, Layout::new(5, 1));
1147 assert_eq!(offsets(&laid_out), [0, 8]);
1148
1149 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1150 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1151 .expect("a packed struct with a bit-field");
1152 assert_eq!(laid_out.layout, Layout::new(5, 1));
1153 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1154
1155 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1158 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1159 .expect("a packed struct with a zero width bit-field");
1160 assert_eq!(laid_out.layout, Layout::new(5, 1));
1161 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1162 }
1163
1164 #[test]
1165 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1166 let mut interner = Interner::new();
1167 let types = Types::new();
1168 let char_ = types.int(IntKind::Char);
1169 let int = types.int(IntKind::Int);
1170 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1171
1172 let fields = [member(char_), member(int)];
1173 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1174 .expect("a packed struct of two complete members");
1175 assert_eq!(laid_out.layout, Layout::new(6, 2));
1176 assert_eq!(offsets(&laid_out), [0, 16]);
1177
1178 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1182 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1183 .expect("a packed struct with a bit-field");
1184 assert_eq!(laid_out.layout, Layout::new(6, 2));
1185 assert_eq!(offsets(&laid_out), [0, 8]);
1186
1187 let fields = [member(char_), unnamed_bits(int, 30)];
1190 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1191 .expect("a packed struct with an unnamed bit-field");
1192 assert_eq!(laid_out.layout, Layout::new(5, 1));
1193 }
1194
1195 #[test]
1196 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1197 let types = Types::new();
1198 let char_ = types.int(IntKind::Char);
1199 let int = types.int(IntKind::Int);
1200
1201 let aligned = FieldDecl { align: Some(16), ..member(int) };
1202 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1203 assert_eq!(laid_out.layout, Layout::new(32, 16));
1204 assert_eq!(offsets(&laid_out), [0, 128]);
1205
1206 let options = RecordOptions { packed: true, align: Some(4), pack: None };
1209 let fields = [member(char_), member(int)];
1210 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1211 .expect("a packed struct with an alignment asked for");
1212 assert_eq!(laid_out.layout, Layout::new(8, 4));
1213 assert_eq!(offsets(&laid_out), [0, 8]);
1214 }
1215
1216 #[test]
1217 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1218 let mut types = Types::new();
1220 let char_ = types.int(IntKind::Char);
1221 let int = types.int(IntKind::Int);
1222 let long_long = types.int(IntKind::LongLong);
1223
1224 let chars = types.array(char_, ArrayLen::Unknown);
1225 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1226 assert_eq!(laid_out.layout, Layout::new(4, 4));
1227 assert_eq!(offsets(&laid_out), [0, 32]);
1228
1229 let longs = types.array(long_long, ArrayLen::Unknown);
1231 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1232 assert_eq!(laid_out.layout, Layout::new(8, 8));
1233 assert_eq!(offsets(&laid_out), [0, 64]);
1234
1235 let fields = [member(chars), member(int)];
1237 let error =
1238 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1239 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1240 }
1241
1242 #[test]
1243 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1244 let types = Types::new();
1246 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1247 assert_eq!(laid_out.layout, Layout::new(0, 1));
1248 }
1249
1250 #[test]
1251 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1252 let types = Types::new();
1253 let int = types.int(IntKind::Int);
1254 let fields = [unnamed_bits(int, 33)];
1255 let error =
1256 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1257 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1258 assert_eq!(error, Err(want));
1259 }
1260
1261 #[test]
1262 fn a_record_reports_its_members_once_it_has_been_completed() {
1263 let mut interner = Interner::new();
1264 let mut types = Types::new();
1265 let char_ = types.int(IntKind::Char);
1266 let int = types.int(IntKind::Int);
1267 let name = interner.intern("count");
1268 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1269 let id = types.declare_record(RecordKind::Struct, None);
1270 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1271 types.complete_record(id, laid_out);
1272 let ty = types.record(id);
1273 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1274 let field = types.field(id, name).expect("the member that was declared");
1275 assert_eq!(field.offset, 4);
1276 assert!(!field.is_bit_field());
1277 assert_eq!(types.field(id, interner.intern("missing")), None);
1278 }
1279
1280 #[test]
1281 fn a_nested_record_brings_its_own_alignment_with_it() {
1282 let mut types = Types::new();
1283 let char_ = types.int(IntKind::Char);
1284 let int = types.int(IntKind::Int);
1285 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1286 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1287 assert_eq!(laid_out.layout, Layout::new(8, 4));
1288 assert_eq!(offsets(&laid_out), [0, 32]);
1289
1290 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1293 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1294 assert_eq!(laid_out.layout, Layout::new(12, 4));
1295 assert_eq!(offsets(&laid_out), [0, 32]);
1296 }
1297
1298 #[test]
1299 fn everything_narrower_than_an_int_promotes_to_one() {
1300 let mut types = Types::new();
1304 let linux = linux();
1305 let int = types.int(IntKind::Int);
1306 let narrow =
1307 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1308 for kind in narrow {
1309 let ty = types.int(kind);
1310 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1311 }
1312 let boolean = types.boolean();
1313 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1314
1315 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1317 let ty = types.int(kind);
1318 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1319 }
1320 }
1321
1322 #[test]
1323 fn a_bit_int_is_not_promoted_at_all() {
1324 let mut types = Types::new();
1327 let linux = linux();
1328 let small = types.bit_int(true, 8);
1329 assert_eq!(promote(&mut types, small, &linux), small);
1330 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1331 }
1332
1333 #[test]
1334 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1335 let mut types = Types::new();
1336 let linux = linux();
1337 let int = types.int(IntKind::Int);
1338 let uint = types.int(IntKind::UInt);
1339 let ullong = types.int(IntKind::ULongLong);
1340
1341 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1343 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1345 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1347 let forty = types.bit_int(false, 40);
1352 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1353 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1355 }
1356
1357 #[test]
1358 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1359 let mut types = Types::new();
1360 let linux = linux();
1361 let int = types.int(IntKind::Int);
1362 let short = types.int(IntKind::Short);
1363 let uint = types.int(IntKind::UInt);
1364
1365 let fixed = types.declare_enum(None);
1367 types.complete_enum(fixed, short, true);
1368 let fixed = types.enumeration(fixed);
1369 assert_eq!(promote(&mut types, fixed, &linux), int);
1370
1371 let unsigned = types.declare_enum(None);
1374 types.complete_enum(unsigned, uint, false);
1375 let unsigned = types.enumeration(unsigned);
1376 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1377
1378 let undecided = types.declare_enum(None);
1381 let undecided = types.enumeration(undecided);
1382 assert_eq!(promote(&mut types, undecided, &linux), int);
1383 }
1384
1385 #[test]
1386 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1387 let mut types = Types::new();
1390 let linux = linux();
1391 let int = types.int(IntKind::Int);
1392 let konst = types.qualified(int, Qualifiers::CONST);
1393 let atomic = types.atomic(konst);
1394 assert_eq!(promote(&mut types, atomic, &linux), int);
1395 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1396 }
1397
1398 #[test]
1399 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1400 let mut types = Types::new();
1402 let linux = linux();
1403 let cases = [
1404 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1405 (IntKind::Int, IntKind::Long, IntKind::Long),
1406 (IntKind::UInt, IntKind::Long, IntKind::Long),
1407 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1408 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1409 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1410 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1411 (IntKind::Char, IntKind::Char, IntKind::Int),
1412 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1413 ];
1414 for (left, right, want) in cases {
1415 let left = types.int(left);
1416 let right = types.int(right);
1417 let want = types.int(want);
1418 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1419 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1420 }
1421 }
1422
1423 #[test]
1424 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1425 let mut types = Types::new();
1429 let linux = linux();
1430 let signed = types.int(IntKind::Int128);
1431 let unsigned = types.int(IntKind::UInt128);
1432 for id in [signed, unsigned] {
1433 let laid_out = layout(&types, id, &linux).expect("a complete type");
1434 assert_eq!(laid_out.size, 16);
1435 assert_eq!(laid_out.align, 16);
1436 }
1437
1438 let ull = types.int(IntKind::ULongLong);
1442 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1443 assert_eq!(promote(&mut types, signed, &linux), signed);
1445 }
1446
1447 #[test]
1448 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1449 let mut types = Types::new();
1452 let linux = linux();
1453 let int128 = types.int(IntKind::Int128);
1454 let bit_int = types.bit_int(true, 128);
1455 assert_ne!(int128, bit_int);
1456 assert!(!compatible(&types, int128, bit_int));
1457 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1458 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1459 }
1460
1461 #[test]
1462 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1463 let mut types = Types::new();
1467 let linux = linux();
1468 let ulong = types.int(IntKind::ULong);
1469 let long_long = types.int(IntKind::LongLong);
1470 let want = types.int(IntKind::ULongLong);
1471 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1472
1473 let windows = target("x86_64-pc-windows-msvc");
1477 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1478 }
1479
1480 #[test]
1481 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1482 let mut types = Types::new();
1484 let linux = linux();
1485 let b40 = types.bit_int(true, 40);
1486 let ub40 = types.bit_int(false, 40);
1487 let b8 = types.bit_int(true, 8);
1488 let b32 = types.bit_int(true, 32);
1489 let int = types.int(IntKind::Int);
1490 let uint = types.int(IntKind::UInt);
1491 let long = types.int(IntKind::Long);
1492 let char_ = types.int(IntKind::Char);
1493
1494 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1496 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1498 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1500 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1501 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1504 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1507 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1508 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1510 }
1511
1512 #[test]
1513 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1514 let mut types = Types::new();
1515 let linux = linux();
1516 let float = types.float(FloatKind::Float);
1517 let double = types.float(FloatKind::Double);
1518 let long_double = types.float(FloatKind::LongDouble);
1519 let ullong = types.int(IntKind::ULongLong);
1520 let int = types.int(IntKind::Int);
1521
1522 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1523 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1524 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1525 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1528 }
1529
1530 #[test]
1531 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1532 let mut types = Types::new();
1533 let linux = linux();
1534 let int = types.int(IntKind::Int);
1535 let float = types.float(FloatKind::Float);
1536 let short = types.int(IntKind::Short);
1537
1538 let four_ints = types.vector(int, 4);
1540 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1541
1542 let uint = types.int(IntKind::UInt);
1545 let four_uints = types.vector(uint, 4);
1546 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1547
1548 let four_floats = types.vector(float, 4);
1551 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1552
1553 let two_shorts = types.vector(short, 2);
1555 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1556
1557 assert_eq!(mask_of(&mut types, int, &linux), None);
1559 }
1560
1561 #[test]
1562 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1563 let mut types = Types::new();
1564 let linux = linux();
1565 let int = types.int(IntKind::Int);
1566 let uint = types.int(IntKind::UInt);
1567 let float = types.float(FloatKind::Float);
1568 let short = types.int(IntKind::Short);
1569
1570 let four_ints = types.vector(int, 4);
1571 let four_uints = types.vector(uint, 4);
1572 let four_floats = types.vector(float, 4);
1573 let eight_shorts = types.vector(short, 8);
1574 let two_ints = types.vector(int, 2);
1575
1576 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1579 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1581 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1583 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1585
1586 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1589 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1591 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1593 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1594 }
1595
1596 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1601 let mut types = Types::new();
1602 let left = types.float(a);
1603 let right = types.float(b);
1604 let want = types.float(expected);
1605 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1606 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1607 }
1608
1609 #[test]
1610 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1611 let x86 = linux();
1615 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1616 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1617 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1618 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1619 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1620 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1621 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1622 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1623 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1624 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1625 }
1626
1627 #[test]
1628 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1629 let mac = target("aarch64-apple-darwin");
1633 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1634 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1635 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1636 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1637 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1638 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1639 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1640 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1643 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1644 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1645 }
1646
1647 #[test]
1648 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1649 let mut types = Types::new();
1650 let linux = linux();
1651 let cfloat = types.complex_float(FloatKind::Float);
1652 let cdouble = types.complex_float(FloatKind::Double);
1653 let cldouble = types.complex_float(FloatKind::LongDouble);
1654 let double = types.float(FloatKind::Double);
1655 let long_double = types.float(FloatKind::LongDouble);
1656 let float = types.float(FloatKind::Float);
1657 let int = types.int(IntKind::Int);
1658
1659 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1660 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1661 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1662 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1663 }
1664
1665 #[test]
1666 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1667 let mut types = Types::new();
1669 let linux = linux();
1670 let int = types.int(IntKind::Int);
1671 let pointer = types.pointer(int);
1672 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1673 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1674 let void = types.void();
1675 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1676 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1679 }
1680
1681 #[test]
1682 fn the_conversions_read_through_sugar() {
1683 let mut interner = Interner::new();
1684 let mut types = Types::new();
1685 let linux = linux();
1686 let char_ = types.int(IntKind::Char);
1687 let name = types.typedef(interner.intern("byte"), char_);
1688 let int = types.int(IntKind::Int);
1689 assert_eq!(promote(&mut types, name, &linux), int);
1690 }
1691
1692 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1694 let ret = types.void();
1695 types.function(FunctionType { ret, params, variadic, prototyped: true })
1696 }
1697
1698 fn old_style(types: &mut Types) -> TypeId {
1700 let ret = types.void();
1701 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1702 }
1703
1704 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1706 let id = types.declare_record(RecordKind::Struct, Some(tag));
1707 let laid_out = lay_out(types, RecordKind::Struct, fields);
1708 types.complete_record(id, laid_out);
1709 id
1710 }
1711
1712 #[test]
1713 fn a_type_is_compatible_with_itself_however_it_was_written() {
1714 let mut interner = Interner::new();
1715 let mut types = Types::new();
1716 let int = types.int(IntKind::Int);
1717 let name = types.typedef(interner.intern("int32_t"), int);
1718 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1719 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1720
1721 let konst = types.qualified(int, Qualifiers::CONST);
1724 assert!(!compatible(&types, konst, int));
1725 let konst_pointer = types.pointer(konst);
1726 let pointer = types.pointer(int);
1727 assert!(!compatible(&types, konst_pointer, pointer));
1728 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1729
1730 let char_ = types.int(IntKind::Char);
1733 let schar = types.int(IntKind::SChar);
1734 assert!(!compatible(&types, char_, schar));
1735 let atomic = types.atomic(int);
1737 assert!(!compatible(&types, atomic, int));
1738 }
1739
1740 #[test]
1741 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1742 let mut types = Types::new();
1745 let uint = types.int(IntKind::UInt);
1746 let int = types.int(IntKind::Int);
1747 let id = types.declare_enum(None);
1748 types.complete_enum(id, uint, false);
1749 let e = types.enumeration(id);
1750 assert!(compatible(&types, e, uint));
1751 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1752 assert!(!compatible(&types, e, int));
1753
1754 let other = types.declare_enum(None);
1757 types.complete_enum(other, uint, false);
1758 let other = types.enumeration(other);
1759 assert!(!compatible(&types, e, other));
1760
1761 let undecided = types.declare_enum(None);
1764 let undecided = types.enumeration(undecided);
1765 assert!(!compatible(&types, undecided, uint));
1766 assert!(compatible(&types, undecided, undecided));
1767 }
1768
1769 #[test]
1770 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1771 let mut types = Types::new();
1774 let int = types.int(IntKind::Int);
1775 let unknown = types.array(int, ArrayLen::Unknown);
1776 let four = types.array(int, ArrayLen::Fixed(4));
1777 let five = types.array(int, ArrayLen::Fixed(5));
1778 assert!(compatible(&types, unknown, four));
1779 assert!(!compatible(&types, four, five));
1780 assert_eq!(composite(&mut types, unknown, four), Some(four));
1781 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1782 assert_eq!(composite(&mut types, four, five), None);
1783
1784 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1787 assert!(compatible(&types, vla, four));
1788 assert_eq!(composite(&mut types, vla, four), Some(four));
1789
1790 let long = types.int(IntKind::Long);
1792 let longs = types.array(long, ArrayLen::Fixed(4));
1793 assert!(!compatible(&types, four, longs));
1794 }
1795
1796 #[test]
1797 fn a_parameter_declared_as_an_array_is_a_pointer() {
1798 let mut types = Types::new();
1802 let int = types.int(IntKind::Int);
1803 let three = types.array(int, ArrayLen::Fixed(3));
1804 let pointer = types.pointer(int);
1805 assert_eq!(adjust_parameter(&mut types, three), pointer);
1806
1807 let function = prototype(&mut types, vec![int], false);
1809 let function_pointer = types.pointer(function);
1810 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1811
1812 let konst = types.qualified(int, Qualifiers::CONST);
1815 assert_eq!(adjust_parameter(&mut types, konst), int);
1816 let to_konst = types.pointer(konst);
1817 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1818 }
1819
1820 #[test]
1821 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1822 let mut types = Types::new();
1826 let old = old_style(&mut types);
1827 let int = types.int(IntKind::Int);
1828 let long = types.int(IntKind::Long);
1829 let char_ = types.int(IntKind::Char);
1830 let float = types.float(FloatKind::Float);
1831 let double = types.float(FloatKind::Double);
1832
1833 let takes_int = prototype(&mut types, vec![int], false);
1834 assert!(compatible(&types, old, takes_int));
1835 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1836 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1838
1839 let pointer = types.pointer(int);
1840 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1841 let ty = prototype(&mut types, params, false);
1842 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1843 }
1844
1845 for params in [vec![char_], vec![float], vec![int, char_]] {
1848 let ty = prototype(&mut types, params, false);
1849 assert!(!compatible(&types, old, ty));
1850 assert_eq!(composite(&mut types, old, ty), None);
1851 }
1852
1853 let variadic = prototype(&mut types, vec![int], true);
1855 assert!(!compatible(&types, old, variadic));
1856
1857 let uint = types.int(IntKind::UInt);
1859 let id = types.declare_enum(None);
1860 types.complete_enum(id, uint, false);
1861 let e = types.enumeration(id);
1862 let takes_enum = prototype(&mut types, vec![e], false);
1863 assert!(compatible(&types, old, takes_enum));
1864
1865 assert!(compatible(&types, old, old));
1867
1868 let returns_int = types.function(FunctionType {
1870 ret: int,
1871 params: Vec::new(),
1872 variadic: false,
1873 prototyped: false,
1874 });
1875 assert!(!compatible(&types, returns_int, takes_int));
1876 }
1877
1878 #[test]
1879 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1880 let mut types = Types::new();
1884 let int = types.int(IntKind::Int);
1885 let takes_int = prototype(&mut types, vec![int], false);
1886 let takes_nothing = prototype(&mut types, Vec::new(), false);
1887 let old = old_style(&mut types);
1888 assert!(!compatible(&types, takes_nothing, takes_int));
1889 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1890 }
1891
1892 #[test]
1893 fn two_prototypes_have_to_agree_about_everything() {
1894 let mut types = Types::new();
1895 let int = types.int(IntKind::Int);
1896 let long = types.int(IntKind::Long);
1897 let base = prototype(&mut types, vec![int, int], false);
1898 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1899 let other = prototype(&mut types, other, false);
1900 assert!(!compatible(&types, base, other));
1901 }
1902 let variadic = prototype(&mut types, vec![int, int], true);
1903 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1904
1905 let four = types.array(int, ArrayLen::Fixed(4));
1908 let unknown = types.array(int, ArrayLen::Unknown);
1909 let to_four = types.pointer(four);
1910 let to_unknown = types.pointer(unknown);
1911 let a = prototype(&mut types, vec![to_four], false);
1912 let b = prototype(&mut types, vec![to_unknown], false);
1913 assert!(compatible(&types, a, b));
1914 assert_eq!(composite(&mut types, a, b), Some(a));
1916 }
1917
1918 #[test]
1919 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1920 let mut types = Types::new();
1921 let int = types.int(IntKind::Int);
1922 let four = types.array(int, ArrayLen::Fixed(4));
1923 let unknown = types.array(int, ArrayLen::Unknown);
1924 let to_four = types.pointer(four);
1925 let to_unknown = types.pointer(unknown);
1926 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1927
1928 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1930 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1931 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1932 }
1933
1934 #[test]
1935 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1936 let mut interner = Interner::new();
1940 let mut types = Types::new();
1941 let tag = interner.intern("point");
1942 let x = interner.intern("x");
1943 let y = interner.intern("y");
1944 let int = types.int(IntKind::Int);
1945 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1946
1947 let first = tagged(&mut types, tag, &members);
1948 let second = tagged(&mut types, tag, &members);
1949 let first = types.record(first);
1950 let second = types.record(second);
1951 assert_ne!(first, second, "still two declarations and two types");
1952 assert!(compatible(&types, first, second));
1953
1954 let z = interner.intern("z");
1957 let long = types.int(IntKind::Long);
1958 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1959 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1960 for other in [&renamed[..], &retyped[..], &members[..1]] {
1961 let other = tagged(&mut types, tag, other);
1962 let other = types.record(other);
1963 assert!(!compatible(&types, first, other));
1964 }
1965 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1966 let elsewhere = types.record(elsewhere);
1967 assert!(!compatible(&types, first, elsewhere));
1968
1969 let anonymous = record(&mut types, RecordKind::Struct, &members);
1972 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1973 assert!(!compatible(&types, anonymous, also_anonymous));
1974
1975 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1977 let incomplete = types.record(incomplete);
1978 assert!(!compatible(&types, first, incomplete));
1979 assert!(compatible(&types, incomplete, incomplete));
1980 }
1981
1982 #[test]
1983 fn a_self_referential_record_is_compared_without_going_round_forever() {
1984 let mut interner = Interner::new();
1988 let mut types = Types::new();
1989 let tag = interner.intern("node");
1990 let value = interner.intern("value");
1991 let next = interner.intern("next");
1992 let int = types.int(IntKind::Int);
1993
1994 let node = |types: &mut Types| {
1995 let id = types.declare_record(RecordKind::Struct, Some(tag));
1996 let ty = types.record(id);
1997 let pointer = types.pointer(ty);
1998 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1999 let laid_out = lay_out(types, RecordKind::Struct, &members);
2000 types.complete_record(id, laid_out);
2001 ty
2002 };
2003 let first = node(&mut types);
2004 let second = node(&mut types);
2005 assert_ne!(first, second);
2006 assert!(compatible(&types, first, second));
2007
2008 let id = types.declare_record(RecordKind::Struct, Some(tag));
2011 let ty = types.record(id);
2012 let pointer = types.pointer(ty);
2013 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
2014 let laid_out = lay_out(&types, RecordKind::Struct, &members);
2015 types.complete_record(id, laid_out);
2016 assert!(!compatible(&types, first, ty));
2017 }
2018
2019 #[test]
2020 fn layout_reads_through_sugar() {
2021 let mut interner = Interner::new();
2022 let mut types = Types::new();
2023 let long = types.int(IntKind::Long);
2024 let name = types.typedef(interner.intern("word"), long);
2025 let array = types.array(name, ArrayLen::Fixed(4));
2026 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
2027 }
2028
2029 fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
2035 match recipe {
2036 Extent::Bytes(count) => *count,
2037 Extent::Member(index) => sizes[*index as usize],
2038 Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
2039 Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
2040 Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
2041 }
2042 }
2043
2044 fn measured(types: &mut Types, which: u32) -> TypeId {
2046 let int = types.int(IntKind::Int);
2047 types.array(int, ArrayLen::Variable(VlaId(which)))
2048 }
2049
2050 #[test]
2051 fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2052 let mut types = Types::new();
2053 let int = types.int(IntKind::Int);
2054 let rows = measured(&mut types, 0);
2055 let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2056
2057 assert_eq!(laid_out.layout, Layout::new(0, 4));
2060 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2061 assert_eq!(variable.offsets[0], None);
2065 let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2066 for count in 0..6u64 {
2067 let sizes = [4 * count, 4];
2068 assert_eq!(work_out(after, &sizes), 4 * count);
2069 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2070 }
2071 assert_eq!(laid_out.fields[1].align, 4);
2072 }
2073
2074 #[test]
2075 fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2076 let mut types = Types::new();
2077 let char_ty = types.int(IntKind::Char);
2078 let rows = measured(&mut types, 0);
2079 let double = types.float(FloatKind::Double);
2080 let fields = [member(char_ty), member(rows), member(double)];
2081 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2082
2083 assert_eq!(laid_out.layout, Layout::new(0, 8));
2084 assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2085 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2086 assert_eq!(variable.offsets[..2], [None, None]);
2087 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2088 for count in 0..6u64 {
2089 let sizes = [1, 4 * count, 8];
2090 let at = (4 + 4 * count).next_multiple_of(8);
2091 assert_eq!(work_out(after, &sizes), at);
2092 assert_eq!(work_out(&variable.size, &sizes), at + 8);
2093 }
2094 }
2095
2096 #[test]
2097 fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2098 let mut types = Types::new();
2099 let rows = measured(&mut types, 0);
2100 let double = types.float(FloatKind::Double);
2101 let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2102
2103 assert_eq!(laid_out.layout, Layout::new(0, 8));
2104 let variable = laid_out.variable.expect("a union with a member of no fixed size");
2105 assert!(variable.offsets.iter().all(Option::is_none));
2108 for count in 0..6u64 {
2109 let sizes = [4 * count, 8];
2110 let want = (4 * count).max(8).next_multiple_of(8);
2111 assert_eq!(work_out(&variable.size, &sizes), want);
2112 }
2113 }
2114
2115 #[test]
2116 fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2117 let mut types = Types::new();
2118 let char_ty = types.int(IntKind::Char);
2119 let int = types.int(IntKind::Int);
2120 let rows = measured(&mut types, 0);
2121 let fields = [member(char_ty), member(rows), member(int)];
2122 let options = RecordOptions { packed: true, ..RecordOptions::default() };
2123 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2124 .expect("a packed record with a member of no fixed size");
2125
2126 assert_eq!(laid_out.layout, Layout::new(0, 1));
2127 assert_eq!(laid_out.fields[2].align, 1);
2128 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2129 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2130 for count in 0..6u64 {
2131 let sizes = [1, 4 * count, 4];
2132 assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2133 assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2134 }
2135 }
2136
2137 #[test]
2138 fn bit_fields_after_a_member_of_no_fixed_size_are_placed_one_after_another() {
2139 let mut interner = Interner::new();
2140 let mut types = Types::new();
2141 let int = types.int(IntKind::Int);
2142 let char_ty = types.int(IntKind::Char);
2143 let rows = measured(&mut types, 0);
2144 let fields = [
2145 member(rows),
2146 bits(&mut interner, "b", int, 3),
2147 bits(&mut interner, "c", int, 30),
2148 member(char_ty),
2149 ];
2150 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2151
2152 assert_eq!((laid_out.fields[2].offset, laid_out.fields[2].bit), (0, 3));
2156 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2157 let after = variable.offsets[3].as_ref().expect("an offset the program works out");
2158 for count in 0..6u64 {
2159 let sizes = [4 * count, 4, 4, 1];
2160 assert_eq!(work_out(after, &sizes), 4 * count + 5);
2161 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 8);
2162 }
2163 }
2164
2165 #[test]
2166 fn a_zero_width_bit_field_that_needs_more_alignment_than_is_known_is_turned_down() {
2167 let mut types = Types::new();
2168 let int = types.int(IntKind::Int);
2169 let char_ty = types.int(IntKind::Char);
2170 let letters = types.array(char_ty, ArrayLen::Variable(VlaId(0)));
2171 let fields = [member(letters), unnamed_bits(int, 0)];
2172 let options = RecordOptions::default();
2173 let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2174
2175 assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2179 }
2180}