1#![doc(html_root_url = "https://docs.rs/rucc-types/0.17.0")]
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, element_as_written, is_aggregate, is_arithmetic, is_array, is_atomic, is_complete,
95 is_complex, is_floating, is_function, is_integer, is_modifiable, is_object, is_pointer,
96 is_real, is_real_floating, is_record, is_scalar, is_vector, is_void, lanes, pointee,
97 pointee_as_written, 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::{BitFieldStyle, 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 an_array_of_an_aligned_typedef_is_as_aligned_as_the_typedef() {
542 let mut interner = Interner::new();
546 let mut types = Types::new();
547 let ull = types.int(IntKind::ULongLong);
548 let part = types.array(ull, ArrayLen::Fixed(2));
549 let float128 = record(&mut types, RecordKind::Struct, &[member(part)]);
550 let sixteen = NonZeroU32::new(16).unwrap();
551 let jbtype = types.aligned_typedef(interner.intern("_JBTYPE"), float128, sixteen);
552 let array = types.array(jbtype, ArrayLen::Fixed(16));
553 let jmp_buf = types.typedef(interner.intern("jmp_buf"), array);
554
555 for target in [linux(), windows(), target("x86_64-pc-windows-gnu")] {
556 assert_eq!(layout(&types, float128, &target), Ok(Layout::new(16, 8)));
557 assert_eq!(layout(&types, array, &target), Ok(Layout::new(256, 16)));
558 assert_eq!(layout(&types, jmp_buf, &target), Ok(Layout::new(256, 16)));
559 let alias = types.typedef(interner.intern("alias_t"), jbtype);
561 let aliased = types.array(alias, ArrayLen::Fixed(16));
562 assert_eq!(layout(&types, aliased, &target), Ok(Layout::new(256, 16)));
563 let two = types.array(jmp_buf, ArrayLen::Fixed(2));
564 assert_eq!(layout(&types, two, &target), Ok(Layout::new(512, 16)));
565 let char_ty = types.int(IntKind::Char);
567 let fields = [member(char_ty), member(jmp_buf)];
568 let laid_out = lay_out_on(&target, &types, RecordKind::Struct, &fields);
569 assert_eq!(offsets(&laid_out), [0, 128]);
570 assert_eq!(laid_out.layout, Layout::new(272, 16));
571 let vla = types.array(jbtype, ArrayLen::Variable(VlaId(0)));
573 assert_eq!(align(&types, vla, &target), Ok(16));
574 }
575 }
576
577 #[test]
578 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
579 let mut interner = Interner::new();
580 let mut types = Types::new();
581 let int = types.int(IntKind::Int);
582 let name = types.typedef(interner.intern("int32_t"), int);
583 let konst = types.qualified(name, Qualifiers::CONST);
584 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
585 let want = types.qualified(int, Qualifiers::CONST);
586 assert_eq!(types.canonical(konst), want);
587 }
588
589 #[test]
590 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
591 let mut interner = Interner::new();
594 let mut types = Types::new();
595 let int = types.int(IntKind::Int);
596 let array = types.array(int, ArrayLen::Fixed(4));
597 let name = types.typedef(interner.intern("A"), array);
598 let konst = types.qualified(name, Qualifiers::CONST);
599 let konst_int = types.qualified(int, Qualifiers::CONST);
600 let want = types.array(konst_int, ArrayLen::Fixed(4));
601 assert_eq!(types.canonical(konst), want);
602 }
603
604 #[test]
605 fn a_function_type_is_deduplicated_by_its_signature() {
606 let mut types = Types::new();
607 let int = types.int(IntKind::Int);
608 let long = types.int(IntKind::Long);
609 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
610 types.function(FunctionType {
611 ret: int,
612 params,
613 variadic,
614 prototyped: true,
615 convention: rucc_target::Convention::Target,
616 })
617 };
618 let a = make(&mut types, vec![int, long], false);
619 let b = make(&mut types, vec![int, long], false);
620 assert_eq!(a, b);
621 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
622 assert_ne!(a, make(&mut types, vec![long, int], false));
623 }
624
625 #[test]
626 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
627 let mut interner = Interner::new();
628 let mut types = Types::new();
629 let int = types.int(IntKind::Int);
630 let name = types.typedef(interner.intern("int32_t"), int);
631 let sugar = types.function(FunctionType {
632 ret: name,
633 params: vec![name],
634 variadic: false,
635 prototyped: true,
636 convention: rucc_target::Convention::Target,
637 });
638 let plain = types.function(FunctionType {
639 ret: int,
640 params: vec![int],
641 variadic: false,
642 prototyped: true,
643 convention: rucc_target::Convention::Target,
644 });
645 assert_ne!(sugar, plain);
646 assert_eq!(types.canonical(sugar), plain);
647 }
648
649 #[test]
650 fn a_record_is_its_declaration_and_not_its_members() {
651 let mut interner = Interner::new();
655 let mut types = Types::new();
656 let tag = interner.intern("point");
657 let first = types.declare_record(RecordKind::Struct, Some(tag));
658 let second = types.declare_record(RecordKind::Struct, Some(tag));
659 assert_ne!(types.record(first), types.record(second));
660 assert_eq!(types.record(first), types.record(first));
661 }
662
663 #[test]
664 fn a_record_has_no_layout_until_it_has_been_completed() {
665 let mut types = Types::new();
666 let id = types.declare_record(RecordKind::Struct, None);
667 let ty = types.record(id);
668 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
669 let long_long = types.int(IntKind::LongLong);
670 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
671 types.complete_record(id, laid_out);
672 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
673 }
674
675 #[test]
676 fn an_enum_takes_the_layout_of_its_underlying_type() {
677 let mut types = Types::new();
678 let id = types.declare_enum(None);
679 let ty = types.enumeration(id);
680 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
681 let int = types.int(IntKind::Int);
682 types.complete_enum(id, int, false);
683 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
684 }
685
686 #[test]
687 fn the_scalar_widths_come_from_the_target() {
688 let mut types = Types::new();
689 let linux = linux();
690 let windows = target("x86_64-pc-windows-msvc");
691 let darwin = target("aarch64-apple-darwin");
692
693 let long = types.int(IntKind::Long);
694 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
695 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
696
697 let ldouble = types.float(FloatKind::LongDouble);
698 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
699 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
700
701 let pointer = types.pointer(types.void());
702 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
703
704 let boolean = types.boolean();
705 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
706 }
707
708 #[test]
709 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
710 let mut types = Types::new();
713 let linux = linux();
714 let cfloat = types.complex_float(FloatKind::Float);
715 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
716 let cdouble = types.complex_float(FloatKind::Double);
717 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
718 let cldouble = types.complex_float(FloatKind::LongDouble);
719 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
720 let darwin = target("aarch64-apple-darwin");
721 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
722 }
723
724 #[test]
725 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
726 let mut types = Types::new();
729 let linux = linux();
730 let long_long = types.int(IntKind::LongLong);
731 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
732 let atomic = types.atomic(plain);
733 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
734 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
735
736 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
738 let atomic_odd = types.atomic(odd);
739 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
740
741 let int = types.int(IntKind::Int);
742 let atomic_int = types.atomic(int);
743 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
744 }
745
746 #[test]
747 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
748 let mut types = Types::new();
751 let linux = linux();
752 let darwin = target("aarch64-apple-darwin");
753 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
754 for (width, size, align) in cases {
755 let ty = types.bit_int(true, width);
756 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
757 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
758 }
759 for width in [65, 96, 128] {
760 let ty = types.bit_int(false, width);
761 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
762 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
763 }
764 let wide = types.bit_int(true, 129);
765 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
766 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
767 }
768
769 #[test]
770 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
771 let mut types = Types::new();
772 let linux = linux();
773 let int = types.int(IntKind::Int);
774 let ty = types.array(int, ArrayLen::Fixed(10));
775 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
776 let nested = types.array(ty, ArrayLen::Fixed(3));
777 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
778 }
779
780 #[test]
781 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
782 let mut types = Types::new();
783 let linux = linux();
784 let int = types.int(IntKind::Int);
785 for len in [ArrayLen::Unknown, ArrayLen::Star] {
786 let ty = types.array(int, len);
787 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
788 }
789 let measured = types.array(int, ArrayLen::Variable(VlaId(0)));
794 assert_eq!(layout(&types, measured, &linux), Err(LayoutError::Variable));
795 assert_eq!(align(&types, measured, &linux), Ok(4));
796 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
797 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
798 }
799
800 #[test]
801 fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
802 let mut types = Types::new();
806 let linux = linux();
807 let max = linux.max_object_size();
808 let ch = types.int(IntKind::Char);
809 let fits = types.array(ch, ArrayLen::Fixed(max));
810 assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
811 let over = types.array(ch, ArrayLen::Fixed(max + 1));
812 assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
813 }
814
815 #[test]
816 fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
817 let mut types = Types::new();
822 let linux = linux();
823 let max = linux.max_object_size();
824 let ch = types.int(IntKind::Char);
825 let int = types.int(IntKind::Int);
826 let short = types.int(IntKind::Short);
827
828 let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
829 let members = [member(huge), member(int), member(int), member(int), member(int)];
830 let laid_out = lay_out(&types, RecordKind::Struct, &members);
831 assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
832
833 let brim = types.array(ch, ArrayLen::Fixed(max));
834 let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
835 assert_eq!(laid_out.layout, Layout::new(max, 1));
836
837 let over = [member(brim), member(ch)];
838 let options = RecordOptions::default();
839 let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
840 assert_eq!(error, Err(RecordError::TooLarge));
841 }
842
843 #[test]
844 fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
845 let mut types = Types::new();
850 let linux = linux();
851 let ch = types.int(IntKind::Char);
852 let int = types.int(IntKind::Int);
853 let mut interner = Interner::new();
854 let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
855 let members = [member(buf), bits(&mut interner, "x", int, 1)];
856 let laid_out = lay_out(&types, RecordKind::Struct, &members);
857 assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
858 let last = laid_out.fields[1];
859 assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
860 assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
861 }
862
863 #[test]
864 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
865 let mut types = Types::new();
866 let int = types.int(IntKind::Int);
867 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
868 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
869 assert_ne!(a, b);
870 }
871
872 #[test]
873 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
874 let mut types = Types::new();
877 let linux = linux();
878 let int = types.int(IntKind::Int);
879 let four = types.vector(int, 4);
880 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
881 let three = types.vector(int, 3);
882 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
883 let three_chars = types.vector(types.int(IntKind::Char), 3);
884 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
885 }
886
887 #[test]
888 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
889 let mut types = Types::new();
892 let linux = linux();
893 let void = types.void();
894 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
895 let int = types.int(IntKind::Int);
896 let function = types.function(FunctionType {
897 ret: int,
898 params: Vec::new(),
899 variadic: false,
900 prototyped: true,
901 convention: rucc_target::Convention::Target,
902 });
903 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
904 let pointer_to_function = types.pointer(function);
905 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
906 }
907
908 #[test]
909 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
910 let types = Types::new();
911 let char_ = types.int(IntKind::Char);
912 let int = types.int(IntKind::Int);
913 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
914 assert_eq!(laid_out.layout, Layout::new(8, 4));
915 assert_eq!(offsets(&laid_out), [0, 32]);
916 assert_eq!(laid_out.fields[1].offset, 4);
917
918 let long_long = types.int(IntKind::LongLong);
920 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
921 assert_eq!(laid_out.layout, Layout::new(16, 8));
922 }
923
924 #[test]
925 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
926 let mut types = Types::new();
927 let char_ = types.int(IntKind::Char);
928 let int = types.int(IntKind::Int);
929 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
930 assert_eq!(laid_out.layout, Layout::new(4, 4));
931 assert_eq!(offsets(&laid_out), [0, 0]);
932
933 let nine = types.array(char_, ArrayLen::Fixed(9));
936 let short = types.int(IntKind::Short);
937 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
938 assert_eq!(laid_out.layout, Layout::new(10, 2));
939 }
940
941 #[test]
942 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
943 let mut interner = Interner::new();
946 let types = Types::new();
947 let char_ = types.int(IntKind::Char);
948 let int = types.int(IntKind::Int);
949 let long_long = types.int(IntKind::LongLong);
950
951 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
952 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
953 assert_eq!(laid_out.layout, Layout::new(4, 4));
954 assert_eq!(offsets(&laid_out), [0, 3]);
955
956 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
958 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
959 assert_eq!(laid_out.layout, Layout::new(8, 4));
960 assert_eq!(offsets(&laid_out), [0, 32]);
961
962 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
965 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
966 assert_eq!(laid_out.layout, Layout::new(8, 8));
967 assert_eq!(offsets(&laid_out), [0, 8]);
968
969 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
971 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
972 assert_eq!(offsets(&laid_out), [0, 8]);
973 }
974
975 #[test]
976 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
977 let types = Types::new();
978 let char_ = types.int(IntKind::Char);
979 let int = types.int(IntKind::Int);
980 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
981 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
982 assert_eq!(laid_out.layout, Layout::new(5, 1));
985 assert_eq!(offsets(&laid_out), [0, 32, 32]);
986 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
987
988 let trailing = [member(char_), unnamed_bits(int, 0)];
992 assert_eq!(lay_out(&types, RecordKind::Struct, &trailing).layout, Layout::new(4, 1));
993
994 let only = [unnamed_bits(int, 0)];
997 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
998 }
999
1000 #[test]
1001 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
1002 let mut interner = Interner::new();
1003 let types = Types::new();
1004 let char_ = types.int(IntKind::Char);
1005 let int = types.int(IntKind::Int);
1006
1007 let unnamed = [member(char_), unnamed_bits(int, 20)];
1008 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
1009 assert_eq!(unnamed.layout, Layout::new(4, 1));
1010
1011 let named = [member(char_), bits(&mut interner, "b", int, 20)];
1012 let named = lay_out(&types, RecordKind::Struct, &named);
1013 assert_eq!(named.layout, Layout::new(4, 4));
1014 assert_eq!(offsets(&named), [0, 8], "the same place either way");
1015
1016 let wider = [member(char_), unnamed_bits(int, 30)];
1019 let wider = lay_out(&types, RecordKind::Struct, &wider);
1020 assert_eq!(wider.layout, Layout::new(8, 1));
1021 assert_eq!(offsets(&wider), [0, 32]);
1022 }
1023
1024 #[test]
1025 fn aapcs64_lets_an_unnamed_bit_field_raise_the_records_alignment() {
1026 let types = Types::new();
1027 let char_ = types.int(IntKind::Char);
1028 let uint = types.int(IntKind::UInt);
1029
1030 let fields = [member(char_), unnamed_bits(uint, 20)];
1032 let arm = lay_out_on(&aapcs(), &types, RecordKind::Struct, &fields);
1033 assert_eq!(arm.layout, Layout::new(4, 4));
1034
1035 let only = [unnamed_bits(uint, 0)];
1038 assert_eq!(
1039 lay_out_on(&aapcs(), &types, RecordKind::Struct, &only).layout,
1040 Layout::new(0, 4)
1041 );
1042 assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
1043
1044 let pushed = [member(char_), unnamed_bits(uint, 0), member(char_)];
1047 let pushed = lay_out_on(&aapcs(), &types, RecordKind::Struct, &pushed);
1048 assert_eq!(pushed.layout, Layout::new(8, 4));
1049 assert_eq!(offsets(&pushed), [0, 32, 32]);
1050 }
1051
1052 #[test]
1053 fn windows_allocates_a_bit_field_into_a_unit_of_its_declared_type() {
1054 let mut interner = Interner::new();
1055 let types = Types::new();
1056 let char_ = types.int(IntKind::Char);
1057 let uint = types.int(IntKind::UInt);
1058 let ushort = types.int(IntKind::UShort);
1059 let longlong = types.int(IntKind::LongLong);
1060
1061 let then_member = [bits(&mut interner, "m0", uint, 3), member(char_)];
1064 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &then_member);
1065 assert_eq!(ms.layout, Layout::new(8, 4));
1066 assert_eq!(offsets(&ms), [0, 32]);
1067 let itanium = lay_out(&types, RecordKind::Struct, &then_member);
1068 assert_eq!(itanium.layout, Layout::new(4, 4));
1069 assert_eq!(offsets(&itanium), [0, 8]);
1070
1071 let narrower = [bits(&mut interner, "m0", uint, 3), bits(&mut interner, "m1", ushort, 5)];
1073 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &narrower);
1074 assert_eq!(ms.layout, Layout::new(8, 4));
1075 assert_eq!(offsets(&ms), [0, 32]);
1076 assert_eq!(lay_out(&types, RecordKind::Struct, &narrower).layout, Layout::new(4, 4));
1077
1078 let wide = [member(char_), bits(&mut interner, "b", longlong, 33)];
1081 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &wide);
1082 assert_eq!(ms.layout, Layout::new(16, 8));
1083 assert_eq!(offsets(&ms), [0, 64]);
1084 let itanium = lay_out(&types, RecordKind::Struct, &wide);
1085 assert_eq!(itanium.layout, Layout::new(8, 8));
1086 assert_eq!(offsets(&itanium), [0, 8]);
1087 }
1088
1089 #[test]
1090 fn microsofts_zero_width_bit_field_closes_a_unit_and_does_nothing_without_one() {
1091 let mut interner = Interner::new();
1092 let types = Types::new();
1093 let char_ = types.int(IntKind::Char);
1094 let uint = types.int(IntKind::UInt);
1095
1096 let alone = [member(char_), unnamed_bits(uint, 0)];
1098 assert_eq!(
1099 lay_out_on(&windows(), &types, RecordKind::Struct, &alone).layout,
1100 Layout::new(1, 1)
1101 );
1102 assert_eq!(lay_out(&types, RecordKind::Struct, &alone).layout, Layout::new(4, 1));
1103
1104 let between = [
1106 bits(&mut interner, "m0", uint, 3),
1107 unnamed_bits(uint, 0),
1108 bits(&mut interner, "m1", uint, 5),
1109 member(char_),
1110 ];
1111 let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &between);
1112 assert_eq!(ms.layout, Layout::new(12, 4));
1113 assert_eq!(offsets(&ms), [0, 32, 32, 64]);
1114 let itanium = lay_out(&types, RecordKind::Struct, &between);
1115 assert_eq!(itanium.layout, Layout::new(8, 4));
1116 assert_eq!(offsets(&itanium), [0, 32, 32, 40]);
1117
1118 let int_ = types.int(IntKind::Int);
1121 let narrow = [
1122 bits(&mut interner, "a", char_, 1),
1123 unnamed_bits(int_, 0),
1124 bits(&mut interner, "b", char_, 1),
1125 ];
1126 for target in [windows(), target("x86_64-pc-windows-gnu")] {
1127 let ms = lay_out_on(&target, &types, RecordKind::Struct, &narrow);
1128 assert_eq!(ms.layout, Layout::new(8, 4));
1129 assert_eq!(offsets(&ms), [0, 32, 32]);
1130 }
1131 }
1132
1133 #[test]
1134 fn ms_struct_and_gcc_struct_choose_the_bit_field_rule_for_one_record() {
1135 let mut interner = Interner::new();
1136 let types = Types::new();
1137 let char_ = types.int(IntKind::Char);
1138 let int_ = types.int(IntKind::Int);
1139 let uint = types.int(IntKind::UInt);
1140 let mingw = target("x86_64-pc-windows-gnu");
1141 let gcc = RecordOptions { bit_fields: Some(BitFieldStyle::Itanium), ..Default::default() };
1142 let ms = RecordOptions { bit_fields: Some(BitFieldStyle::Microsoft), ..Default::default() };
1143 let on = |target: &TargetInfo, options: &RecordOptions, fields: &[FieldDecl]| {
1144 layout_record(&types, RecordKind::Struct, fields, options, target)
1145 .expect("a record every member of which has a layout")
1146 };
1147
1148 let then_member = [bits(&mut interner, "m", uint, 3), member(char_)];
1152 let laid_out = on(&mingw, &gcc, &then_member);
1153 assert_eq!(laid_out.layout, Layout::new(4, 4));
1154 assert_eq!(offsets(&laid_out), [0, 8]);
1155 let laid_out = on(&linux(), &ms, &then_member);
1156 assert_eq!(laid_out.layout, Layout::new(8, 4));
1157 assert_eq!(offsets(&laid_out), [0, 32]);
1158
1159 assert_eq!(
1161 on(&mingw, &ms, &then_member),
1162 on(&mingw, &RecordOptions::default(), &then_member)
1163 );
1164 assert_eq!(
1165 on(&linux(), &gcc, &then_member),
1166 lay_out(&types, RecordKind::Struct, &then_member)
1167 );
1168
1169 let unnamed = [member(char_), unnamed_bits(int_, 20)];
1171 assert_eq!(on(&mingw, &gcc, &unnamed).layout, Layout::new(4, 1));
1172 assert_eq!(on(&linux(), &ms, &unnamed).layout, Layout::new(8, 4));
1173 let arm_mingw = target("aarch64-pc-windows-gnu");
1176 assert_eq!(on(&arm_mingw, &gcc, &unnamed).layout, Layout::new(4, 4));
1177 assert_eq!(on(&arm_mingw, &RecordOptions::default(), &unnamed).layout, Layout::new(8, 4));
1178
1179 let narrow = [
1181 bits(&mut interner, "a", char_, 1),
1182 unnamed_bits(int_, 0),
1183 bits(&mut interner, "b", char_, 1),
1184 ];
1185 let laid_out = on(&mingw, &gcc, &narrow);
1186 assert_eq!(laid_out.layout, Layout::new(5, 1));
1187 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1188 assert_eq!(on(&linux(), &ms, &narrow).layout, Layout::new(8, 4));
1189 let alone = [member(char_), unnamed_bits(uint, 0)];
1190 assert_eq!(on(&mingw, &gcc, &alone).layout, Layout::new(4, 1));
1191 assert_eq!(on(&linux(), &ms, &alone).layout, Layout::new(1, 1));
1192 }
1193
1194 #[test]
1195 fn msvc_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1196 let mut interner = Interner::new();
1197 let types = Types::new();
1198 let char_ = types.int(IntKind::Char);
1199 let uint = types.int(IntKind::UInt);
1200
1201 let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1204 assert_eq!(
1205 lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1206 Layout::new(4, 1)
1207 );
1208 assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1209 let mingw = target("x86_64-pc-windows-gnu");
1212 assert_eq!(
1213 lay_out_on(&mingw, &types, RecordKind::Union, &fields).layout,
1214 Layout::new(4, 4)
1215 );
1216 }
1217
1218 #[test]
1219 fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1220 let mut types = Types::new();
1221 let uint = types.int(IntKind::UInt);
1222 let mingw = target("x86_64-pc-windows-gnu");
1223
1224 let none: [FieldDecl; 0] = [];
1226 let zero_width = [unnamed_bits(uint, 0)];
1227 let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1228 for fields in [&none[..], &zero_width[..], &flexible[..]] {
1229 let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1230 assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1231 assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1232 assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1233 }
1234
1235 assert_eq!(windows().empty_record_size, 4);
1239 assert_eq!(mingw.empty_record_size, 0);
1240 }
1241
1242 #[test]
1243 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
1244 let mut interner = Interner::new();
1245 let types = Types::new();
1246 let char_ = types.int(IntKind::Char);
1247 let int = types.int(IntKind::Int);
1248 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1249
1250 let fields = [member(char_), member(int)];
1251 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1252 .expect("a packed struct of two complete members");
1253 assert_eq!(laid_out.layout, Layout::new(5, 1));
1254 assert_eq!(offsets(&laid_out), [0, 8]);
1255
1256 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1257 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1258 .expect("a packed struct with a bit-field");
1259 assert_eq!(laid_out.layout, Layout::new(5, 1));
1260 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1261
1262 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1265 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1266 .expect("a packed struct with a zero width bit-field");
1267 assert_eq!(laid_out.layout, Layout::new(5, 1));
1268 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1269 }
1270
1271 #[test]
1272 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1273 let mut interner = Interner::new();
1274 let types = Types::new();
1275 let char_ = types.int(IntKind::Char);
1276 let int = types.int(IntKind::Int);
1277 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1278
1279 let fields = [member(char_), member(int)];
1280 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1281 .expect("a packed struct of two complete members");
1282 assert_eq!(laid_out.layout, Layout::new(6, 2));
1283 assert_eq!(offsets(&laid_out), [0, 16]);
1284
1285 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1289 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1290 .expect("a packed struct with a bit-field");
1291 assert_eq!(laid_out.layout, Layout::new(6, 2));
1292 assert_eq!(offsets(&laid_out), [0, 8]);
1293
1294 let fields = [member(char_), unnamed_bits(int, 30)];
1297 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1298 .expect("a packed struct with an unnamed bit-field");
1299 assert_eq!(laid_out.layout, Layout::new(5, 1));
1300 }
1301
1302 #[test]
1303 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1304 let types = Types::new();
1305 let char_ = types.int(IntKind::Char);
1306 let int = types.int(IntKind::Int);
1307
1308 let aligned = FieldDecl { align: Some(16), ..member(int) };
1309 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1310 assert_eq!(laid_out.layout, Layout::new(32, 16));
1311 assert_eq!(offsets(&laid_out), [0, 128]);
1312
1313 let options = RecordOptions { packed: true, align: Some(4), ..RecordOptions::default() };
1316 let fields = [member(char_), member(int)];
1317 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1318 .expect("a packed struct with an alignment asked for");
1319 assert_eq!(laid_out.layout, Layout::new(8, 4));
1320 assert_eq!(offsets(&laid_out), [0, 8]);
1321 }
1322
1323 #[test]
1324 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1325 let mut types = Types::new();
1327 let char_ = types.int(IntKind::Char);
1328 let int = types.int(IntKind::Int);
1329 let long_long = types.int(IntKind::LongLong);
1330
1331 let chars = types.array(char_, ArrayLen::Unknown);
1332 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1333 assert_eq!(laid_out.layout, Layout::new(4, 4));
1334 assert_eq!(offsets(&laid_out), [0, 32]);
1335
1336 let longs = types.array(long_long, ArrayLen::Unknown);
1338 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1339 assert_eq!(laid_out.layout, Layout::new(8, 8));
1340 assert_eq!(offsets(&laid_out), [0, 64]);
1341
1342 let fields = [member(chars), member(int)];
1344 let error =
1345 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1346 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1347 }
1348
1349 #[test]
1350 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1351 let types = Types::new();
1353 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1354 assert_eq!(laid_out.layout, Layout::new(0, 1));
1355 }
1356
1357 #[test]
1358 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1359 let types = Types::new();
1360 let int = types.int(IntKind::Int);
1361 let fields = [unnamed_bits(int, 33)];
1362 let error =
1363 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1364 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1365 assert_eq!(error, Err(want));
1366 }
1367
1368 #[test]
1369 fn a_record_reports_its_members_once_it_has_been_completed() {
1370 let mut interner = Interner::new();
1371 let mut types = Types::new();
1372 let char_ = types.int(IntKind::Char);
1373 let int = types.int(IntKind::Int);
1374 let name = interner.intern("count");
1375 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1376 let id = types.declare_record(RecordKind::Struct, None);
1377 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1378 types.complete_record(id, laid_out);
1379 let ty = types.record(id);
1380 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1381 let field = types.field(id, name).expect("the member that was declared");
1382 assert_eq!(field.offset, 4);
1383 assert!(!field.is_bit_field());
1384 assert_eq!(types.field(id, interner.intern("missing")), None);
1385 }
1386
1387 #[test]
1388 fn a_nested_record_brings_its_own_alignment_with_it() {
1389 let mut types = Types::new();
1390 let char_ = types.int(IntKind::Char);
1391 let int = types.int(IntKind::Int);
1392 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1393 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1394 assert_eq!(laid_out.layout, Layout::new(8, 4));
1395 assert_eq!(offsets(&laid_out), [0, 32]);
1396
1397 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1400 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1401 assert_eq!(laid_out.layout, Layout::new(12, 4));
1402 assert_eq!(offsets(&laid_out), [0, 32]);
1403 }
1404
1405 #[test]
1406 fn everything_narrower_than_an_int_promotes_to_one() {
1407 let mut types = Types::new();
1411 let linux = linux();
1412 let int = types.int(IntKind::Int);
1413 let narrow =
1414 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1415 for kind in narrow {
1416 let ty = types.int(kind);
1417 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1418 }
1419 let boolean = types.boolean();
1420 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1421
1422 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1424 let ty = types.int(kind);
1425 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1426 }
1427 }
1428
1429 #[test]
1430 fn a_bit_int_is_not_promoted_at_all() {
1431 let mut types = Types::new();
1434 let linux = linux();
1435 let small = types.bit_int(true, 8);
1436 assert_eq!(promote(&mut types, small, &linux), small);
1437 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1438 }
1439
1440 #[test]
1441 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1442 let mut types = Types::new();
1443 let linux = linux();
1444 let int = types.int(IntKind::Int);
1445 let uint = types.int(IntKind::UInt);
1446 let ullong = types.int(IntKind::ULongLong);
1447
1448 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1450 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1452 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1454 let forty = types.bit_int(false, 40);
1459 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1460 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1462 }
1463
1464 #[test]
1465 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1466 let mut types = Types::new();
1467 let linux = linux();
1468 let int = types.int(IntKind::Int);
1469 let short = types.int(IntKind::Short);
1470 let uint = types.int(IntKind::UInt);
1471
1472 let fixed = types.declare_enum(None);
1474 types.complete_enum(fixed, short, true);
1475 let fixed = types.enumeration(fixed);
1476 assert_eq!(promote(&mut types, fixed, &linux), int);
1477
1478 let unsigned = types.declare_enum(None);
1481 types.complete_enum(unsigned, uint, false);
1482 let unsigned = types.enumeration(unsigned);
1483 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1484
1485 let undecided = types.declare_enum(None);
1488 let undecided = types.enumeration(undecided);
1489 assert_eq!(promote(&mut types, undecided, &linux), int);
1490 }
1491
1492 #[test]
1493 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1494 let mut types = Types::new();
1497 let linux = linux();
1498 let int = types.int(IntKind::Int);
1499 let konst = types.qualified(int, Qualifiers::CONST);
1500 let atomic = types.atomic(konst);
1501 assert_eq!(promote(&mut types, atomic, &linux), int);
1502 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1503 }
1504
1505 #[test]
1506 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1507 let mut types = Types::new();
1509 let linux = linux();
1510 let cases = [
1511 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1512 (IntKind::Int, IntKind::Long, IntKind::Long),
1513 (IntKind::UInt, IntKind::Long, IntKind::Long),
1514 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1515 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1516 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1517 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1518 (IntKind::Char, IntKind::Char, IntKind::Int),
1519 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1520 ];
1521 for (left, right, want) in cases {
1522 let left = types.int(left);
1523 let right = types.int(right);
1524 let want = types.int(want);
1525 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1526 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1527 }
1528 }
1529
1530 #[test]
1531 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1532 let mut types = Types::new();
1536 let linux = linux();
1537 let signed = types.int(IntKind::Int128);
1538 let unsigned = types.int(IntKind::UInt128);
1539 for id in [signed, unsigned] {
1540 let laid_out = layout(&types, id, &linux).expect("a complete type");
1541 assert_eq!(laid_out.size, 16);
1542 assert_eq!(laid_out.align, 16);
1543 }
1544
1545 let ull = types.int(IntKind::ULongLong);
1549 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1550 assert_eq!(promote(&mut types, signed, &linux), signed);
1552 }
1553
1554 #[test]
1555 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1556 let mut types = Types::new();
1559 let linux = linux();
1560 let int128 = types.int(IntKind::Int128);
1561 let bit_int = types.bit_int(true, 128);
1562 assert_ne!(int128, bit_int);
1563 assert!(!compatible(&types, int128, bit_int));
1564 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1565 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1566 }
1567
1568 #[test]
1569 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1570 let mut types = Types::new();
1574 let linux = linux();
1575 let ulong = types.int(IntKind::ULong);
1576 let long_long = types.int(IntKind::LongLong);
1577 let want = types.int(IntKind::ULongLong);
1578 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1579
1580 let windows = target("x86_64-pc-windows-msvc");
1584 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1585 }
1586
1587 #[test]
1588 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1589 let mut types = Types::new();
1591 let linux = linux();
1592 let b40 = types.bit_int(true, 40);
1593 let ub40 = types.bit_int(false, 40);
1594 let b8 = types.bit_int(true, 8);
1595 let b32 = types.bit_int(true, 32);
1596 let int = types.int(IntKind::Int);
1597 let uint = types.int(IntKind::UInt);
1598 let long = types.int(IntKind::Long);
1599 let char_ = types.int(IntKind::Char);
1600
1601 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1603 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1605 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1607 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1608 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1611 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1614 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1615 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1617 }
1618
1619 #[test]
1620 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1621 let mut types = Types::new();
1622 let linux = linux();
1623 let float = types.float(FloatKind::Float);
1624 let double = types.float(FloatKind::Double);
1625 let long_double = types.float(FloatKind::LongDouble);
1626 let ullong = types.int(IntKind::ULongLong);
1627 let int = types.int(IntKind::Int);
1628
1629 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1630 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1631 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1632 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1635 }
1636
1637 #[test]
1638 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1639 let mut types = Types::new();
1640 let linux = linux();
1641 let int = types.int(IntKind::Int);
1642 let float = types.float(FloatKind::Float);
1643 let short = types.int(IntKind::Short);
1644
1645 let four_ints = types.vector(int, 4);
1647 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1648
1649 let uint = types.int(IntKind::UInt);
1652 let four_uints = types.vector(uint, 4);
1653 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1654
1655 let four_floats = types.vector(float, 4);
1658 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1659
1660 let two_shorts = types.vector(short, 2);
1662 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1663
1664 assert_eq!(mask_of(&mut types, int, &linux), None);
1666 }
1667
1668 #[test]
1669 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1670 let mut types = Types::new();
1671 let linux = linux();
1672 let int = types.int(IntKind::Int);
1673 let uint = types.int(IntKind::UInt);
1674 let float = types.float(FloatKind::Float);
1675 let short = types.int(IntKind::Short);
1676
1677 let four_ints = types.vector(int, 4);
1678 let four_uints = types.vector(uint, 4);
1679 let four_floats = types.vector(float, 4);
1680 let eight_shorts = types.vector(short, 8);
1681 let two_ints = types.vector(int, 2);
1682
1683 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1686 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1688 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1690 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1692
1693 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1696 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1698 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1700 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1701 }
1702
1703 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1708 let mut types = Types::new();
1709 let left = types.float(a);
1710 let right = types.float(b);
1711 let want = types.float(expected);
1712 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1713 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1714 }
1715
1716 #[test]
1717 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1718 let x86 = linux();
1722 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1723 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1724 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1725 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1726 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1727 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1728 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1729 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1730 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1731 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1732 }
1733
1734 #[test]
1735 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1736 let mac = target("aarch64-apple-darwin");
1740 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1741 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1742 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1743 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1744 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1745 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1746 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1747 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1750 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1751 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1752 }
1753
1754 #[test]
1755 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1756 let mut types = Types::new();
1757 let linux = linux();
1758 let cfloat = types.complex_float(FloatKind::Float);
1759 let cdouble = types.complex_float(FloatKind::Double);
1760 let cldouble = types.complex_float(FloatKind::LongDouble);
1761 let double = types.float(FloatKind::Double);
1762 let long_double = types.float(FloatKind::LongDouble);
1763 let float = types.float(FloatKind::Float);
1764 let int = types.int(IntKind::Int);
1765
1766 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1767 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1768 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1769 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1770 }
1771
1772 #[test]
1773 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1774 let mut types = Types::new();
1776 let linux = linux();
1777 let int = types.int(IntKind::Int);
1778 let pointer = types.pointer(int);
1779 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1780 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1781 let void = types.void();
1782 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1783 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1786 }
1787
1788 #[test]
1789 fn the_conversions_read_through_sugar() {
1790 let mut interner = Interner::new();
1791 let mut types = Types::new();
1792 let linux = linux();
1793 let char_ = types.int(IntKind::Char);
1794 let name = types.typedef(interner.intern("byte"), char_);
1795 let int = types.int(IntKind::Int);
1796 assert_eq!(promote(&mut types, name, &linux), int);
1797 }
1798
1799 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1801 let ret = types.void();
1802 types.function(FunctionType {
1803 ret,
1804 params,
1805 variadic,
1806 prototyped: true,
1807 convention: rucc_target::Convention::Target,
1808 })
1809 }
1810
1811 fn old_style(types: &mut Types) -> TypeId {
1813 let ret = types.void();
1814 types.function(FunctionType {
1815 ret,
1816 params: Vec::new(),
1817 variadic: false,
1818 prototyped: false,
1819 convention: rucc_target::Convention::Target,
1820 })
1821 }
1822
1823 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1825 let id = types.declare_record(RecordKind::Struct, Some(tag));
1826 let laid_out = lay_out(types, RecordKind::Struct, fields);
1827 types.complete_record(id, laid_out);
1828 id
1829 }
1830
1831 #[test]
1832 fn a_type_is_compatible_with_itself_however_it_was_written() {
1833 let mut interner = Interner::new();
1834 let mut types = Types::new();
1835 let int = types.int(IntKind::Int);
1836 let name = types.typedef(interner.intern("int32_t"), int);
1837 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1838 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1839
1840 let konst = types.qualified(int, Qualifiers::CONST);
1843 assert!(!compatible(&types, konst, int));
1844 let konst_pointer = types.pointer(konst);
1845 let pointer = types.pointer(int);
1846 assert!(!compatible(&types, konst_pointer, pointer));
1847 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1848
1849 let char_ = types.int(IntKind::Char);
1852 let schar = types.int(IntKind::SChar);
1853 assert!(!compatible(&types, char_, schar));
1854 let atomic = types.atomic(int);
1856 assert!(!compatible(&types, atomic, int));
1857 }
1858
1859 #[test]
1860 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1861 let mut types = Types::new();
1864 let uint = types.int(IntKind::UInt);
1865 let int = types.int(IntKind::Int);
1866 let id = types.declare_enum(None);
1867 types.complete_enum(id, uint, false);
1868 let e = types.enumeration(id);
1869 assert!(compatible(&types, e, uint));
1870 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1871 assert!(!compatible(&types, e, int));
1872
1873 let other = types.declare_enum(None);
1876 types.complete_enum(other, uint, false);
1877 let other = types.enumeration(other);
1878 assert!(!compatible(&types, e, other));
1879
1880 let undecided = types.declare_enum(None);
1883 let undecided = types.enumeration(undecided);
1884 assert!(!compatible(&types, undecided, uint));
1885 assert!(compatible(&types, undecided, undecided));
1886 }
1887
1888 #[test]
1889 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1890 let mut types = Types::new();
1893 let int = types.int(IntKind::Int);
1894 let unknown = types.array(int, ArrayLen::Unknown);
1895 let four = types.array(int, ArrayLen::Fixed(4));
1896 let five = types.array(int, ArrayLen::Fixed(5));
1897 assert!(compatible(&types, unknown, four));
1898 assert!(!compatible(&types, four, five));
1899 assert_eq!(composite(&mut types, unknown, four), Some(four));
1900 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1901 assert_eq!(composite(&mut types, four, five), None);
1902
1903 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1906 assert!(compatible(&types, vla, four));
1907 assert_eq!(composite(&mut types, vla, four), Some(four));
1908
1909 let long = types.int(IntKind::Long);
1911 let longs = types.array(long, ArrayLen::Fixed(4));
1912 assert!(!compatible(&types, four, longs));
1913 }
1914
1915 #[test]
1916 fn a_parameter_declared_as_an_array_is_a_pointer() {
1917 let mut types = Types::new();
1921 let int = types.int(IntKind::Int);
1922 let three = types.array(int, ArrayLen::Fixed(3));
1923 let pointer = types.pointer(int);
1924 assert_eq!(adjust_parameter(&mut types, three), pointer);
1925
1926 let function = prototype(&mut types, vec![int], false);
1928 let function_pointer = types.pointer(function);
1929 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1930
1931 let konst = types.qualified(int, Qualifiers::CONST);
1934 assert_eq!(adjust_parameter(&mut types, konst), int);
1935 let to_konst = types.pointer(konst);
1936 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1937 }
1938
1939 #[test]
1940 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1941 let mut types = Types::new();
1945 let old = old_style(&mut types);
1946 let int = types.int(IntKind::Int);
1947 let long = types.int(IntKind::Long);
1948 let char_ = types.int(IntKind::Char);
1949 let float = types.float(FloatKind::Float);
1950 let double = types.float(FloatKind::Double);
1951
1952 let takes_int = prototype(&mut types, vec![int], false);
1953 assert!(compatible(&types, old, takes_int));
1954 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1955 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1957
1958 let pointer = types.pointer(int);
1959 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1960 let ty = prototype(&mut types, params, false);
1961 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1962 }
1963
1964 for params in [vec![char_], vec![float], vec![int, char_]] {
1967 let ty = prototype(&mut types, params, false);
1968 assert!(!compatible(&types, old, ty));
1969 assert_eq!(composite(&mut types, old, ty), None);
1970 }
1971
1972 let variadic = prototype(&mut types, vec![int], true);
1974 assert!(!compatible(&types, old, variadic));
1975
1976 let uint = types.int(IntKind::UInt);
1978 let id = types.declare_enum(None);
1979 types.complete_enum(id, uint, false);
1980 let e = types.enumeration(id);
1981 let takes_enum = prototype(&mut types, vec![e], false);
1982 assert!(compatible(&types, old, takes_enum));
1983
1984 assert!(compatible(&types, old, old));
1986
1987 let returns_int = types.function(FunctionType {
1989 ret: int,
1990 params: Vec::new(),
1991 variadic: false,
1992 prototyped: false,
1993 convention: rucc_target::Convention::Target,
1994 });
1995 assert!(!compatible(&types, returns_int, takes_int));
1996 }
1997
1998 #[test]
2002 fn two_conventions_are_two_incompatible_types() {
2003 let mut types = Types::new();
2004 let int = types.int(IntKind::Int);
2005 let signature = FunctionType {
2006 ret: int,
2007 params: vec![int],
2008 variadic: false,
2009 prototyped: true,
2010 convention: rucc_target::Convention::Ms,
2011 };
2012 let native = types.function(FunctionType {
2013 convention: rucc_target::Convention::Target,
2014 ..signature.clone()
2015 });
2016 let ms = types.function(signature);
2017 let old_ms = types.function(FunctionType {
2018 ret: int,
2019 params: Vec::new(),
2020 variadic: false,
2021 prototyped: false,
2022 convention: rucc_target::Convention::Ms,
2023 });
2024 assert!(!compatible(&types, native, ms));
2025 let (to_native, to_ms) = (types.pointer(native), types.pointer(ms));
2026 assert!(!compatible(&types, to_native, to_ms));
2027 assert!(compatible(&types, ms, old_ms));
2028 let merged = composite(&mut types, old_ms, ms).expect("the two agree");
2029 let TypeKind::Function(id) = types.kind(merged) else { panic!("a function") };
2030 assert_eq!(types.signature(id).convention, rucc_target::Convention::Ms);
2031 assert!(types.signature(id).prototyped);
2032 }
2033
2034 #[test]
2035 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
2036 let mut types = Types::new();
2040 let int = types.int(IntKind::Int);
2041 let takes_int = prototype(&mut types, vec![int], false);
2042 let takes_nothing = prototype(&mut types, Vec::new(), false);
2043 let old = old_style(&mut types);
2044 assert!(!compatible(&types, takes_nothing, takes_int));
2045 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
2046 }
2047
2048 #[test]
2049 fn two_prototypes_have_to_agree_about_everything() {
2050 let mut types = Types::new();
2051 let int = types.int(IntKind::Int);
2052 let long = types.int(IntKind::Long);
2053 let base = prototype(&mut types, vec![int, int], false);
2054 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
2055 let other = prototype(&mut types, other, false);
2056 assert!(!compatible(&types, base, other));
2057 }
2058 let variadic = prototype(&mut types, vec![int, int], true);
2059 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
2060
2061 let four = types.array(int, ArrayLen::Fixed(4));
2064 let unknown = types.array(int, ArrayLen::Unknown);
2065 let to_four = types.pointer(four);
2066 let to_unknown = types.pointer(unknown);
2067 let a = prototype(&mut types, vec![to_four], false);
2068 let b = prototype(&mut types, vec![to_unknown], false);
2069 assert!(compatible(&types, a, b));
2070 assert_eq!(composite(&mut types, a, b), Some(a));
2072 }
2073
2074 #[test]
2075 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
2076 let mut types = Types::new();
2077 let int = types.int(IntKind::Int);
2078 let four = types.array(int, ArrayLen::Fixed(4));
2079 let unknown = types.array(int, ArrayLen::Unknown);
2080 let to_four = types.pointer(four);
2081 let to_unknown = types.pointer(unknown);
2082 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
2083
2084 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
2086 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
2087 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
2088 }
2089
2090 #[test]
2091 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
2092 let mut interner = Interner::new();
2096 let mut types = Types::new();
2097 let tag = interner.intern("point");
2098 let x = interner.intern("x");
2099 let y = interner.intern("y");
2100 let int = types.int(IntKind::Int);
2101 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
2102
2103 let first = tagged(&mut types, tag, &members);
2104 let second = tagged(&mut types, tag, &members);
2105 let first = types.record(first);
2106 let second = types.record(second);
2107 assert_ne!(first, second, "still two declarations and two types");
2108 assert!(compatible(&types, first, second));
2109
2110 let z = interner.intern("z");
2113 let long = types.int(IntKind::Long);
2114 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
2115 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
2116 for other in [&renamed[..], &retyped[..], &members[..1]] {
2117 let other = tagged(&mut types, tag, other);
2118 let other = types.record(other);
2119 assert!(!compatible(&types, first, other));
2120 }
2121 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
2122 let elsewhere = types.record(elsewhere);
2123 assert!(!compatible(&types, first, elsewhere));
2124
2125 let anonymous = record(&mut types, RecordKind::Struct, &members);
2128 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
2129 assert!(!compatible(&types, anonymous, also_anonymous));
2130
2131 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
2133 let incomplete = types.record(incomplete);
2134 assert!(!compatible(&types, first, incomplete));
2135 assert!(compatible(&types, incomplete, incomplete));
2136 }
2137
2138 #[test]
2139 fn a_self_referential_record_is_compared_without_going_round_forever() {
2140 let mut interner = Interner::new();
2144 let mut types = Types::new();
2145 let tag = interner.intern("node");
2146 let value = interner.intern("value");
2147 let next = interner.intern("next");
2148 let int = types.int(IntKind::Int);
2149
2150 let node = |types: &mut Types| {
2151 let id = types.declare_record(RecordKind::Struct, Some(tag));
2152 let ty = types.record(id);
2153 let pointer = types.pointer(ty);
2154 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
2155 let laid_out = lay_out(types, RecordKind::Struct, &members);
2156 types.complete_record(id, laid_out);
2157 ty
2158 };
2159 let first = node(&mut types);
2160 let second = node(&mut types);
2161 assert_ne!(first, second);
2162 assert!(compatible(&types, first, second));
2163
2164 let id = types.declare_record(RecordKind::Struct, Some(tag));
2167 let ty = types.record(id);
2168 let pointer = types.pointer(ty);
2169 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
2170 let laid_out = lay_out(&types, RecordKind::Struct, &members);
2171 types.complete_record(id, laid_out);
2172 assert!(!compatible(&types, first, ty));
2173 }
2174
2175 #[test]
2176 fn layout_reads_through_sugar() {
2177 let mut interner = Interner::new();
2178 let mut types = Types::new();
2179 let long = types.int(IntKind::Long);
2180 let name = types.typedef(interner.intern("word"), long);
2181 let array = types.array(name, ArrayLen::Fixed(4));
2182 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
2183 }
2184
2185 fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
2191 match recipe {
2192 Extent::Bytes(count) => *count,
2193 Extent::Member(index) => sizes[*index as usize],
2194 Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
2195 Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
2196 Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
2197 }
2198 }
2199
2200 fn measured(types: &mut Types, which: u32) -> TypeId {
2202 let int = types.int(IntKind::Int);
2203 types.array(int, ArrayLen::Variable(VlaId(which)))
2204 }
2205
2206 #[test]
2207 fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2208 let mut types = Types::new();
2209 let int = types.int(IntKind::Int);
2210 let rows = measured(&mut types, 0);
2211 let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2212
2213 assert_eq!(laid_out.layout, Layout::new(0, 4));
2216 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2217 assert_eq!(variable.offsets[0], None);
2221 let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2222 for count in 0..6u64 {
2223 let sizes = [4 * count, 4];
2224 assert_eq!(work_out(after, &sizes), 4 * count);
2225 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2226 }
2227 assert_eq!(laid_out.fields[1].align, 4);
2228 }
2229
2230 #[test]
2231 fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2232 let mut types = Types::new();
2233 let char_ty = types.int(IntKind::Char);
2234 let rows = measured(&mut types, 0);
2235 let double = types.float(FloatKind::Double);
2236 let fields = [member(char_ty), member(rows), member(double)];
2237 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2238
2239 assert_eq!(laid_out.layout, Layout::new(0, 8));
2240 assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2241 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2242 assert_eq!(variable.offsets[..2], [None, None]);
2243 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2244 for count in 0..6u64 {
2245 let sizes = [1, 4 * count, 8];
2246 let at = (4 + 4 * count).next_multiple_of(8);
2247 assert_eq!(work_out(after, &sizes), at);
2248 assert_eq!(work_out(&variable.size, &sizes), at + 8);
2249 }
2250 }
2251
2252 #[test]
2253 fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2254 let mut types = Types::new();
2255 let rows = measured(&mut types, 0);
2256 let double = types.float(FloatKind::Double);
2257 let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2258
2259 assert_eq!(laid_out.layout, Layout::new(0, 8));
2260 let variable = laid_out.variable.expect("a union with a member of no fixed size");
2261 assert!(variable.offsets.iter().all(Option::is_none));
2264 for count in 0..6u64 {
2265 let sizes = [4 * count, 8];
2266 let want = (4 * count).max(8).next_multiple_of(8);
2267 assert_eq!(work_out(&variable.size, &sizes), want);
2268 }
2269 }
2270
2271 #[test]
2272 fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2273 let mut types = Types::new();
2274 let char_ty = types.int(IntKind::Char);
2275 let int = types.int(IntKind::Int);
2276 let rows = measured(&mut types, 0);
2277 let fields = [member(char_ty), member(rows), member(int)];
2278 let options = RecordOptions { packed: true, ..RecordOptions::default() };
2279 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2280 .expect("a packed record with a member of no fixed size");
2281
2282 assert_eq!(laid_out.layout, Layout::new(0, 1));
2283 assert_eq!(laid_out.fields[2].align, 1);
2284 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2285 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2286 for count in 0..6u64 {
2287 let sizes = [1, 4 * count, 4];
2288 assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2289 assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2290 }
2291 }
2292
2293 #[test]
2294 fn bit_fields_after_a_member_of_no_fixed_size_are_placed_one_after_another() {
2295 let mut interner = Interner::new();
2296 let mut types = Types::new();
2297 let int = types.int(IntKind::Int);
2298 let char_ty = types.int(IntKind::Char);
2299 let rows = measured(&mut types, 0);
2300 let fields = [
2301 member(rows),
2302 bits(&mut interner, "b", int, 3),
2303 bits(&mut interner, "c", int, 30),
2304 member(char_ty),
2305 ];
2306 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2307
2308 assert_eq!((laid_out.fields[2].offset, laid_out.fields[2].bit), (0, 3));
2312 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2313 let after = variable.offsets[3].as_ref().expect("an offset the program works out");
2314 for count in 0..6u64 {
2315 let sizes = [4 * count, 4, 4, 1];
2316 assert_eq!(work_out(after, &sizes), 4 * count + 5);
2317 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 8);
2318 }
2319 }
2320
2321 #[test]
2322 fn a_zero_width_bit_field_that_needs_more_alignment_than_is_known_is_turned_down() {
2323 let mut types = Types::new();
2324 let int = types.int(IntKind::Int);
2325 let char_ty = types.int(IntKind::Char);
2326 let letters = types.array(char_ty, ArrayLen::Variable(VlaId(0)));
2327 let fields = [member(letters), unnamed_bits(int, 0)];
2328 let options = RecordOptions::default();
2329 let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2330
2331 assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2335 }
2336}