1#![doc(html_root_url = "https://docs.rs/rucc-types/0.5.2")]
82
83mod classify;
84mod compat;
85mod convert;
86mod kind;
87mod layout;
88mod print;
89mod record;
90mod types;
91
92pub use crate::classify::{
93 element, is_aggregate, is_arithmetic, is_array, is_atomic, is_complete, is_complex,
94 is_floating, is_function, is_integer, is_modifiable, is_object, is_pointer, is_real,
95 is_real_floating, is_record, is_scalar, is_vector, is_void, pointee,
96};
97pub use crate::compat::{adjust_parameter, compatible, composite};
98pub use crate::convert::{promote, promote_bit_field, usual_arithmetic};
99pub use crate::kind::{
100 ArrayLen, EnumId, FloatKind, FunctionId, FunctionType, IntKind, Qualifiers, RecordId,
101 RecordKind, Type, TypeKind, VlaId,
102};
103pub use crate::layout::{
104 IntegerInfo, Layout, LayoutError, float_format, float_width, int_width, integer_info, layout,
105};
106pub use crate::print::{declare, spell};
107pub use crate::record::{
108 Field, FieldDecl, RecordError, RecordLayout, RecordOptions, layout_record,
109};
110pub use crate::types::{EnumInfo, RecordInfo, TypeId, Types};
111
112pub const MILESTONE: &str = "M2";
114
115#[cfg(test)]
116mod tests {
117 use std::num::NonZeroU32;
118
119 use rucc_base::{Interner, Symbol};
120 use rucc_target::{TargetInfo, Triple};
121
122 use super::*;
123
124 fn target(triple: &str) -> TargetInfo {
125 TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
126 }
127
128 fn linux() -> TargetInfo {
129 target("x86_64-unknown-linux-gnu")
130 }
131
132 fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
134 layout_record(types, kind, fields, &RecordOptions::default(), &linux())
135 .expect("a record every member of which has a layout")
136 }
137
138 fn offsets(laid_out: &RecordLayout) -> Vec<u128> {
141 laid_out.fields.iter().map(Field::bit_offset).collect()
142 }
143
144 fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
146 let id = types.declare_record(kind, None);
147 let laid_out = lay_out(types, kind, fields);
148 types.complete_record(id, laid_out);
149 types.record(id)
150 }
151
152 fn member(ty: TypeId) -> FieldDecl {
154 FieldDecl::new(None, ty)
155 }
156
157 fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
160 FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
161 }
162
163 fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
165 FieldDecl::bit_field(None, ty, width)
166 }
167
168 #[test]
169 fn milestone_is_recorded() {
170 assert!(MILESTONE.starts_with('M'));
171 }
172
173 #[test]
174 fn an_integer_type_answers_with_the_width_of_its_value_and_not_of_its_object() {
175 let mut interner = Interner::new();
176 let mut types = Types::new();
177 let target = linux();
178
179 let boolean = types.boolean();
182 let bits = types.bit_int(true, 37);
183 let short = types.int(IntKind::Short);
185 let alias = types.typedef(interner.intern("word"), short);
186 let unsigned_char = types.int(IntKind::UChar);
187 let atomic = types.atomic(unsigned_char);
188
189 let shape = |ty| integer_info(&types, ty, &target).expect("an integer type");
190 assert_eq!(shape(boolean), IntegerInfo::new(false, 1));
191 assert_eq!(shape(bits), IntegerInfo::new(true, 37));
192 assert_eq!(shape(types.int(IntKind::Int)), IntegerInfo::new(true, 32));
193 assert_eq!(shape(types.int(IntKind::ULong)), IntegerInfo::new(false, 64));
194 assert_eq!(shape(alias), IntegerInfo::new(true, 16));
195 assert_eq!(shape(atomic), IntegerInfo::new(false, 8));
196
197 assert_eq!(integer_info(&types, types.float(FloatKind::Double), &target), None);
198 }
199
200 #[test]
201 fn an_enumeration_answers_with_the_type_the_enumerators_are_kept_in() {
202 let mut interner = Interner::new();
203 let mut types = Types::new();
204 let target = linux();
205
206 let colour = types.declare_enum(Some(interner.intern("colour")));
209 let ty = types.enumeration(colour);
210 assert_eq!(integer_info(&types, ty, &target), None);
211
212 let underlying = types.int(IntKind::ULong);
213 types.complete_enum(colour, underlying, true);
214 assert_eq!(integer_info(&types, ty, &target), Some(IntegerInfo::new(false, 64)));
215 }
216
217 #[test]
218 fn a_value_stored_in_an_integer_type_keeps_the_bits_the_type_has_room_for() {
219 let char_type = IntegerInfo::new(true, 8);
220 assert_eq!(char_type.wrap(300), 44);
221 assert!(!char_type.holds(300));
222 assert!(char_type.holds(-128));
223
224 assert_eq!(IntegerInfo::new(false, 32).wrap(-1), 4_294_967_295);
225 assert_eq!(IntegerInfo::new(false, 8).wrap(-1), 255);
226
227 assert!(IntegerInfo::new(false, 128).holds(i128::MIN));
230 assert!(IntegerInfo::new(true, 128).holds(i128::MIN));
231 assert_eq!(IntegerInfo::new(true, 128).wrap(i128::MAX), i128::MAX);
232 }
233
234 #[test]
235 fn a_long_double_has_a_format_the_size_does_not_give_away() {
236 let target = linux();
237 assert_eq!(float_width(FloatKind::LongDouble, &target), 128);
240 assert_eq!(
241 float_format(FloatKind::LongDouble, &target),
242 rucc_base::float::Format::X87Extended
243 );
244 assert_eq!(float_format(FloatKind::Float, &target), rucc_base::float::Format::Single);
245 }
246
247 #[test]
248 fn an_interchange_type_names_a_format_and_an_extended_one_names_the_target() {
249 use rucc_base::float::Format;
250
251 for target in [&linux(), &target("aarch64-apple-darwin")] {
254 assert_eq!(float_format(FloatKind::Float16, target), Format::Half);
255 assert_eq!(float_format(FloatKind::Float32, target), Format::Single);
256 assert_eq!(float_format(FloatKind::Float64, target), Format::Double);
257 assert_eq!(float_format(FloatKind::Float128, target), Format::Quad);
258 assert_eq!(float_width(FloatKind::Float16, target), 16);
259 assert_eq!(float_width(FloatKind::Float32, target), 32);
260 assert_eq!(float_width(FloatKind::Float64, target), 64);
261 assert_eq!(float_width(FloatKind::Float128, target), 128);
262 assert_eq!(float_format(FloatKind::Float32x, target), Format::Double);
264 }
265
266 let x86 = linux();
270 assert_eq!(float_format(FloatKind::Float64x, &x86), Format::X87Extended);
271 assert_eq!(float_format(FloatKind::LongDouble, &x86), Format::X87Extended);
272 let mac = target("aarch64-apple-darwin");
273 assert_eq!(float_format(FloatKind::Float64x, &mac), Format::Quad);
274 assert_eq!(float_format(FloatKind::LongDouble, &mac), Format::Double);
275 assert_eq!(float_width(FloatKind::Float64x, &x86), 128);
278 assert_eq!(float_width(FloatKind::Float64x, &mac), 128);
279 }
280
281 #[test]
282 fn every_floating_type_is_as_wide_as_the_format_it_is_stored_in() {
283 let types = Types::new();
284 let sizes = |target: &TargetInfo| -> Vec<(u64, u64)> {
285 FloatKind::ALL
286 .iter()
287 .map(|&kind| {
288 let found = layout(&types, types.float(kind), target).expect("a complete type");
289 (found.size, found.align)
290 })
291 .collect()
292 };
293 assert_eq!(
297 sizes(&linux()),
298 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16), (16, 16)]
299 );
300 assert_eq!(
301 sizes(&target("aarch64-apple-darwin")),
302 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16)]
303 );
304 }
305
306 #[test]
307 fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
308 let types = Types::new();
311 let mut seen = Vec::new();
312 for kind in FloatKind::ALL {
313 seen.push(types.float(kind));
314 }
315 let mut sorted = seen.clone();
316 sorted.sort_unstable();
317 sorted.dedup();
318 assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
319
320 let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
321 assert_eq!(
322 names,
323 [
324 "_Float16",
325 "float",
326 "_Float32",
327 "double",
328 "_Float32x",
329 "_Float64",
330 "long double",
331 "_Float64x",
332 "_Float128",
333 ]
334 );
335 }
336
337 #[test]
338 fn the_same_type_asked_for_twice_is_the_same_id() {
339 let mut types = Types::new();
340 let a = types.pointer(types.int(IntKind::Int));
341 let b = types.pointer(types.int(IntKind::Int));
342 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
343 let c = types.pointer(types.int(IntKind::Long));
344 assert_ne!(a, c);
345 }
346
347 #[test]
348 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
349 let mut types = Types::new();
350 let int = types.int(IntKind::Int);
351 let konst = types.qualified(int, Qualifiers::CONST);
352 assert_ne!(int, konst);
353 assert_eq!(types.kind(konst), types.kind(int));
354 assert!(types.quals(konst).has(Qualifiers::CONST));
355 assert_eq!(types.unqualified(konst), int);
356 }
357
358 #[test]
359 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
360 let mut types = Types::new();
361 let int = types.int(IntKind::Int);
362 let a = types.qualified(int, Qualifiers::CONST);
363 let a = types.qualified(a, Qualifiers::VOLATILE);
364 let b = types.qualified(int, Qualifiers::VOLATILE);
365 let b = types.qualified(b, Qualifiers::CONST);
366 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
367 }
368
369 #[test]
370 fn qualifying_an_array_qualifies_its_element() {
371 let mut types = Types::new();
374 let int = types.int(IntKind::Int);
375 let array = types.array(int, ArrayLen::Fixed(4));
376 let konst = types.qualified(array, Qualifiers::CONST);
377 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
378 let TypeKind::Array { elem, len } = types.kind(konst) else {
379 panic!("still an array");
380 };
381 assert_eq!(len, ArrayLen::Fixed(4));
382 assert!(types.quals(elem).has(Qualifiers::CONST));
383 }
384
385 #[test]
386 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
387 let mut interner = Interner::new();
388 let mut types = Types::new();
389 let int = types.int(IntKind::Int);
390 let name = types.typedef(interner.intern("int32_t"), int);
391 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
392 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
393 assert!(types.is_sugar(name));
394 assert!(!types.is_sugar(int));
395 }
396
397 #[test]
398 fn sugar_below_the_outermost_node_is_resolved_too() {
399 let mut interner = Interner::new();
402 let mut types = Types::new();
403 let int = types.int(IntKind::Int);
404 let name = types.typedef(interner.intern("int32_t"), int);
405 let sugar_pointer = types.pointer(name);
406 let plain_pointer = types.pointer(int);
407 assert_ne!(sugar_pointer, plain_pointer);
408 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
409
410 let sugar_array = types.array(name, ArrayLen::Fixed(3));
411 let plain_array = types.array(int, ArrayLen::Fixed(3));
412 assert_eq!(types.canonical(sugar_array), plain_array);
413 }
414
415 #[test]
416 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
417 let mut interner = Interner::new();
418 let mut types = Types::new();
419 let int = types.int(IntKind::Int);
420 let mut current = int;
421 for i in 0..8 {
422 current = types.typedef(interner.intern(&format!("t{i}")), current);
423 }
424 assert_eq!(types.canonical(current), int);
425 }
426
427 #[test]
428 fn a_typedef_that_asked_for_an_alignment_says_what_it_is_and_not_what_it_is_at_least() {
429 let mut interner = Interner::new();
434 let mut types = Types::new();
435 let target = linux();
436 let int = types.int(IntKind::Int);
437 let low = types.aligned_typedef(interner.intern("L"), int, NonZeroU32::new(2).unwrap());
438 let high = types.aligned_typedef(interner.intern("H"), int, NonZeroU32::new(16).unwrap());
439
440 assert_eq!(layout(&types, low, &target), Ok(Layout::new(4, 2)));
441 assert_eq!(layout(&types, high, &target), Ok(Layout::new(4, 16)));
442 assert_eq!(layout(&types, int, &target), Ok(Layout::new(4, 4)));
445
446 assert_ne!(low, high);
449
450 let outer = types.aligned_typedef(interner.intern("M"), low, NonZeroU32::new(8).unwrap());
453 assert_eq!(types.align_override(outer), NonZeroU32::new(8));
454 let plain = types.typedef(interner.intern("N"), low);
455 assert_eq!(types.align_override(plain), NonZeroU32::new(2));
456 assert_eq!(types.align_override(int), None);
458 }
459
460 #[test]
461 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
462 let mut interner = Interner::new();
463 let mut types = Types::new();
464 let int = types.int(IntKind::Int);
465 let name = types.typedef(interner.intern("int32_t"), int);
466 let konst = types.qualified(name, Qualifiers::CONST);
467 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
468 let want = types.qualified(int, Qualifiers::CONST);
469 assert_eq!(types.canonical(konst), want);
470 }
471
472 #[test]
473 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
474 let mut interner = Interner::new();
477 let mut types = Types::new();
478 let int = types.int(IntKind::Int);
479 let array = types.array(int, ArrayLen::Fixed(4));
480 let name = types.typedef(interner.intern("A"), array);
481 let konst = types.qualified(name, Qualifiers::CONST);
482 let konst_int = types.qualified(int, Qualifiers::CONST);
483 let want = types.array(konst_int, ArrayLen::Fixed(4));
484 assert_eq!(types.canonical(konst), want);
485 }
486
487 #[test]
488 fn a_function_type_is_deduplicated_by_its_signature() {
489 let mut types = Types::new();
490 let int = types.int(IntKind::Int);
491 let long = types.int(IntKind::Long);
492 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
493 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
494 };
495 let a = make(&mut types, vec![int, long], false);
496 let b = make(&mut types, vec![int, long], false);
497 assert_eq!(a, b);
498 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
499 assert_ne!(a, make(&mut types, vec![long, int], false));
500 }
501
502 #[test]
503 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
504 let mut interner = Interner::new();
505 let mut types = Types::new();
506 let int = types.int(IntKind::Int);
507 let name = types.typedef(interner.intern("int32_t"), int);
508 let sugar = types.function(FunctionType {
509 ret: name,
510 params: vec![name],
511 variadic: false,
512 prototyped: true,
513 });
514 let plain = types.function(FunctionType {
515 ret: int,
516 params: vec![int],
517 variadic: false,
518 prototyped: true,
519 });
520 assert_ne!(sugar, plain);
521 assert_eq!(types.canonical(sugar), plain);
522 }
523
524 #[test]
525 fn a_record_is_its_declaration_and_not_its_members() {
526 let mut interner = Interner::new();
530 let mut types = Types::new();
531 let tag = interner.intern("point");
532 let first = types.declare_record(RecordKind::Struct, Some(tag));
533 let second = types.declare_record(RecordKind::Struct, Some(tag));
534 assert_ne!(types.record(first), types.record(second));
535 assert_eq!(types.record(first), types.record(first));
536 }
537
538 #[test]
539 fn a_record_has_no_layout_until_it_has_been_completed() {
540 let mut types = Types::new();
541 let id = types.declare_record(RecordKind::Struct, None);
542 let ty = types.record(id);
543 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
544 let long_long = types.int(IntKind::LongLong);
545 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
546 types.complete_record(id, laid_out);
547 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
548 }
549
550 #[test]
551 fn an_enum_takes_the_layout_of_its_underlying_type() {
552 let mut types = Types::new();
553 let id = types.declare_enum(None);
554 let ty = types.enumeration(id);
555 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
556 let int = types.int(IntKind::Int);
557 types.complete_enum(id, int, false);
558 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
559 }
560
561 #[test]
562 fn the_scalar_widths_come_from_the_target() {
563 let mut types = Types::new();
564 let linux = linux();
565 let windows = target("x86_64-pc-windows-msvc");
566 let darwin = target("aarch64-apple-darwin");
567
568 let long = types.int(IntKind::Long);
569 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
570 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
571
572 let ldouble = types.float(FloatKind::LongDouble);
573 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
574 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
575
576 let pointer = types.pointer(types.void());
577 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
578
579 let boolean = types.boolean();
580 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
581 }
582
583 #[test]
584 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
585 let mut types = Types::new();
588 let linux = linux();
589 let cfloat = types.complex(FloatKind::Float);
590 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
591 let cdouble = types.complex(FloatKind::Double);
592 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
593 let cldouble = types.complex(FloatKind::LongDouble);
594 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
595 let darwin = target("aarch64-apple-darwin");
596 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
597 }
598
599 #[test]
600 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
601 let mut types = Types::new();
604 let linux = linux();
605 let long_long = types.int(IntKind::LongLong);
606 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
607 let atomic = types.atomic(plain);
608 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
609 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
610
611 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
613 let atomic_odd = types.atomic(odd);
614 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
615
616 let int = types.int(IntKind::Int);
617 let atomic_int = types.atomic(int);
618 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
619 }
620
621 #[test]
622 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
623 let mut types = Types::new();
626 let linux = linux();
627 let darwin = target("aarch64-apple-darwin");
628 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
629 for (width, size, align) in cases {
630 let ty = types.bit_int(true, width);
631 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
632 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
633 }
634 for width in [65, 96, 128] {
635 let ty = types.bit_int(false, width);
636 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
637 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
638 }
639 let wide = types.bit_int(true, 129);
640 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
641 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
642 }
643
644 #[test]
645 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
646 let mut types = Types::new();
647 let linux = linux();
648 let int = types.int(IntKind::Int);
649 let ty = types.array(int, ArrayLen::Fixed(10));
650 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
651 let nested = types.array(ty, ArrayLen::Fixed(3));
652 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
653 }
654
655 #[test]
656 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
657 let mut types = Types::new();
658 let linux = linux();
659 let int = types.int(IntKind::Int);
660 for len in [ArrayLen::Unknown, ArrayLen::Star, ArrayLen::Variable(VlaId(0))] {
661 let ty = types.array(int, len);
662 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
663 }
664 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
665 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
666 }
667
668 #[test]
669 fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
670 let mut types = Types::new();
674 let linux = linux();
675 let max = linux.max_object_size();
676 let ch = types.int(IntKind::Char);
677 let fits = types.array(ch, ArrayLen::Fixed(max));
678 assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
679 let over = types.array(ch, ArrayLen::Fixed(max + 1));
680 assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
681 }
682
683 #[test]
684 fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
685 let mut types = Types::new();
690 let linux = linux();
691 let max = linux.max_object_size();
692 let ch = types.int(IntKind::Char);
693 let int = types.int(IntKind::Int);
694 let short = types.int(IntKind::Short);
695
696 let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
697 let members = [member(huge), member(int), member(int), member(int), member(int)];
698 let laid_out = lay_out(&types, RecordKind::Struct, &members);
699 assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
700
701 let brim = types.array(ch, ArrayLen::Fixed(max));
702 let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
703 assert_eq!(laid_out.layout, Layout::new(max, 1));
704
705 let over = [member(brim), member(ch)];
706 let options = RecordOptions::default();
707 let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
708 assert_eq!(error, Err(RecordError::TooLarge));
709 }
710
711 #[test]
712 fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
713 let mut types = Types::new();
718 let linux = linux();
719 let ch = types.int(IntKind::Char);
720 let int = types.int(IntKind::Int);
721 let mut interner = Interner::new();
722 let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
723 let members = [member(buf), bits(&mut interner, "x", int, 1)];
724 let laid_out = lay_out(&types, RecordKind::Struct, &members);
725 assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
726 let last = laid_out.fields[1];
727 assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
728 assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
729 }
730
731 #[test]
732 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
733 let mut types = Types::new();
734 let int = types.int(IntKind::Int);
735 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
736 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
737 assert_ne!(a, b);
738 }
739
740 #[test]
741 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
742 let mut types = Types::new();
745 let linux = linux();
746 let int = types.int(IntKind::Int);
747 let four = types.vector(int, 4);
748 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
749 let three = types.vector(int, 3);
750 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
751 let three_chars = types.vector(types.int(IntKind::Char), 3);
752 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
753 }
754
755 #[test]
756 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
757 let mut types = Types::new();
760 let linux = linux();
761 let void = types.void();
762 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
763 let int = types.int(IntKind::Int);
764 let function = types.function(FunctionType {
765 ret: int,
766 params: Vec::new(),
767 variadic: false,
768 prototyped: true,
769 });
770 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
771 let pointer_to_function = types.pointer(function);
772 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
773 }
774
775 #[test]
776 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
777 let types = Types::new();
778 let char_ = types.int(IntKind::Char);
779 let int = types.int(IntKind::Int);
780 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
781 assert_eq!(laid_out.layout, Layout::new(8, 4));
782 assert_eq!(offsets(&laid_out), [0, 32]);
783 assert_eq!(laid_out.fields[1].offset, 4);
784
785 let long_long = types.int(IntKind::LongLong);
787 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
788 assert_eq!(laid_out.layout, Layout::new(16, 8));
789 }
790
791 #[test]
792 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
793 let mut types = Types::new();
794 let char_ = types.int(IntKind::Char);
795 let int = types.int(IntKind::Int);
796 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
797 assert_eq!(laid_out.layout, Layout::new(4, 4));
798 assert_eq!(offsets(&laid_out), [0, 0]);
799
800 let nine = types.array(char_, ArrayLen::Fixed(9));
803 let short = types.int(IntKind::Short);
804 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
805 assert_eq!(laid_out.layout, Layout::new(10, 2));
806 }
807
808 #[test]
809 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
810 let mut interner = Interner::new();
813 let types = Types::new();
814 let char_ = types.int(IntKind::Char);
815 let int = types.int(IntKind::Int);
816 let long_long = types.int(IntKind::LongLong);
817
818 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
819 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
820 assert_eq!(laid_out.layout, Layout::new(4, 4));
821 assert_eq!(offsets(&laid_out), [0, 3]);
822
823 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
825 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
826 assert_eq!(laid_out.layout, Layout::new(8, 4));
827 assert_eq!(offsets(&laid_out), [0, 32]);
828
829 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
832 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
833 assert_eq!(laid_out.layout, Layout::new(8, 8));
834 assert_eq!(offsets(&laid_out), [0, 8]);
835
836 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
838 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
839 assert_eq!(offsets(&laid_out), [0, 8]);
840 }
841
842 #[test]
843 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
844 let types = Types::new();
845 let char_ = types.int(IntKind::Char);
846 let int = types.int(IntKind::Int);
847 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
848 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
849 assert_eq!(laid_out.layout, Layout::new(5, 1));
852 assert_eq!(offsets(&laid_out), [0, 32, 32]);
853 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
854 }
855
856 #[test]
857 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
858 let mut interner = Interner::new();
859 let types = Types::new();
860 let char_ = types.int(IntKind::Char);
861 let int = types.int(IntKind::Int);
862
863 let unnamed = [member(char_), unnamed_bits(int, 20)];
864 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
865 assert_eq!(unnamed.layout, Layout::new(4, 1));
866
867 let named = [member(char_), bits(&mut interner, "b", int, 20)];
868 let named = lay_out(&types, RecordKind::Struct, &named);
869 assert_eq!(named.layout, Layout::new(4, 4));
870 assert_eq!(offsets(&named), [0, 8], "the same place either way");
871
872 let wider = [member(char_), unnamed_bits(int, 30)];
875 let wider = lay_out(&types, RecordKind::Struct, &wider);
876 assert_eq!(wider.layout, Layout::new(8, 1));
877 assert_eq!(offsets(&wider), [0, 32]);
878 }
879
880 #[test]
881 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
882 let mut interner = Interner::new();
883 let types = Types::new();
884 let char_ = types.int(IntKind::Char);
885 let int = types.int(IntKind::Int);
886 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
887
888 let fields = [member(char_), member(int)];
889 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
890 .expect("a packed struct of two complete members");
891 assert_eq!(laid_out.layout, Layout::new(5, 1));
892 assert_eq!(offsets(&laid_out), [0, 8]);
893
894 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
895 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
896 .expect("a packed struct with a bit-field");
897 assert_eq!(laid_out.layout, Layout::new(5, 1));
898 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
899
900 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
903 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
904 .expect("a packed struct with a zero width bit-field");
905 assert_eq!(laid_out.layout, Layout::new(5, 1));
906 assert_eq!(offsets(&laid_out), [0, 32, 32]);
907 }
908
909 #[test]
910 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
911 let mut interner = Interner::new();
912 let types = Types::new();
913 let char_ = types.int(IntKind::Char);
914 let int = types.int(IntKind::Int);
915 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
916
917 let fields = [member(char_), member(int)];
918 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
919 .expect("a packed struct of two complete members");
920 assert_eq!(laid_out.layout, Layout::new(6, 2));
921 assert_eq!(offsets(&laid_out), [0, 16]);
922
923 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
927 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
928 .expect("a packed struct with a bit-field");
929 assert_eq!(laid_out.layout, Layout::new(6, 2));
930 assert_eq!(offsets(&laid_out), [0, 8]);
931
932 let fields = [member(char_), unnamed_bits(int, 30)];
935 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
936 .expect("a packed struct with an unnamed bit-field");
937 assert_eq!(laid_out.layout, Layout::new(5, 1));
938 }
939
940 #[test]
941 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
942 let types = Types::new();
943 let char_ = types.int(IntKind::Char);
944 let int = types.int(IntKind::Int);
945
946 let aligned = FieldDecl { align: Some(16), ..member(int) };
947 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
948 assert_eq!(laid_out.layout, Layout::new(32, 16));
949 assert_eq!(offsets(&laid_out), [0, 128]);
950
951 let options = RecordOptions { packed: true, align: Some(4), pack: None };
954 let fields = [member(char_), member(int)];
955 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
956 .expect("a packed struct with an alignment asked for");
957 assert_eq!(laid_out.layout, Layout::new(8, 4));
958 assert_eq!(offsets(&laid_out), [0, 8]);
959 }
960
961 #[test]
962 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
963 let mut types = Types::new();
965 let char_ = types.int(IntKind::Char);
966 let int = types.int(IntKind::Int);
967 let long_long = types.int(IntKind::LongLong);
968
969 let chars = types.array(char_, ArrayLen::Unknown);
970 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
971 assert_eq!(laid_out.layout, Layout::new(4, 4));
972 assert_eq!(offsets(&laid_out), [0, 32]);
973
974 let longs = types.array(long_long, ArrayLen::Unknown);
976 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
977 assert_eq!(laid_out.layout, Layout::new(8, 8));
978 assert_eq!(offsets(&laid_out), [0, 64]);
979
980 let fields = [member(chars), member(int)];
982 let error =
983 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
984 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
985 }
986
987 #[test]
988 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
989 let types = Types::new();
991 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
992 assert_eq!(laid_out.layout, Layout::new(0, 1));
993 }
994
995 #[test]
996 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
997 let types = Types::new();
998 let int = types.int(IntKind::Int);
999 let fields = [unnamed_bits(int, 33)];
1000 let error =
1001 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1002 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1003 assert_eq!(error, Err(want));
1004 }
1005
1006 #[test]
1007 fn a_record_reports_its_members_once_it_has_been_completed() {
1008 let mut interner = Interner::new();
1009 let mut types = Types::new();
1010 let char_ = types.int(IntKind::Char);
1011 let int = types.int(IntKind::Int);
1012 let name = interner.intern("count");
1013 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1014 let id = types.declare_record(RecordKind::Struct, None);
1015 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1016 types.complete_record(id, laid_out);
1017 let ty = types.record(id);
1018 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1019 let field = types.field(id, name).expect("the member that was declared");
1020 assert_eq!(field.offset, 4);
1021 assert!(!field.is_bit_field());
1022 assert_eq!(types.field(id, interner.intern("missing")), None);
1023 }
1024
1025 #[test]
1026 fn a_nested_record_brings_its_own_alignment_with_it() {
1027 let mut types = Types::new();
1028 let char_ = types.int(IntKind::Char);
1029 let int = types.int(IntKind::Int);
1030 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1031 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1032 assert_eq!(laid_out.layout, Layout::new(8, 4));
1033 assert_eq!(offsets(&laid_out), [0, 32]);
1034
1035 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1038 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1039 assert_eq!(laid_out.layout, Layout::new(12, 4));
1040 assert_eq!(offsets(&laid_out), [0, 32]);
1041 }
1042
1043 #[test]
1044 fn everything_narrower_than_an_int_promotes_to_one() {
1045 let mut types = Types::new();
1049 let linux = linux();
1050 let int = types.int(IntKind::Int);
1051 let narrow =
1052 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1053 for kind in narrow {
1054 let ty = types.int(kind);
1055 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1056 }
1057 let boolean = types.boolean();
1058 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1059
1060 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1062 let ty = types.int(kind);
1063 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1064 }
1065 }
1066
1067 #[test]
1068 fn a_bit_int_is_not_promoted_at_all() {
1069 let mut types = Types::new();
1072 let linux = linux();
1073 let small = types.bit_int(true, 8);
1074 assert_eq!(promote(&mut types, small, &linux), small);
1075 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1076 }
1077
1078 #[test]
1079 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1080 let mut types = Types::new();
1081 let linux = linux();
1082 let int = types.int(IntKind::Int);
1083 let uint = types.int(IntKind::UInt);
1084 let ullong = types.int(IntKind::ULongLong);
1085
1086 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1088 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1090 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1092 let forty = types.bit_int(false, 40);
1097 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1098 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1100 }
1101
1102 #[test]
1103 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1104 let mut types = Types::new();
1105 let linux = linux();
1106 let int = types.int(IntKind::Int);
1107 let short = types.int(IntKind::Short);
1108 let uint = types.int(IntKind::UInt);
1109
1110 let fixed = types.declare_enum(None);
1112 types.complete_enum(fixed, short, true);
1113 let fixed = types.enumeration(fixed);
1114 assert_eq!(promote(&mut types, fixed, &linux), int);
1115
1116 let unsigned = types.declare_enum(None);
1119 types.complete_enum(unsigned, uint, false);
1120 let unsigned = types.enumeration(unsigned);
1121 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1122
1123 let undecided = types.declare_enum(None);
1126 let undecided = types.enumeration(undecided);
1127 assert_eq!(promote(&mut types, undecided, &linux), int);
1128 }
1129
1130 #[test]
1131 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1132 let mut types = Types::new();
1135 let linux = linux();
1136 let int = types.int(IntKind::Int);
1137 let konst = types.qualified(int, Qualifiers::CONST);
1138 let atomic = types.atomic(konst);
1139 assert_eq!(promote(&mut types, atomic, &linux), int);
1140 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1141 }
1142
1143 #[test]
1144 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1145 let mut types = Types::new();
1147 let linux = linux();
1148 let cases = [
1149 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1150 (IntKind::Int, IntKind::Long, IntKind::Long),
1151 (IntKind::UInt, IntKind::Long, IntKind::Long),
1152 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1153 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1154 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1155 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1156 (IntKind::Char, IntKind::Char, IntKind::Int),
1157 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1158 ];
1159 for (left, right, want) in cases {
1160 let left = types.int(left);
1161 let right = types.int(right);
1162 let want = types.int(want);
1163 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1164 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1165 }
1166 }
1167
1168 #[test]
1169 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1170 let mut types = Types::new();
1174 let linux = linux();
1175 let signed = types.int(IntKind::Int128);
1176 let unsigned = types.int(IntKind::UInt128);
1177 for id in [signed, unsigned] {
1178 let laid_out = layout(&types, id, &linux).expect("a complete type");
1179 assert_eq!(laid_out.size, 16);
1180 assert_eq!(laid_out.align, 16);
1181 }
1182
1183 let ull = types.int(IntKind::ULongLong);
1187 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1188 assert_eq!(promote(&mut types, signed, &linux), signed);
1190 }
1191
1192 #[test]
1193 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1194 let mut types = Types::new();
1197 let linux = linux();
1198 let int128 = types.int(IntKind::Int128);
1199 let bit_int = types.bit_int(true, 128);
1200 assert_ne!(int128, bit_int);
1201 assert!(!compatible(&types, int128, bit_int));
1202 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1203 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1204 }
1205
1206 #[test]
1207 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1208 let mut types = Types::new();
1212 let linux = linux();
1213 let ulong = types.int(IntKind::ULong);
1214 let long_long = types.int(IntKind::LongLong);
1215 let want = types.int(IntKind::ULongLong);
1216 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1217
1218 let windows = target("x86_64-pc-windows-msvc");
1222 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1223 }
1224
1225 #[test]
1226 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1227 let mut types = Types::new();
1229 let linux = linux();
1230 let b40 = types.bit_int(true, 40);
1231 let ub40 = types.bit_int(false, 40);
1232 let b8 = types.bit_int(true, 8);
1233 let b32 = types.bit_int(true, 32);
1234 let int = types.int(IntKind::Int);
1235 let uint = types.int(IntKind::UInt);
1236 let long = types.int(IntKind::Long);
1237 let char_ = types.int(IntKind::Char);
1238
1239 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1241 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1243 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1245 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1246 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1249 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1252 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1253 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1255 }
1256
1257 #[test]
1258 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1259 let mut types = Types::new();
1260 let linux = linux();
1261 let float = types.float(FloatKind::Float);
1262 let double = types.float(FloatKind::Double);
1263 let long_double = types.float(FloatKind::LongDouble);
1264 let ullong = types.int(IntKind::ULongLong);
1265 let int = types.int(IntKind::Int);
1266
1267 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1268 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1269 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1270 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1273 }
1274
1275 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1280 let mut types = Types::new();
1281 let left = types.float(a);
1282 let right = types.float(b);
1283 let want = types.float(expected);
1284 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1285 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1286 }
1287
1288 #[test]
1289 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1290 let x86 = linux();
1294 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1295 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1296 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1297 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1298 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1299 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1300 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1301 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1302 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1303 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1304 }
1305
1306 #[test]
1307 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1308 let mac = target("aarch64-apple-darwin");
1312 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1313 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1314 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1315 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1316 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1317 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1318 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1319 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1322 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1323 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1324 }
1325
1326 #[test]
1327 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1328 let mut types = Types::new();
1329 let linux = linux();
1330 let cfloat = types.complex(FloatKind::Float);
1331 let cdouble = types.complex(FloatKind::Double);
1332 let cldouble = types.complex(FloatKind::LongDouble);
1333 let double = types.float(FloatKind::Double);
1334 let long_double = types.float(FloatKind::LongDouble);
1335 let float = types.float(FloatKind::Float);
1336 let int = types.int(IntKind::Int);
1337
1338 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1339 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1340 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1341 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1342 }
1343
1344 #[test]
1345 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1346 let mut types = Types::new();
1348 let linux = linux();
1349 let int = types.int(IntKind::Int);
1350 let pointer = types.pointer(int);
1351 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1352 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1353 let void = types.void();
1354 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1355 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1358 }
1359
1360 #[test]
1361 fn the_conversions_read_through_sugar() {
1362 let mut interner = Interner::new();
1363 let mut types = Types::new();
1364 let linux = linux();
1365 let char_ = types.int(IntKind::Char);
1366 let name = types.typedef(interner.intern("byte"), char_);
1367 let int = types.int(IntKind::Int);
1368 assert_eq!(promote(&mut types, name, &linux), int);
1369 }
1370
1371 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1373 let ret = types.void();
1374 types.function(FunctionType { ret, params, variadic, prototyped: true })
1375 }
1376
1377 fn old_style(types: &mut Types) -> TypeId {
1379 let ret = types.void();
1380 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1381 }
1382
1383 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1385 let id = types.declare_record(RecordKind::Struct, Some(tag));
1386 let laid_out = lay_out(types, RecordKind::Struct, fields);
1387 types.complete_record(id, laid_out);
1388 id
1389 }
1390
1391 #[test]
1392 fn a_type_is_compatible_with_itself_however_it_was_written() {
1393 let mut interner = Interner::new();
1394 let mut types = Types::new();
1395 let int = types.int(IntKind::Int);
1396 let name = types.typedef(interner.intern("int32_t"), int);
1397 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1398 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1399
1400 let konst = types.qualified(int, Qualifiers::CONST);
1403 assert!(!compatible(&types, konst, int));
1404 let konst_pointer = types.pointer(konst);
1405 let pointer = types.pointer(int);
1406 assert!(!compatible(&types, konst_pointer, pointer));
1407 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1408
1409 let char_ = types.int(IntKind::Char);
1412 let schar = types.int(IntKind::SChar);
1413 assert!(!compatible(&types, char_, schar));
1414 let atomic = types.atomic(int);
1416 assert!(!compatible(&types, atomic, int));
1417 }
1418
1419 #[test]
1420 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1421 let mut types = Types::new();
1424 let uint = types.int(IntKind::UInt);
1425 let int = types.int(IntKind::Int);
1426 let id = types.declare_enum(None);
1427 types.complete_enum(id, uint, false);
1428 let e = types.enumeration(id);
1429 assert!(compatible(&types, e, uint));
1430 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1431 assert!(!compatible(&types, e, int));
1432
1433 let other = types.declare_enum(None);
1436 types.complete_enum(other, uint, false);
1437 let other = types.enumeration(other);
1438 assert!(!compatible(&types, e, other));
1439
1440 let undecided = types.declare_enum(None);
1443 let undecided = types.enumeration(undecided);
1444 assert!(!compatible(&types, undecided, uint));
1445 assert!(compatible(&types, undecided, undecided));
1446 }
1447
1448 #[test]
1449 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1450 let mut types = Types::new();
1453 let int = types.int(IntKind::Int);
1454 let unknown = types.array(int, ArrayLen::Unknown);
1455 let four = types.array(int, ArrayLen::Fixed(4));
1456 let five = types.array(int, ArrayLen::Fixed(5));
1457 assert!(compatible(&types, unknown, four));
1458 assert!(!compatible(&types, four, five));
1459 assert_eq!(composite(&mut types, unknown, four), Some(four));
1460 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1461 assert_eq!(composite(&mut types, four, five), None);
1462
1463 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1466 assert!(compatible(&types, vla, four));
1467 assert_eq!(composite(&mut types, vla, four), Some(four));
1468
1469 let long = types.int(IntKind::Long);
1471 let longs = types.array(long, ArrayLen::Fixed(4));
1472 assert!(!compatible(&types, four, longs));
1473 }
1474
1475 #[test]
1476 fn a_parameter_declared_as_an_array_is_a_pointer() {
1477 let mut types = Types::new();
1481 let int = types.int(IntKind::Int);
1482 let three = types.array(int, ArrayLen::Fixed(3));
1483 let pointer = types.pointer(int);
1484 assert_eq!(adjust_parameter(&mut types, three), pointer);
1485
1486 let function = prototype(&mut types, vec![int], false);
1488 let function_pointer = types.pointer(function);
1489 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1490
1491 let konst = types.qualified(int, Qualifiers::CONST);
1494 assert_eq!(adjust_parameter(&mut types, konst), int);
1495 let to_konst = types.pointer(konst);
1496 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1497 }
1498
1499 #[test]
1500 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1501 let mut types = Types::new();
1505 let old = old_style(&mut types);
1506 let int = types.int(IntKind::Int);
1507 let long = types.int(IntKind::Long);
1508 let char_ = types.int(IntKind::Char);
1509 let float = types.float(FloatKind::Float);
1510 let double = types.float(FloatKind::Double);
1511
1512 let takes_int = prototype(&mut types, vec![int], false);
1513 assert!(compatible(&types, old, takes_int));
1514 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1515 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1517
1518 let pointer = types.pointer(int);
1519 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1520 let ty = prototype(&mut types, params, false);
1521 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1522 }
1523
1524 for params in [vec![char_], vec![float], vec![int, char_]] {
1527 let ty = prototype(&mut types, params, false);
1528 assert!(!compatible(&types, old, ty));
1529 assert_eq!(composite(&mut types, old, ty), None);
1530 }
1531
1532 let variadic = prototype(&mut types, vec![int], true);
1534 assert!(!compatible(&types, old, variadic));
1535
1536 let uint = types.int(IntKind::UInt);
1538 let id = types.declare_enum(None);
1539 types.complete_enum(id, uint, false);
1540 let e = types.enumeration(id);
1541 let takes_enum = prototype(&mut types, vec![e], false);
1542 assert!(compatible(&types, old, takes_enum));
1543
1544 assert!(compatible(&types, old, old));
1546
1547 let returns_int = types.function(FunctionType {
1549 ret: int,
1550 params: Vec::new(),
1551 variadic: false,
1552 prototyped: false,
1553 });
1554 assert!(!compatible(&types, returns_int, takes_int));
1555 }
1556
1557 #[test]
1558 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1559 let mut types = Types::new();
1563 let int = types.int(IntKind::Int);
1564 let takes_int = prototype(&mut types, vec![int], false);
1565 let takes_nothing = prototype(&mut types, Vec::new(), false);
1566 let old = old_style(&mut types);
1567 assert!(!compatible(&types, takes_nothing, takes_int));
1568 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1569 }
1570
1571 #[test]
1572 fn two_prototypes_have_to_agree_about_everything() {
1573 let mut types = Types::new();
1574 let int = types.int(IntKind::Int);
1575 let long = types.int(IntKind::Long);
1576 let base = prototype(&mut types, vec![int, int], false);
1577 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1578 let other = prototype(&mut types, other, false);
1579 assert!(!compatible(&types, base, other));
1580 }
1581 let variadic = prototype(&mut types, vec![int, int], true);
1582 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1583
1584 let four = types.array(int, ArrayLen::Fixed(4));
1587 let unknown = types.array(int, ArrayLen::Unknown);
1588 let to_four = types.pointer(four);
1589 let to_unknown = types.pointer(unknown);
1590 let a = prototype(&mut types, vec![to_four], false);
1591 let b = prototype(&mut types, vec![to_unknown], false);
1592 assert!(compatible(&types, a, b));
1593 assert_eq!(composite(&mut types, a, b), Some(a));
1595 }
1596
1597 #[test]
1598 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1599 let mut types = Types::new();
1600 let int = types.int(IntKind::Int);
1601 let four = types.array(int, ArrayLen::Fixed(4));
1602 let unknown = types.array(int, ArrayLen::Unknown);
1603 let to_four = types.pointer(four);
1604 let to_unknown = types.pointer(unknown);
1605 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1606
1607 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1609 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1610 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1611 }
1612
1613 #[test]
1614 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1615 let mut interner = Interner::new();
1619 let mut types = Types::new();
1620 let tag = interner.intern("point");
1621 let x = interner.intern("x");
1622 let y = interner.intern("y");
1623 let int = types.int(IntKind::Int);
1624 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1625
1626 let first = tagged(&mut types, tag, &members);
1627 let second = tagged(&mut types, tag, &members);
1628 let first = types.record(first);
1629 let second = types.record(second);
1630 assert_ne!(first, second, "still two declarations and two types");
1631 assert!(compatible(&types, first, second));
1632
1633 let z = interner.intern("z");
1636 let long = types.int(IntKind::Long);
1637 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1638 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1639 for other in [&renamed[..], &retyped[..], &members[..1]] {
1640 let other = tagged(&mut types, tag, other);
1641 let other = types.record(other);
1642 assert!(!compatible(&types, first, other));
1643 }
1644 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1645 let elsewhere = types.record(elsewhere);
1646 assert!(!compatible(&types, first, elsewhere));
1647
1648 let anonymous = record(&mut types, RecordKind::Struct, &members);
1651 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1652 assert!(!compatible(&types, anonymous, also_anonymous));
1653
1654 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1656 let incomplete = types.record(incomplete);
1657 assert!(!compatible(&types, first, incomplete));
1658 assert!(compatible(&types, incomplete, incomplete));
1659 }
1660
1661 #[test]
1662 fn a_self_referential_record_is_compared_without_going_round_forever() {
1663 let mut interner = Interner::new();
1667 let mut types = Types::new();
1668 let tag = interner.intern("node");
1669 let value = interner.intern("value");
1670 let next = interner.intern("next");
1671 let int = types.int(IntKind::Int);
1672
1673 let node = |types: &mut Types| {
1674 let id = types.declare_record(RecordKind::Struct, Some(tag));
1675 let ty = types.record(id);
1676 let pointer = types.pointer(ty);
1677 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1678 let laid_out = lay_out(types, RecordKind::Struct, &members);
1679 types.complete_record(id, laid_out);
1680 ty
1681 };
1682 let first = node(&mut types);
1683 let second = node(&mut types);
1684 assert_ne!(first, second);
1685 assert!(compatible(&types, first, second));
1686
1687 let id = types.declare_record(RecordKind::Struct, Some(tag));
1690 let ty = types.record(id);
1691 let pointer = types.pointer(ty);
1692 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1693 let laid_out = lay_out(&types, RecordKind::Struct, &members);
1694 types.complete_record(id, laid_out);
1695 assert!(!compatible(&types, first, ty));
1696 }
1697
1698 #[test]
1699 fn layout_reads_through_sugar() {
1700 let mut interner = Interner::new();
1701 let mut types = Types::new();
1702 let long = types.int(IntKind::Long);
1703 let name = types.typedef(interner.intern("word"), long);
1704 let array = types.array(name, ArrayLen::Fixed(4));
1705 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1706 }
1707}