1#![doc(html_root_url = "https://docs.rs/rucc-types/0.15.3")]
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
1174 let narrow = [
1176 bits(&mut interner, "a", char_, 1),
1177 unnamed_bits(int_, 0),
1178 bits(&mut interner, "b", char_, 1),
1179 ];
1180 let laid_out = on(&mingw, &gcc, &narrow);
1181 assert_eq!(laid_out.layout, Layout::new(5, 1));
1182 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1183 assert_eq!(on(&linux(), &ms, &narrow).layout, Layout::new(8, 4));
1184 let alone = [member(char_), unnamed_bits(uint, 0)];
1185 assert_eq!(on(&mingw, &gcc, &alone).layout, Layout::new(4, 1));
1186 assert_eq!(on(&linux(), &ms, &alone).layout, Layout::new(1, 1));
1187 }
1188
1189 #[test]
1190 fn msvc_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1191 let mut interner = Interner::new();
1192 let types = Types::new();
1193 let char_ = types.int(IntKind::Char);
1194 let uint = types.int(IntKind::UInt);
1195
1196 let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1199 assert_eq!(
1200 lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1201 Layout::new(4, 1)
1202 );
1203 assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1204 let mingw = target("x86_64-pc-windows-gnu");
1207 assert_eq!(
1208 lay_out_on(&mingw, &types, RecordKind::Union, &fields).layout,
1209 Layout::new(4, 4)
1210 );
1211 }
1212
1213 #[test]
1214 fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1215 let mut types = Types::new();
1216 let uint = types.int(IntKind::UInt);
1217 let mingw = target("x86_64-pc-windows-gnu");
1218
1219 let none: [FieldDecl; 0] = [];
1221 let zero_width = [unnamed_bits(uint, 0)];
1222 let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1223 for fields in [&none[..], &zero_width[..], &flexible[..]] {
1224 let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1225 assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1226 assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1227 assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1228 }
1229
1230 assert_eq!(windows().empty_record_size, 4);
1234 assert_eq!(mingw.empty_record_size, 0);
1235 }
1236
1237 #[test]
1238 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
1239 let mut interner = Interner::new();
1240 let types = Types::new();
1241 let char_ = types.int(IntKind::Char);
1242 let int = types.int(IntKind::Int);
1243 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1244
1245 let fields = [member(char_), member(int)];
1246 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1247 .expect("a packed struct of two complete members");
1248 assert_eq!(laid_out.layout, Layout::new(5, 1));
1249 assert_eq!(offsets(&laid_out), [0, 8]);
1250
1251 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1252 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1253 .expect("a packed struct with a bit-field");
1254 assert_eq!(laid_out.layout, Layout::new(5, 1));
1255 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1256
1257 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1260 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1261 .expect("a packed struct with a zero width bit-field");
1262 assert_eq!(laid_out.layout, Layout::new(5, 1));
1263 assert_eq!(offsets(&laid_out), [0, 32, 32]);
1264 }
1265
1266 #[test]
1267 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1268 let mut interner = Interner::new();
1269 let types = Types::new();
1270 let char_ = types.int(IntKind::Char);
1271 let int = types.int(IntKind::Int);
1272 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1273
1274 let fields = [member(char_), member(int)];
1275 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1276 .expect("a packed struct of two complete members");
1277 assert_eq!(laid_out.layout, Layout::new(6, 2));
1278 assert_eq!(offsets(&laid_out), [0, 16]);
1279
1280 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1284 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1285 .expect("a packed struct with a bit-field");
1286 assert_eq!(laid_out.layout, Layout::new(6, 2));
1287 assert_eq!(offsets(&laid_out), [0, 8]);
1288
1289 let fields = [member(char_), unnamed_bits(int, 30)];
1292 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1293 .expect("a packed struct with an unnamed bit-field");
1294 assert_eq!(laid_out.layout, Layout::new(5, 1));
1295 }
1296
1297 #[test]
1298 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1299 let types = Types::new();
1300 let char_ = types.int(IntKind::Char);
1301 let int = types.int(IntKind::Int);
1302
1303 let aligned = FieldDecl { align: Some(16), ..member(int) };
1304 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1305 assert_eq!(laid_out.layout, Layout::new(32, 16));
1306 assert_eq!(offsets(&laid_out), [0, 128]);
1307
1308 let options = RecordOptions { packed: true, align: Some(4), ..RecordOptions::default() };
1311 let fields = [member(char_), member(int)];
1312 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1313 .expect("a packed struct with an alignment asked for");
1314 assert_eq!(laid_out.layout, Layout::new(8, 4));
1315 assert_eq!(offsets(&laid_out), [0, 8]);
1316 }
1317
1318 #[test]
1319 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1320 let mut types = Types::new();
1322 let char_ = types.int(IntKind::Char);
1323 let int = types.int(IntKind::Int);
1324 let long_long = types.int(IntKind::LongLong);
1325
1326 let chars = types.array(char_, ArrayLen::Unknown);
1327 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1328 assert_eq!(laid_out.layout, Layout::new(4, 4));
1329 assert_eq!(offsets(&laid_out), [0, 32]);
1330
1331 let longs = types.array(long_long, ArrayLen::Unknown);
1333 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1334 assert_eq!(laid_out.layout, Layout::new(8, 8));
1335 assert_eq!(offsets(&laid_out), [0, 64]);
1336
1337 let fields = [member(chars), member(int)];
1339 let error =
1340 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1341 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1342 }
1343
1344 #[test]
1345 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1346 let types = Types::new();
1348 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1349 assert_eq!(laid_out.layout, Layout::new(0, 1));
1350 }
1351
1352 #[test]
1353 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1354 let types = Types::new();
1355 let int = types.int(IntKind::Int);
1356 let fields = [unnamed_bits(int, 33)];
1357 let error =
1358 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1359 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1360 assert_eq!(error, Err(want));
1361 }
1362
1363 #[test]
1364 fn a_record_reports_its_members_once_it_has_been_completed() {
1365 let mut interner = Interner::new();
1366 let mut types = Types::new();
1367 let char_ = types.int(IntKind::Char);
1368 let int = types.int(IntKind::Int);
1369 let name = interner.intern("count");
1370 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1371 let id = types.declare_record(RecordKind::Struct, None);
1372 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1373 types.complete_record(id, laid_out);
1374 let ty = types.record(id);
1375 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1376 let field = types.field(id, name).expect("the member that was declared");
1377 assert_eq!(field.offset, 4);
1378 assert!(!field.is_bit_field());
1379 assert_eq!(types.field(id, interner.intern("missing")), None);
1380 }
1381
1382 #[test]
1383 fn a_nested_record_brings_its_own_alignment_with_it() {
1384 let mut types = Types::new();
1385 let char_ = types.int(IntKind::Char);
1386 let int = types.int(IntKind::Int);
1387 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1388 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1389 assert_eq!(laid_out.layout, Layout::new(8, 4));
1390 assert_eq!(offsets(&laid_out), [0, 32]);
1391
1392 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1395 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1396 assert_eq!(laid_out.layout, Layout::new(12, 4));
1397 assert_eq!(offsets(&laid_out), [0, 32]);
1398 }
1399
1400 #[test]
1401 fn everything_narrower_than_an_int_promotes_to_one() {
1402 let mut types = Types::new();
1406 let linux = linux();
1407 let int = types.int(IntKind::Int);
1408 let narrow =
1409 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1410 for kind in narrow {
1411 let ty = types.int(kind);
1412 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1413 }
1414 let boolean = types.boolean();
1415 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1416
1417 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1419 let ty = types.int(kind);
1420 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1421 }
1422 }
1423
1424 #[test]
1425 fn a_bit_int_is_not_promoted_at_all() {
1426 let mut types = Types::new();
1429 let linux = linux();
1430 let small = types.bit_int(true, 8);
1431 assert_eq!(promote(&mut types, small, &linux), small);
1432 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1433 }
1434
1435 #[test]
1436 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1437 let mut types = Types::new();
1438 let linux = linux();
1439 let int = types.int(IntKind::Int);
1440 let uint = types.int(IntKind::UInt);
1441 let ullong = types.int(IntKind::ULongLong);
1442
1443 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1445 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1447 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1449 let forty = types.bit_int(false, 40);
1454 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1455 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1457 }
1458
1459 #[test]
1460 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1461 let mut types = Types::new();
1462 let linux = linux();
1463 let int = types.int(IntKind::Int);
1464 let short = types.int(IntKind::Short);
1465 let uint = types.int(IntKind::UInt);
1466
1467 let fixed = types.declare_enum(None);
1469 types.complete_enum(fixed, short, true);
1470 let fixed = types.enumeration(fixed);
1471 assert_eq!(promote(&mut types, fixed, &linux), int);
1472
1473 let unsigned = types.declare_enum(None);
1476 types.complete_enum(unsigned, uint, false);
1477 let unsigned = types.enumeration(unsigned);
1478 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1479
1480 let undecided = types.declare_enum(None);
1483 let undecided = types.enumeration(undecided);
1484 assert_eq!(promote(&mut types, undecided, &linux), int);
1485 }
1486
1487 #[test]
1488 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1489 let mut types = Types::new();
1492 let linux = linux();
1493 let int = types.int(IntKind::Int);
1494 let konst = types.qualified(int, Qualifiers::CONST);
1495 let atomic = types.atomic(konst);
1496 assert_eq!(promote(&mut types, atomic, &linux), int);
1497 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1498 }
1499
1500 #[test]
1501 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1502 let mut types = Types::new();
1504 let linux = linux();
1505 let cases = [
1506 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1507 (IntKind::Int, IntKind::Long, IntKind::Long),
1508 (IntKind::UInt, IntKind::Long, IntKind::Long),
1509 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1510 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1511 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1512 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1513 (IntKind::Char, IntKind::Char, IntKind::Int),
1514 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1515 ];
1516 for (left, right, want) in cases {
1517 let left = types.int(left);
1518 let right = types.int(right);
1519 let want = types.int(want);
1520 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1521 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1522 }
1523 }
1524
1525 #[test]
1526 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1527 let mut types = Types::new();
1531 let linux = linux();
1532 let signed = types.int(IntKind::Int128);
1533 let unsigned = types.int(IntKind::UInt128);
1534 for id in [signed, unsigned] {
1535 let laid_out = layout(&types, id, &linux).expect("a complete type");
1536 assert_eq!(laid_out.size, 16);
1537 assert_eq!(laid_out.align, 16);
1538 }
1539
1540 let ull = types.int(IntKind::ULongLong);
1544 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1545 assert_eq!(promote(&mut types, signed, &linux), signed);
1547 }
1548
1549 #[test]
1550 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1551 let mut types = Types::new();
1554 let linux = linux();
1555 let int128 = types.int(IntKind::Int128);
1556 let bit_int = types.bit_int(true, 128);
1557 assert_ne!(int128, bit_int);
1558 assert!(!compatible(&types, int128, bit_int));
1559 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1560 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1561 }
1562
1563 #[test]
1564 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1565 let mut types = Types::new();
1569 let linux = linux();
1570 let ulong = types.int(IntKind::ULong);
1571 let long_long = types.int(IntKind::LongLong);
1572 let want = types.int(IntKind::ULongLong);
1573 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1574
1575 let windows = target("x86_64-pc-windows-msvc");
1579 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1580 }
1581
1582 #[test]
1583 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1584 let mut types = Types::new();
1586 let linux = linux();
1587 let b40 = types.bit_int(true, 40);
1588 let ub40 = types.bit_int(false, 40);
1589 let b8 = types.bit_int(true, 8);
1590 let b32 = types.bit_int(true, 32);
1591 let int = types.int(IntKind::Int);
1592 let uint = types.int(IntKind::UInt);
1593 let long = types.int(IntKind::Long);
1594 let char_ = types.int(IntKind::Char);
1595
1596 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1598 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1600 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1602 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1603 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1606 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1609 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1610 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1612 }
1613
1614 #[test]
1615 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1616 let mut types = Types::new();
1617 let linux = linux();
1618 let float = types.float(FloatKind::Float);
1619 let double = types.float(FloatKind::Double);
1620 let long_double = types.float(FloatKind::LongDouble);
1621 let ullong = types.int(IntKind::ULongLong);
1622 let int = types.int(IntKind::Int);
1623
1624 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1625 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1626 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1627 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1630 }
1631
1632 #[test]
1633 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1634 let mut types = Types::new();
1635 let linux = linux();
1636 let int = types.int(IntKind::Int);
1637 let float = types.float(FloatKind::Float);
1638 let short = types.int(IntKind::Short);
1639
1640 let four_ints = types.vector(int, 4);
1642 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1643
1644 let uint = types.int(IntKind::UInt);
1647 let four_uints = types.vector(uint, 4);
1648 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1649
1650 let four_floats = types.vector(float, 4);
1653 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1654
1655 let two_shorts = types.vector(short, 2);
1657 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1658
1659 assert_eq!(mask_of(&mut types, int, &linux), None);
1661 }
1662
1663 #[test]
1664 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1665 let mut types = Types::new();
1666 let linux = linux();
1667 let int = types.int(IntKind::Int);
1668 let uint = types.int(IntKind::UInt);
1669 let float = types.float(FloatKind::Float);
1670 let short = types.int(IntKind::Short);
1671
1672 let four_ints = types.vector(int, 4);
1673 let four_uints = types.vector(uint, 4);
1674 let four_floats = types.vector(float, 4);
1675 let eight_shorts = types.vector(short, 8);
1676 let two_ints = types.vector(int, 2);
1677
1678 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1681 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1683 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1685 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1687
1688 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1691 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1693 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1695 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1696 }
1697
1698 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1703 let mut types = Types::new();
1704 let left = types.float(a);
1705 let right = types.float(b);
1706 let want = types.float(expected);
1707 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1708 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1709 }
1710
1711 #[test]
1712 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1713 let x86 = linux();
1717 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1718 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1719 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1720 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1721 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1722 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1723 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1724 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1725 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1726 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1727 }
1728
1729 #[test]
1730 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1731 let mac = target("aarch64-apple-darwin");
1735 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1736 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1737 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1738 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1739 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1740 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1741 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1742 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1745 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1746 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1747 }
1748
1749 #[test]
1750 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1751 let mut types = Types::new();
1752 let linux = linux();
1753 let cfloat = types.complex_float(FloatKind::Float);
1754 let cdouble = types.complex_float(FloatKind::Double);
1755 let cldouble = types.complex_float(FloatKind::LongDouble);
1756 let double = types.float(FloatKind::Double);
1757 let long_double = types.float(FloatKind::LongDouble);
1758 let float = types.float(FloatKind::Float);
1759 let int = types.int(IntKind::Int);
1760
1761 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1762 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1763 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1764 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1765 }
1766
1767 #[test]
1768 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1769 let mut types = Types::new();
1771 let linux = linux();
1772 let int = types.int(IntKind::Int);
1773 let pointer = types.pointer(int);
1774 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1775 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1776 let void = types.void();
1777 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1778 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1781 }
1782
1783 #[test]
1784 fn the_conversions_read_through_sugar() {
1785 let mut interner = Interner::new();
1786 let mut types = Types::new();
1787 let linux = linux();
1788 let char_ = types.int(IntKind::Char);
1789 let name = types.typedef(interner.intern("byte"), char_);
1790 let int = types.int(IntKind::Int);
1791 assert_eq!(promote(&mut types, name, &linux), int);
1792 }
1793
1794 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1796 let ret = types.void();
1797 types.function(FunctionType {
1798 ret,
1799 params,
1800 variadic,
1801 prototyped: true,
1802 convention: rucc_target::Convention::Target,
1803 })
1804 }
1805
1806 fn old_style(types: &mut Types) -> TypeId {
1808 let ret = types.void();
1809 types.function(FunctionType {
1810 ret,
1811 params: Vec::new(),
1812 variadic: false,
1813 prototyped: false,
1814 convention: rucc_target::Convention::Target,
1815 })
1816 }
1817
1818 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1820 let id = types.declare_record(RecordKind::Struct, Some(tag));
1821 let laid_out = lay_out(types, RecordKind::Struct, fields);
1822 types.complete_record(id, laid_out);
1823 id
1824 }
1825
1826 #[test]
1827 fn a_type_is_compatible_with_itself_however_it_was_written() {
1828 let mut interner = Interner::new();
1829 let mut types = Types::new();
1830 let int = types.int(IntKind::Int);
1831 let name = types.typedef(interner.intern("int32_t"), int);
1832 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1833 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1834
1835 let konst = types.qualified(int, Qualifiers::CONST);
1838 assert!(!compatible(&types, konst, int));
1839 let konst_pointer = types.pointer(konst);
1840 let pointer = types.pointer(int);
1841 assert!(!compatible(&types, konst_pointer, pointer));
1842 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1843
1844 let char_ = types.int(IntKind::Char);
1847 let schar = types.int(IntKind::SChar);
1848 assert!(!compatible(&types, char_, schar));
1849 let atomic = types.atomic(int);
1851 assert!(!compatible(&types, atomic, int));
1852 }
1853
1854 #[test]
1855 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1856 let mut types = Types::new();
1859 let uint = types.int(IntKind::UInt);
1860 let int = types.int(IntKind::Int);
1861 let id = types.declare_enum(None);
1862 types.complete_enum(id, uint, false);
1863 let e = types.enumeration(id);
1864 assert!(compatible(&types, e, uint));
1865 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1866 assert!(!compatible(&types, e, int));
1867
1868 let other = types.declare_enum(None);
1871 types.complete_enum(other, uint, false);
1872 let other = types.enumeration(other);
1873 assert!(!compatible(&types, e, other));
1874
1875 let undecided = types.declare_enum(None);
1878 let undecided = types.enumeration(undecided);
1879 assert!(!compatible(&types, undecided, uint));
1880 assert!(compatible(&types, undecided, undecided));
1881 }
1882
1883 #[test]
1884 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1885 let mut types = Types::new();
1888 let int = types.int(IntKind::Int);
1889 let unknown = types.array(int, ArrayLen::Unknown);
1890 let four = types.array(int, ArrayLen::Fixed(4));
1891 let five = types.array(int, ArrayLen::Fixed(5));
1892 assert!(compatible(&types, unknown, four));
1893 assert!(!compatible(&types, four, five));
1894 assert_eq!(composite(&mut types, unknown, four), Some(four));
1895 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1896 assert_eq!(composite(&mut types, four, five), None);
1897
1898 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1901 assert!(compatible(&types, vla, four));
1902 assert_eq!(composite(&mut types, vla, four), Some(four));
1903
1904 let long = types.int(IntKind::Long);
1906 let longs = types.array(long, ArrayLen::Fixed(4));
1907 assert!(!compatible(&types, four, longs));
1908 }
1909
1910 #[test]
1911 fn a_parameter_declared_as_an_array_is_a_pointer() {
1912 let mut types = Types::new();
1916 let int = types.int(IntKind::Int);
1917 let three = types.array(int, ArrayLen::Fixed(3));
1918 let pointer = types.pointer(int);
1919 assert_eq!(adjust_parameter(&mut types, three), pointer);
1920
1921 let function = prototype(&mut types, vec![int], false);
1923 let function_pointer = types.pointer(function);
1924 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1925
1926 let konst = types.qualified(int, Qualifiers::CONST);
1929 assert_eq!(adjust_parameter(&mut types, konst), int);
1930 let to_konst = types.pointer(konst);
1931 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1932 }
1933
1934 #[test]
1935 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1936 let mut types = Types::new();
1940 let old = old_style(&mut types);
1941 let int = types.int(IntKind::Int);
1942 let long = types.int(IntKind::Long);
1943 let char_ = types.int(IntKind::Char);
1944 let float = types.float(FloatKind::Float);
1945 let double = types.float(FloatKind::Double);
1946
1947 let takes_int = prototype(&mut types, vec![int], false);
1948 assert!(compatible(&types, old, takes_int));
1949 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1950 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1952
1953 let pointer = types.pointer(int);
1954 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1955 let ty = prototype(&mut types, params, false);
1956 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1957 }
1958
1959 for params in [vec![char_], vec![float], vec![int, char_]] {
1962 let ty = prototype(&mut types, params, false);
1963 assert!(!compatible(&types, old, ty));
1964 assert_eq!(composite(&mut types, old, ty), None);
1965 }
1966
1967 let variadic = prototype(&mut types, vec![int], true);
1969 assert!(!compatible(&types, old, variadic));
1970
1971 let uint = types.int(IntKind::UInt);
1973 let id = types.declare_enum(None);
1974 types.complete_enum(id, uint, false);
1975 let e = types.enumeration(id);
1976 let takes_enum = prototype(&mut types, vec![e], false);
1977 assert!(compatible(&types, old, takes_enum));
1978
1979 assert!(compatible(&types, old, old));
1981
1982 let returns_int = types.function(FunctionType {
1984 ret: int,
1985 params: Vec::new(),
1986 variadic: false,
1987 prototyped: false,
1988 convention: rucc_target::Convention::Target,
1989 });
1990 assert!(!compatible(&types, returns_int, takes_int));
1991 }
1992
1993 #[test]
1997 fn two_conventions_are_two_incompatible_types() {
1998 let mut types = Types::new();
1999 let int = types.int(IntKind::Int);
2000 let signature = FunctionType {
2001 ret: int,
2002 params: vec![int],
2003 variadic: false,
2004 prototyped: true,
2005 convention: rucc_target::Convention::Ms,
2006 };
2007 let native = types.function(FunctionType {
2008 convention: rucc_target::Convention::Target,
2009 ..signature.clone()
2010 });
2011 let ms = types.function(signature);
2012 let old_ms = types.function(FunctionType {
2013 ret: int,
2014 params: Vec::new(),
2015 variadic: false,
2016 prototyped: false,
2017 convention: rucc_target::Convention::Ms,
2018 });
2019 assert!(!compatible(&types, native, ms));
2020 let (to_native, to_ms) = (types.pointer(native), types.pointer(ms));
2021 assert!(!compatible(&types, to_native, to_ms));
2022 assert!(compatible(&types, ms, old_ms));
2023 let merged = composite(&mut types, old_ms, ms).expect("the two agree");
2024 let TypeKind::Function(id) = types.kind(merged) else { panic!("a function") };
2025 assert_eq!(types.signature(id).convention, rucc_target::Convention::Ms);
2026 assert!(types.signature(id).prototyped);
2027 }
2028
2029 #[test]
2030 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
2031 let mut types = Types::new();
2035 let int = types.int(IntKind::Int);
2036 let takes_int = prototype(&mut types, vec![int], false);
2037 let takes_nothing = prototype(&mut types, Vec::new(), false);
2038 let old = old_style(&mut types);
2039 assert!(!compatible(&types, takes_nothing, takes_int));
2040 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
2041 }
2042
2043 #[test]
2044 fn two_prototypes_have_to_agree_about_everything() {
2045 let mut types = Types::new();
2046 let int = types.int(IntKind::Int);
2047 let long = types.int(IntKind::Long);
2048 let base = prototype(&mut types, vec![int, int], false);
2049 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
2050 let other = prototype(&mut types, other, false);
2051 assert!(!compatible(&types, base, other));
2052 }
2053 let variadic = prototype(&mut types, vec![int, int], true);
2054 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
2055
2056 let four = types.array(int, ArrayLen::Fixed(4));
2059 let unknown = types.array(int, ArrayLen::Unknown);
2060 let to_four = types.pointer(four);
2061 let to_unknown = types.pointer(unknown);
2062 let a = prototype(&mut types, vec![to_four], false);
2063 let b = prototype(&mut types, vec![to_unknown], false);
2064 assert!(compatible(&types, a, b));
2065 assert_eq!(composite(&mut types, a, b), Some(a));
2067 }
2068
2069 #[test]
2070 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
2071 let mut types = Types::new();
2072 let int = types.int(IntKind::Int);
2073 let four = types.array(int, ArrayLen::Fixed(4));
2074 let unknown = types.array(int, ArrayLen::Unknown);
2075 let to_four = types.pointer(four);
2076 let to_unknown = types.pointer(unknown);
2077 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
2078
2079 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
2081 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
2082 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
2083 }
2084
2085 #[test]
2086 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
2087 let mut interner = Interner::new();
2091 let mut types = Types::new();
2092 let tag = interner.intern("point");
2093 let x = interner.intern("x");
2094 let y = interner.intern("y");
2095 let int = types.int(IntKind::Int);
2096 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
2097
2098 let first = tagged(&mut types, tag, &members);
2099 let second = tagged(&mut types, tag, &members);
2100 let first = types.record(first);
2101 let second = types.record(second);
2102 assert_ne!(first, second, "still two declarations and two types");
2103 assert!(compatible(&types, first, second));
2104
2105 let z = interner.intern("z");
2108 let long = types.int(IntKind::Long);
2109 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
2110 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
2111 for other in [&renamed[..], &retyped[..], &members[..1]] {
2112 let other = tagged(&mut types, tag, other);
2113 let other = types.record(other);
2114 assert!(!compatible(&types, first, other));
2115 }
2116 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
2117 let elsewhere = types.record(elsewhere);
2118 assert!(!compatible(&types, first, elsewhere));
2119
2120 let anonymous = record(&mut types, RecordKind::Struct, &members);
2123 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
2124 assert!(!compatible(&types, anonymous, also_anonymous));
2125
2126 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
2128 let incomplete = types.record(incomplete);
2129 assert!(!compatible(&types, first, incomplete));
2130 assert!(compatible(&types, incomplete, incomplete));
2131 }
2132
2133 #[test]
2134 fn a_self_referential_record_is_compared_without_going_round_forever() {
2135 let mut interner = Interner::new();
2139 let mut types = Types::new();
2140 let tag = interner.intern("node");
2141 let value = interner.intern("value");
2142 let next = interner.intern("next");
2143 let int = types.int(IntKind::Int);
2144
2145 let node = |types: &mut Types| {
2146 let id = types.declare_record(RecordKind::Struct, Some(tag));
2147 let ty = types.record(id);
2148 let pointer = types.pointer(ty);
2149 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
2150 let laid_out = lay_out(types, RecordKind::Struct, &members);
2151 types.complete_record(id, laid_out);
2152 ty
2153 };
2154 let first = node(&mut types);
2155 let second = node(&mut types);
2156 assert_ne!(first, second);
2157 assert!(compatible(&types, first, second));
2158
2159 let id = types.declare_record(RecordKind::Struct, Some(tag));
2162 let ty = types.record(id);
2163 let pointer = types.pointer(ty);
2164 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
2165 let laid_out = lay_out(&types, RecordKind::Struct, &members);
2166 types.complete_record(id, laid_out);
2167 assert!(!compatible(&types, first, ty));
2168 }
2169
2170 #[test]
2171 fn layout_reads_through_sugar() {
2172 let mut interner = Interner::new();
2173 let mut types = Types::new();
2174 let long = types.int(IntKind::Long);
2175 let name = types.typedef(interner.intern("word"), long);
2176 let array = types.array(name, ArrayLen::Fixed(4));
2177 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
2178 }
2179
2180 fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
2186 match recipe {
2187 Extent::Bytes(count) => *count,
2188 Extent::Member(index) => sizes[*index as usize],
2189 Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
2190 Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
2191 Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
2192 }
2193 }
2194
2195 fn measured(types: &mut Types, which: u32) -> TypeId {
2197 let int = types.int(IntKind::Int);
2198 types.array(int, ArrayLen::Variable(VlaId(which)))
2199 }
2200
2201 #[test]
2202 fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2203 let mut types = Types::new();
2204 let int = types.int(IntKind::Int);
2205 let rows = measured(&mut types, 0);
2206 let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2207
2208 assert_eq!(laid_out.layout, Layout::new(0, 4));
2211 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2212 assert_eq!(variable.offsets[0], None);
2216 let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2217 for count in 0..6u64 {
2218 let sizes = [4 * count, 4];
2219 assert_eq!(work_out(after, &sizes), 4 * count);
2220 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2221 }
2222 assert_eq!(laid_out.fields[1].align, 4);
2223 }
2224
2225 #[test]
2226 fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2227 let mut types = Types::new();
2228 let char_ty = types.int(IntKind::Char);
2229 let rows = measured(&mut types, 0);
2230 let double = types.float(FloatKind::Double);
2231 let fields = [member(char_ty), member(rows), member(double)];
2232 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2233
2234 assert_eq!(laid_out.layout, Layout::new(0, 8));
2235 assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2236 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2237 assert_eq!(variable.offsets[..2], [None, None]);
2238 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2239 for count in 0..6u64 {
2240 let sizes = [1, 4 * count, 8];
2241 let at = (4 + 4 * count).next_multiple_of(8);
2242 assert_eq!(work_out(after, &sizes), at);
2243 assert_eq!(work_out(&variable.size, &sizes), at + 8);
2244 }
2245 }
2246
2247 #[test]
2248 fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2249 let mut types = Types::new();
2250 let rows = measured(&mut types, 0);
2251 let double = types.float(FloatKind::Double);
2252 let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2253
2254 assert_eq!(laid_out.layout, Layout::new(0, 8));
2255 let variable = laid_out.variable.expect("a union with a member of no fixed size");
2256 assert!(variable.offsets.iter().all(Option::is_none));
2259 for count in 0..6u64 {
2260 let sizes = [4 * count, 8];
2261 let want = (4 * count).max(8).next_multiple_of(8);
2262 assert_eq!(work_out(&variable.size, &sizes), want);
2263 }
2264 }
2265
2266 #[test]
2267 fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2268 let mut types = Types::new();
2269 let char_ty = types.int(IntKind::Char);
2270 let int = types.int(IntKind::Int);
2271 let rows = measured(&mut types, 0);
2272 let fields = [member(char_ty), member(rows), member(int)];
2273 let options = RecordOptions { packed: true, ..RecordOptions::default() };
2274 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2275 .expect("a packed record with a member of no fixed size");
2276
2277 assert_eq!(laid_out.layout, Layout::new(0, 1));
2278 assert_eq!(laid_out.fields[2].align, 1);
2279 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2280 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2281 for count in 0..6u64 {
2282 let sizes = [1, 4 * count, 4];
2283 assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2284 assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2285 }
2286 }
2287
2288 #[test]
2289 fn bit_fields_after_a_member_of_no_fixed_size_are_placed_one_after_another() {
2290 let mut interner = Interner::new();
2291 let mut types = Types::new();
2292 let int = types.int(IntKind::Int);
2293 let char_ty = types.int(IntKind::Char);
2294 let rows = measured(&mut types, 0);
2295 let fields = [
2296 member(rows),
2297 bits(&mut interner, "b", int, 3),
2298 bits(&mut interner, "c", int, 30),
2299 member(char_ty),
2300 ];
2301 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2302
2303 assert_eq!((laid_out.fields[2].offset, laid_out.fields[2].bit), (0, 3));
2307 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2308 let after = variable.offsets[3].as_ref().expect("an offset the program works out");
2309 for count in 0..6u64 {
2310 let sizes = [4 * count, 4, 4, 1];
2311 assert_eq!(work_out(after, &sizes), 4 * count + 5);
2312 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 8);
2313 }
2314 }
2315
2316 #[test]
2317 fn a_zero_width_bit_field_that_needs_more_alignment_than_is_known_is_turned_down() {
2318 let mut types = Types::new();
2319 let int = types.int(IntKind::Int);
2320 let char_ty = types.int(IntKind::Char);
2321 let letters = types.array(char_ty, ArrayLen::Variable(VlaId(0)));
2322 let fields = [member(letters), unnamed_bits(int, 0)];
2323 let options = RecordOptions::default();
2324 let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2325
2326 assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2330 }
2331}