1#![doc(html_root_url = "https://docs.rs/rucc-types/0.19.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 an_alignment_asked_for_on_a_bit_field_moves_it_even_when_packed() {
1325 let mut interner = Interner::new();
1326 let 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 aligned = FieldDecl { align: Some(16), ..bits(&mut interner, "a", char_, 4) };
1334 let fields = [bits(&mut interner, "x", char_, 3), aligned];
1335 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1336 assert_eq!(laid_out.layout, Layout::new(32, 16));
1337 assert_eq!(offsets(&laid_out), [0, 128]);
1338
1339 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1341 let aligned = FieldDecl { align: Some(4), ..bits(&mut interner, "a", int, 4) };
1342 let fields = [bits(&mut interner, "x", char_, 3), aligned];
1343 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1344 .expect("a packed struct with an aligned bit-field");
1345 assert_eq!(laid_out.layout, Layout::new(8, 4));
1346 assert_eq!(offsets(&laid_out), [0, 32]);
1347
1348 let aligned = FieldDecl { align: Some(1), ..bits(&mut interner, "a", int, 4) };
1351 let fields = [bits(&mut interner, "x", char_, 3), aligned];
1352 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1353 .expect("a packed struct with a byte aligned bit-field");
1354 assert_eq!(laid_out.layout, Layout::new(2, 1));
1355 assert_eq!(offsets(&laid_out), [0, 8]);
1356
1357 let pack = RecordOptions { pack: Some(1), ..RecordOptions::default() };
1360 let fields = [
1361 bits(&mut interner, "x", int, 12),
1362 bits(&mut interner, "y", char_, 6),
1363 bits(&mut interner, "z", long_long, 63),
1364 FieldDecl { align: Some(16), ..bits(&mut interner, "a", char_, 4) },
1365 bits(&mut interner, "b", long_long, 2),
1366 ];
1367 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1368 .expect("a struct under pragma pack with an aligned bit-field");
1369 assert_eq!(laid_out.layout, Layout::new(12, 1));
1370 assert_eq!(offsets(&laid_out), [0, 12, 18, 88, 92]);
1371 }
1372
1373 #[test]
1374 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1375 let mut types = Types::new();
1377 let char_ = types.int(IntKind::Char);
1378 let int = types.int(IntKind::Int);
1379 let long_long = types.int(IntKind::LongLong);
1380
1381 let chars = types.array(char_, ArrayLen::Unknown);
1382 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1383 assert_eq!(laid_out.layout, Layout::new(4, 4));
1384 assert_eq!(offsets(&laid_out), [0, 32]);
1385
1386 let longs = types.array(long_long, ArrayLen::Unknown);
1388 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1389 assert_eq!(laid_out.layout, Layout::new(8, 8));
1390 assert_eq!(offsets(&laid_out), [0, 64]);
1391
1392 let fields = [member(chars), member(int)];
1394 let error =
1395 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1396 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1397 }
1398
1399 #[test]
1400 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1401 let types = Types::new();
1403 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1404 assert_eq!(laid_out.layout, Layout::new(0, 1));
1405 }
1406
1407 #[test]
1408 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1409 let types = Types::new();
1410 let int = types.int(IntKind::Int);
1411 let fields = [unnamed_bits(int, 33)];
1412 let error =
1413 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1414 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1415 assert_eq!(error, Err(want));
1416 }
1417
1418 #[test]
1419 fn a_record_reports_its_members_once_it_has_been_completed() {
1420 let mut interner = Interner::new();
1421 let mut types = Types::new();
1422 let char_ = types.int(IntKind::Char);
1423 let int = types.int(IntKind::Int);
1424 let name = interner.intern("count");
1425 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1426 let id = types.declare_record(RecordKind::Struct, None);
1427 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1428 types.complete_record(id, laid_out);
1429 let ty = types.record(id);
1430 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1431 let field = types.field(id, name).expect("the member that was declared");
1432 assert_eq!(field.offset, 4);
1433 assert!(!field.is_bit_field());
1434 assert_eq!(types.field(id, interner.intern("missing")), None);
1435 }
1436
1437 #[test]
1438 fn a_nested_record_brings_its_own_alignment_with_it() {
1439 let mut types = Types::new();
1440 let char_ = types.int(IntKind::Char);
1441 let int = types.int(IntKind::Int);
1442 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1443 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1444 assert_eq!(laid_out.layout, Layout::new(8, 4));
1445 assert_eq!(offsets(&laid_out), [0, 32]);
1446
1447 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1450 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1451 assert_eq!(laid_out.layout, Layout::new(12, 4));
1452 assert_eq!(offsets(&laid_out), [0, 32]);
1453 }
1454
1455 #[test]
1456 fn everything_narrower_than_an_int_promotes_to_one() {
1457 let mut types = Types::new();
1461 let linux = linux();
1462 let int = types.int(IntKind::Int);
1463 let narrow =
1464 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1465 for kind in narrow {
1466 let ty = types.int(kind);
1467 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1468 }
1469 let boolean = types.boolean();
1470 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1471
1472 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1474 let ty = types.int(kind);
1475 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1476 }
1477 }
1478
1479 #[test]
1480 fn a_bit_int_is_not_promoted_at_all() {
1481 let mut types = Types::new();
1484 let linux = linux();
1485 let small = types.bit_int(true, 8);
1486 assert_eq!(promote(&mut types, small, &linux), small);
1487 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1488 }
1489
1490 #[test]
1491 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1492 let mut types = Types::new();
1493 let linux = linux();
1494 let int = types.int(IntKind::Int);
1495 let uint = types.int(IntKind::UInt);
1496 let ullong = types.int(IntKind::ULongLong);
1497
1498 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1500 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1502 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1504 let forty = types.bit_int(false, 40);
1509 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1510 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1512 }
1513
1514 #[test]
1515 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1516 let mut types = Types::new();
1517 let linux = linux();
1518 let int = types.int(IntKind::Int);
1519 let short = types.int(IntKind::Short);
1520 let uint = types.int(IntKind::UInt);
1521
1522 let fixed = types.declare_enum(None);
1524 types.complete_enum(fixed, short, true);
1525 let fixed = types.enumeration(fixed);
1526 assert_eq!(promote(&mut types, fixed, &linux), int);
1527
1528 let unsigned = types.declare_enum(None);
1531 types.complete_enum(unsigned, uint, false);
1532 let unsigned = types.enumeration(unsigned);
1533 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1534
1535 let undecided = types.declare_enum(None);
1538 let undecided = types.enumeration(undecided);
1539 assert_eq!(promote(&mut types, undecided, &linux), int);
1540 }
1541
1542 #[test]
1543 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1544 let mut types = Types::new();
1547 let linux = linux();
1548 let int = types.int(IntKind::Int);
1549 let konst = types.qualified(int, Qualifiers::CONST);
1550 let atomic = types.atomic(konst);
1551 assert_eq!(promote(&mut types, atomic, &linux), int);
1552 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1553 }
1554
1555 #[test]
1556 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1557 let mut types = Types::new();
1559 let linux = linux();
1560 let cases = [
1561 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1562 (IntKind::Int, IntKind::Long, IntKind::Long),
1563 (IntKind::UInt, IntKind::Long, IntKind::Long),
1564 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1565 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1566 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1567 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1568 (IntKind::Char, IntKind::Char, IntKind::Int),
1569 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1570 ];
1571 for (left, right, want) in cases {
1572 let left = types.int(left);
1573 let right = types.int(right);
1574 let want = types.int(want);
1575 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1576 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1577 }
1578 }
1579
1580 #[test]
1581 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1582 let mut types = Types::new();
1586 let linux = linux();
1587 let signed = types.int(IntKind::Int128);
1588 let unsigned = types.int(IntKind::UInt128);
1589 for id in [signed, unsigned] {
1590 let laid_out = layout(&types, id, &linux).expect("a complete type");
1591 assert_eq!(laid_out.size, 16);
1592 assert_eq!(laid_out.align, 16);
1593 }
1594
1595 let ull = types.int(IntKind::ULongLong);
1599 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1600 assert_eq!(promote(&mut types, signed, &linux), signed);
1602 }
1603
1604 #[test]
1605 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1606 let mut types = Types::new();
1609 let linux = linux();
1610 let int128 = types.int(IntKind::Int128);
1611 let bit_int = types.bit_int(true, 128);
1612 assert_ne!(int128, bit_int);
1613 assert!(!compatible(&types, int128, bit_int));
1614 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1615 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1616 }
1617
1618 #[test]
1619 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1620 let mut types = Types::new();
1624 let linux = linux();
1625 let ulong = types.int(IntKind::ULong);
1626 let long_long = types.int(IntKind::LongLong);
1627 let want = types.int(IntKind::ULongLong);
1628 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1629
1630 let windows = target("x86_64-pc-windows-msvc");
1634 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1635 }
1636
1637 #[test]
1638 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1639 let mut types = Types::new();
1641 let linux = linux();
1642 let b40 = types.bit_int(true, 40);
1643 let ub40 = types.bit_int(false, 40);
1644 let b8 = types.bit_int(true, 8);
1645 let b32 = types.bit_int(true, 32);
1646 let int = types.int(IntKind::Int);
1647 let uint = types.int(IntKind::UInt);
1648 let long = types.int(IntKind::Long);
1649 let char_ = types.int(IntKind::Char);
1650
1651 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1653 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1655 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1657 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1658 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1661 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1664 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1665 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1667 }
1668
1669 #[test]
1670 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1671 let mut types = Types::new();
1672 let linux = linux();
1673 let float = types.float(FloatKind::Float);
1674 let double = types.float(FloatKind::Double);
1675 let long_double = types.float(FloatKind::LongDouble);
1676 let ullong = types.int(IntKind::ULongLong);
1677 let int = types.int(IntKind::Int);
1678
1679 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1680 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1681 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1682 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1685 }
1686
1687 #[test]
1688 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1689 let mut types = Types::new();
1690 let linux = linux();
1691 let int = types.int(IntKind::Int);
1692 let float = types.float(FloatKind::Float);
1693 let short = types.int(IntKind::Short);
1694
1695 let four_ints = types.vector(int, 4);
1697 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1698
1699 let uint = types.int(IntKind::UInt);
1702 let four_uints = types.vector(uint, 4);
1703 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1704
1705 let four_floats = types.vector(float, 4);
1708 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1709
1710 let two_shorts = types.vector(short, 2);
1712 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1713
1714 assert_eq!(mask_of(&mut types, int, &linux), None);
1716 }
1717
1718 #[test]
1719 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1720 let mut types = Types::new();
1721 let linux = linux();
1722 let int = types.int(IntKind::Int);
1723 let uint = types.int(IntKind::UInt);
1724 let float = types.float(FloatKind::Float);
1725 let short = types.int(IntKind::Short);
1726
1727 let four_ints = types.vector(int, 4);
1728 let four_uints = types.vector(uint, 4);
1729 let four_floats = types.vector(float, 4);
1730 let eight_shorts = types.vector(short, 8);
1731 let two_ints = types.vector(int, 2);
1732
1733 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1736 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1738 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1740 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1742
1743 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1746 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1748 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1750 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1751 }
1752
1753 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1758 let mut types = Types::new();
1759 let left = types.float(a);
1760 let right = types.float(b);
1761 let want = types.float(expected);
1762 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1763 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1764 }
1765
1766 #[test]
1767 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1768 let x86 = linux();
1772 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1773 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1774 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1775 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1776 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1777 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1778 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1779 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1780 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1781 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1782 }
1783
1784 #[test]
1785 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1786 let mac = target("aarch64-apple-darwin");
1790 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1791 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1792 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1793 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1794 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1795 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1796 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1797 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1800 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1801 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1802 }
1803
1804 #[test]
1805 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1806 let mut types = Types::new();
1807 let linux = linux();
1808 let cfloat = types.complex_float(FloatKind::Float);
1809 let cdouble = types.complex_float(FloatKind::Double);
1810 let cldouble = types.complex_float(FloatKind::LongDouble);
1811 let double = types.float(FloatKind::Double);
1812 let long_double = types.float(FloatKind::LongDouble);
1813 let float = types.float(FloatKind::Float);
1814 let int = types.int(IntKind::Int);
1815
1816 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1817 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1818 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1819 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1820 }
1821
1822 #[test]
1823 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1824 let mut types = Types::new();
1826 let linux = linux();
1827 let int = types.int(IntKind::Int);
1828 let pointer = types.pointer(int);
1829 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1830 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1831 let void = types.void();
1832 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1833 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1836 }
1837
1838 #[test]
1839 fn the_conversions_read_through_sugar() {
1840 let mut interner = Interner::new();
1841 let mut types = Types::new();
1842 let linux = linux();
1843 let char_ = types.int(IntKind::Char);
1844 let name = types.typedef(interner.intern("byte"), char_);
1845 let int = types.int(IntKind::Int);
1846 assert_eq!(promote(&mut types, name, &linux), int);
1847 }
1848
1849 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1851 let ret = types.void();
1852 types.function(FunctionType {
1853 ret,
1854 params,
1855 variadic,
1856 prototyped: true,
1857 convention: rucc_target::Convention::Target,
1858 })
1859 }
1860
1861 fn old_style(types: &mut Types) -> TypeId {
1863 let ret = types.void();
1864 types.function(FunctionType {
1865 ret,
1866 params: Vec::new(),
1867 variadic: false,
1868 prototyped: false,
1869 convention: rucc_target::Convention::Target,
1870 })
1871 }
1872
1873 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1875 let id = types.declare_record(RecordKind::Struct, Some(tag));
1876 let laid_out = lay_out(types, RecordKind::Struct, fields);
1877 types.complete_record(id, laid_out);
1878 id
1879 }
1880
1881 #[test]
1882 fn a_type_is_compatible_with_itself_however_it_was_written() {
1883 let mut interner = Interner::new();
1884 let mut types = Types::new();
1885 let int = types.int(IntKind::Int);
1886 let name = types.typedef(interner.intern("int32_t"), int);
1887 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1888 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1889
1890 let konst = types.qualified(int, Qualifiers::CONST);
1893 assert!(!compatible(&types, konst, int));
1894 let konst_pointer = types.pointer(konst);
1895 let pointer = types.pointer(int);
1896 assert!(!compatible(&types, konst_pointer, pointer));
1897 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1898
1899 let char_ = types.int(IntKind::Char);
1902 let schar = types.int(IntKind::SChar);
1903 assert!(!compatible(&types, char_, schar));
1904 let atomic = types.atomic(int);
1906 assert!(!compatible(&types, atomic, int));
1907 }
1908
1909 #[test]
1910 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1911 let mut types = Types::new();
1914 let uint = types.int(IntKind::UInt);
1915 let int = types.int(IntKind::Int);
1916 let id = types.declare_enum(None);
1917 types.complete_enum(id, uint, false);
1918 let e = types.enumeration(id);
1919 assert!(compatible(&types, e, uint));
1920 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1921 assert!(!compatible(&types, e, int));
1922
1923 let other = types.declare_enum(None);
1926 types.complete_enum(other, uint, false);
1927 let other = types.enumeration(other);
1928 assert!(!compatible(&types, e, other));
1929
1930 let undecided = types.declare_enum(None);
1933 let undecided = types.enumeration(undecided);
1934 assert!(!compatible(&types, undecided, uint));
1935 assert!(compatible(&types, undecided, undecided));
1936 }
1937
1938 #[test]
1939 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1940 let mut types = Types::new();
1943 let int = types.int(IntKind::Int);
1944 let unknown = types.array(int, ArrayLen::Unknown);
1945 let four = types.array(int, ArrayLen::Fixed(4));
1946 let five = types.array(int, ArrayLen::Fixed(5));
1947 assert!(compatible(&types, unknown, four));
1948 assert!(!compatible(&types, four, five));
1949 assert_eq!(composite(&mut types, unknown, four), Some(four));
1950 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1951 assert_eq!(composite(&mut types, four, five), None);
1952
1953 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1956 assert!(compatible(&types, vla, four));
1957 assert_eq!(composite(&mut types, vla, four), Some(four));
1958
1959 let long = types.int(IntKind::Long);
1961 let longs = types.array(long, ArrayLen::Fixed(4));
1962 assert!(!compatible(&types, four, longs));
1963 }
1964
1965 #[test]
1966 fn a_parameter_declared_as_an_array_is_a_pointer() {
1967 let mut types = Types::new();
1971 let int = types.int(IntKind::Int);
1972 let three = types.array(int, ArrayLen::Fixed(3));
1973 let pointer = types.pointer(int);
1974 assert_eq!(adjust_parameter(&mut types, three), pointer);
1975
1976 let function = prototype(&mut types, vec![int], false);
1978 let function_pointer = types.pointer(function);
1979 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1980
1981 let konst = types.qualified(int, Qualifiers::CONST);
1984 assert_eq!(adjust_parameter(&mut types, konst), int);
1985 let to_konst = types.pointer(konst);
1986 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1987 }
1988
1989 #[test]
1990 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1991 let mut types = Types::new();
1995 let old = old_style(&mut types);
1996 let int = types.int(IntKind::Int);
1997 let long = types.int(IntKind::Long);
1998 let char_ = types.int(IntKind::Char);
1999 let float = types.float(FloatKind::Float);
2000 let double = types.float(FloatKind::Double);
2001
2002 let takes_int = prototype(&mut types, vec![int], false);
2003 assert!(compatible(&types, old, takes_int));
2004 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
2005 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
2007
2008 let pointer = types.pointer(int);
2009 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
2010 let ty = prototype(&mut types, params, false);
2011 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
2012 }
2013
2014 for params in [vec![char_], vec![float], vec![int, char_]] {
2017 let ty = prototype(&mut types, params, false);
2018 assert!(!compatible(&types, old, ty));
2019 assert_eq!(composite(&mut types, old, ty), None);
2020 }
2021
2022 let variadic = prototype(&mut types, vec![int], true);
2024 assert!(!compatible(&types, old, variadic));
2025
2026 let uint = types.int(IntKind::UInt);
2028 let id = types.declare_enum(None);
2029 types.complete_enum(id, uint, false);
2030 let e = types.enumeration(id);
2031 let takes_enum = prototype(&mut types, vec![e], false);
2032 assert!(compatible(&types, old, takes_enum));
2033
2034 assert!(compatible(&types, old, old));
2036
2037 let returns_int = types.function(FunctionType {
2039 ret: int,
2040 params: Vec::new(),
2041 variadic: false,
2042 prototyped: false,
2043 convention: rucc_target::Convention::Target,
2044 });
2045 assert!(!compatible(&types, returns_int, takes_int));
2046 }
2047
2048 #[test]
2052 fn two_conventions_are_two_incompatible_types() {
2053 let mut types = Types::new();
2054 let int = types.int(IntKind::Int);
2055 let signature = FunctionType {
2056 ret: int,
2057 params: vec![int],
2058 variadic: false,
2059 prototyped: true,
2060 convention: rucc_target::Convention::Ms,
2061 };
2062 let native = types.function(FunctionType {
2063 convention: rucc_target::Convention::Target,
2064 ..signature.clone()
2065 });
2066 let ms = types.function(signature);
2067 let old_ms = types.function(FunctionType {
2068 ret: int,
2069 params: Vec::new(),
2070 variadic: false,
2071 prototyped: false,
2072 convention: rucc_target::Convention::Ms,
2073 });
2074 assert!(!compatible(&types, native, ms));
2075 let (to_native, to_ms) = (types.pointer(native), types.pointer(ms));
2076 assert!(!compatible(&types, to_native, to_ms));
2077 assert!(compatible(&types, ms, old_ms));
2078 let merged = composite(&mut types, old_ms, ms).expect("the two agree");
2079 let TypeKind::Function(id) = types.kind(merged) else { panic!("a function") };
2080 assert_eq!(types.signature(id).convention, rucc_target::Convention::Ms);
2081 assert!(types.signature(id).prototyped);
2082 }
2083
2084 #[test]
2085 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
2086 let mut types = Types::new();
2090 let int = types.int(IntKind::Int);
2091 let takes_int = prototype(&mut types, vec![int], false);
2092 let takes_nothing = prototype(&mut types, Vec::new(), false);
2093 let old = old_style(&mut types);
2094 assert!(!compatible(&types, takes_nothing, takes_int));
2095 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
2096 }
2097
2098 #[test]
2099 fn two_prototypes_have_to_agree_about_everything() {
2100 let mut types = Types::new();
2101 let int = types.int(IntKind::Int);
2102 let long = types.int(IntKind::Long);
2103 let base = prototype(&mut types, vec![int, int], false);
2104 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
2105 let other = prototype(&mut types, other, false);
2106 assert!(!compatible(&types, base, other));
2107 }
2108 let variadic = prototype(&mut types, vec![int, int], true);
2109 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
2110
2111 let four = types.array(int, ArrayLen::Fixed(4));
2114 let unknown = types.array(int, ArrayLen::Unknown);
2115 let to_four = types.pointer(four);
2116 let to_unknown = types.pointer(unknown);
2117 let a = prototype(&mut types, vec![to_four], false);
2118 let b = prototype(&mut types, vec![to_unknown], false);
2119 assert!(compatible(&types, a, b));
2120 assert_eq!(composite(&mut types, a, b), Some(a));
2122 }
2123
2124 #[test]
2125 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
2126 let mut types = Types::new();
2127 let int = types.int(IntKind::Int);
2128 let four = types.array(int, ArrayLen::Fixed(4));
2129 let unknown = types.array(int, ArrayLen::Unknown);
2130 let to_four = types.pointer(four);
2131 let to_unknown = types.pointer(unknown);
2132 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
2133
2134 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
2136 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
2137 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
2138 }
2139
2140 #[test]
2141 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
2142 let mut interner = Interner::new();
2146 let mut types = Types::new();
2147 let tag = interner.intern("point");
2148 let x = interner.intern("x");
2149 let y = interner.intern("y");
2150 let int = types.int(IntKind::Int);
2151 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
2152
2153 let first = tagged(&mut types, tag, &members);
2154 let second = tagged(&mut types, tag, &members);
2155 let first = types.record(first);
2156 let second = types.record(second);
2157 assert_ne!(first, second, "still two declarations and two types");
2158 assert!(compatible(&types, first, second));
2159
2160 let z = interner.intern("z");
2163 let long = types.int(IntKind::Long);
2164 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
2165 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
2166 for other in [&renamed[..], &retyped[..], &members[..1]] {
2167 let other = tagged(&mut types, tag, other);
2168 let other = types.record(other);
2169 assert!(!compatible(&types, first, other));
2170 }
2171 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
2172 let elsewhere = types.record(elsewhere);
2173 assert!(!compatible(&types, first, elsewhere));
2174
2175 let anonymous = record(&mut types, RecordKind::Struct, &members);
2178 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
2179 assert!(!compatible(&types, anonymous, also_anonymous));
2180
2181 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
2183 let incomplete = types.record(incomplete);
2184 assert!(!compatible(&types, first, incomplete));
2185 assert!(compatible(&types, incomplete, incomplete));
2186 }
2187
2188 #[test]
2189 fn a_self_referential_record_is_compared_without_going_round_forever() {
2190 let mut interner = Interner::new();
2194 let mut types = Types::new();
2195 let tag = interner.intern("node");
2196 let value = interner.intern("value");
2197 let next = interner.intern("next");
2198 let int = types.int(IntKind::Int);
2199
2200 let node = |types: &mut Types| {
2201 let id = types.declare_record(RecordKind::Struct, Some(tag));
2202 let ty = types.record(id);
2203 let pointer = types.pointer(ty);
2204 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
2205 let laid_out = lay_out(types, RecordKind::Struct, &members);
2206 types.complete_record(id, laid_out);
2207 ty
2208 };
2209 let first = node(&mut types);
2210 let second = node(&mut types);
2211 assert_ne!(first, second);
2212 assert!(compatible(&types, first, second));
2213
2214 let id = types.declare_record(RecordKind::Struct, Some(tag));
2217 let ty = types.record(id);
2218 let pointer = types.pointer(ty);
2219 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
2220 let laid_out = lay_out(&types, RecordKind::Struct, &members);
2221 types.complete_record(id, laid_out);
2222 assert!(!compatible(&types, first, ty));
2223 }
2224
2225 #[test]
2226 fn layout_reads_through_sugar() {
2227 let mut interner = Interner::new();
2228 let mut types = Types::new();
2229 let long = types.int(IntKind::Long);
2230 let name = types.typedef(interner.intern("word"), long);
2231 let array = types.array(name, ArrayLen::Fixed(4));
2232 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
2233 }
2234
2235 fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
2241 match recipe {
2242 Extent::Bytes(count) => *count,
2243 Extent::Member(index) => sizes[*index as usize],
2244 Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
2245 Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
2246 Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
2247 }
2248 }
2249
2250 fn measured(types: &mut Types, which: u32) -> TypeId {
2252 let int = types.int(IntKind::Int);
2253 types.array(int, ArrayLen::Variable(VlaId(which)))
2254 }
2255
2256 #[test]
2257 fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2258 let mut types = Types::new();
2259 let int = types.int(IntKind::Int);
2260 let rows = measured(&mut types, 0);
2261 let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2262
2263 assert_eq!(laid_out.layout, Layout::new(0, 4));
2266 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2267 assert_eq!(variable.offsets[0], None);
2271 let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2272 for count in 0..6u64 {
2273 let sizes = [4 * count, 4];
2274 assert_eq!(work_out(after, &sizes), 4 * count);
2275 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2276 }
2277 assert_eq!(laid_out.fields[1].align, 4);
2278 }
2279
2280 #[test]
2281 fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2282 let mut types = Types::new();
2283 let char_ty = types.int(IntKind::Char);
2284 let rows = measured(&mut types, 0);
2285 let double = types.float(FloatKind::Double);
2286 let fields = [member(char_ty), member(rows), member(double)];
2287 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2288
2289 assert_eq!(laid_out.layout, Layout::new(0, 8));
2290 assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2291 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2292 assert_eq!(variable.offsets[..2], [None, None]);
2293 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2294 for count in 0..6u64 {
2295 let sizes = [1, 4 * count, 8];
2296 let at = (4 + 4 * count).next_multiple_of(8);
2297 assert_eq!(work_out(after, &sizes), at);
2298 assert_eq!(work_out(&variable.size, &sizes), at + 8);
2299 }
2300 }
2301
2302 #[test]
2303 fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2304 let mut types = Types::new();
2305 let rows = measured(&mut types, 0);
2306 let double = types.float(FloatKind::Double);
2307 let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2308
2309 assert_eq!(laid_out.layout, Layout::new(0, 8));
2310 let variable = laid_out.variable.expect("a union with a member of no fixed size");
2311 assert!(variable.offsets.iter().all(Option::is_none));
2314 for count in 0..6u64 {
2315 let sizes = [4 * count, 8];
2316 let want = (4 * count).max(8).next_multiple_of(8);
2317 assert_eq!(work_out(&variable.size, &sizes), want);
2318 }
2319 }
2320
2321 #[test]
2322 fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2323 let mut types = Types::new();
2324 let char_ty = types.int(IntKind::Char);
2325 let int = types.int(IntKind::Int);
2326 let rows = measured(&mut types, 0);
2327 let fields = [member(char_ty), member(rows), member(int)];
2328 let options = RecordOptions { packed: true, ..RecordOptions::default() };
2329 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2330 .expect("a packed record with a member of no fixed size");
2331
2332 assert_eq!(laid_out.layout, Layout::new(0, 1));
2333 assert_eq!(laid_out.fields[2].align, 1);
2334 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2335 let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2336 for count in 0..6u64 {
2337 let sizes = [1, 4 * count, 4];
2338 assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2339 assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2340 }
2341 }
2342
2343 #[test]
2344 fn bit_fields_after_a_member_of_no_fixed_size_are_placed_one_after_another() {
2345 let mut interner = Interner::new();
2346 let mut types = Types::new();
2347 let int = types.int(IntKind::Int);
2348 let char_ty = types.int(IntKind::Char);
2349 let rows = measured(&mut types, 0);
2350 let fields = [
2351 member(rows),
2352 bits(&mut interner, "b", int, 3),
2353 bits(&mut interner, "c", int, 30),
2354 member(char_ty),
2355 ];
2356 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2357
2358 assert_eq!((laid_out.fields[2].offset, laid_out.fields[2].bit), (0, 3));
2362 let variable = laid_out.variable.expect("a record with a member of no fixed size");
2363 let after = variable.offsets[3].as_ref().expect("an offset the program works out");
2364 for count in 0..6u64 {
2365 let sizes = [4 * count, 4, 4, 1];
2366 assert_eq!(work_out(after, &sizes), 4 * count + 5);
2367 assert_eq!(work_out(&variable.size, &sizes), 4 * count + 8);
2368 }
2369 }
2370
2371 #[test]
2372 fn a_zero_width_bit_field_that_needs_more_alignment_than_is_known_is_turned_down() {
2373 let mut types = Types::new();
2374 let int = types.int(IntKind::Int);
2375 let char_ty = types.int(IntKind::Char);
2376 let letters = types.array(char_ty, ArrayLen::Variable(VlaId(0)));
2377 let fields = [member(letters), unnamed_bits(int, 0)];
2378 let options = RecordOptions::default();
2379 let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2380
2381 assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2385 }
2386}