1#![doc(html_root_url = "https://docs.rs/rucc-types/0.6.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, lanes, pointee,
96};
97pub use crate::compat::{adjust_parameter, compatible, composite};
98pub use crate::convert::{
99 mask_of, promote, promote_bit_field, usual_arithmetic, vectors_convertible,
100};
101pub use crate::kind::{
102 ArrayLen, EnumId, FloatKind, FunctionId, FunctionType, IntKind, Qualifiers, RecordId,
103 RecordKind, Type, TypeKind, VlaId,
104};
105pub use crate::layout::{
106 IntegerInfo, Layout, LayoutError, float_format, float_width, int_width, integer_info, layout,
107};
108pub use crate::print::{declare, spell};
109pub use crate::record::{
110 Field, FieldDecl, RecordError, RecordLayout, RecordOptions, layout_record,
111};
112pub use crate::types::{EnumInfo, RecordInfo, TypeId, Types};
113
114pub const MILESTONE: &str = "M2";
116
117#[cfg(test)]
118mod tests {
119 use std::num::NonZeroU32;
120
121 use rucc_base::{Interner, Symbol};
122 use rucc_target::{TargetInfo, Triple};
123
124 use super::*;
125
126 fn target(triple: &str) -> TargetInfo {
127 TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
128 }
129
130 fn linux() -> TargetInfo {
131 target("x86_64-unknown-linux-gnu")
132 }
133
134 fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
136 layout_record(types, kind, fields, &RecordOptions::default(), &linux())
137 .expect("a record every member of which has a layout")
138 }
139
140 fn offsets(laid_out: &RecordLayout) -> Vec<u128> {
143 laid_out.fields.iter().map(Field::bit_offset).collect()
144 }
145
146 fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
148 let id = types.declare_record(kind, None);
149 let laid_out = lay_out(types, kind, fields);
150 types.complete_record(id, laid_out);
151 types.record(id)
152 }
153
154 fn member(ty: TypeId) -> FieldDecl {
156 FieldDecl::new(None, ty)
157 }
158
159 fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
162 FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
163 }
164
165 fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
167 FieldDecl::bit_field(None, ty, width)
168 }
169
170 #[test]
171 fn milestone_is_recorded() {
172 assert!(MILESTONE.starts_with('M'));
173 }
174
175 #[test]
176 fn an_integer_type_answers_with_the_width_of_its_value_and_not_of_its_object() {
177 let mut interner = Interner::new();
178 let mut types = Types::new();
179 let target = linux();
180
181 let boolean = types.boolean();
184 let bits = types.bit_int(true, 37);
185 let short = types.int(IntKind::Short);
187 let alias = types.typedef(interner.intern("word"), short);
188 let unsigned_char = types.int(IntKind::UChar);
189 let atomic = types.atomic(unsigned_char);
190
191 let shape = |ty| integer_info(&types, ty, &target).expect("an integer type");
192 assert_eq!(shape(boolean), IntegerInfo::new(false, 1));
193 assert_eq!(shape(bits), IntegerInfo::new(true, 37));
194 assert_eq!(shape(types.int(IntKind::Int)), IntegerInfo::new(true, 32));
195 assert_eq!(shape(types.int(IntKind::ULong)), IntegerInfo::new(false, 64));
196 assert_eq!(shape(alias), IntegerInfo::new(true, 16));
197 assert_eq!(shape(atomic), IntegerInfo::new(false, 8));
198
199 assert_eq!(integer_info(&types, types.float(FloatKind::Double), &target), None);
200 }
201
202 #[test]
203 fn an_enumeration_answers_with_the_type_the_enumerators_are_kept_in() {
204 let mut interner = Interner::new();
205 let mut types = Types::new();
206 let target = linux();
207
208 let colour = types.declare_enum(Some(interner.intern("colour")));
211 let ty = types.enumeration(colour);
212 assert_eq!(integer_info(&types, ty, &target), None);
213
214 let underlying = types.int(IntKind::ULong);
215 types.complete_enum(colour, underlying, true);
216 assert_eq!(integer_info(&types, ty, &target), Some(IntegerInfo::new(false, 64)));
217 }
218
219 #[test]
220 fn a_value_stored_in_an_integer_type_keeps_the_bits_the_type_has_room_for() {
221 let char_type = IntegerInfo::new(true, 8);
222 assert_eq!(char_type.wrap(300), 44);
223 assert!(!char_type.holds(300));
224 assert!(char_type.holds(-128));
225
226 assert_eq!(IntegerInfo::new(false, 32).wrap(-1), 4_294_967_295);
227 assert_eq!(IntegerInfo::new(false, 8).wrap(-1), 255);
228
229 assert!(IntegerInfo::new(false, 128).holds(i128::MIN));
232 assert!(IntegerInfo::new(true, 128).holds(i128::MIN));
233 assert_eq!(IntegerInfo::new(true, 128).wrap(i128::MAX), i128::MAX);
234 }
235
236 #[test]
237 fn a_long_double_has_a_format_the_size_does_not_give_away() {
238 let target = linux();
239 assert_eq!(float_width(FloatKind::LongDouble, &target), 128);
242 assert_eq!(
243 float_format(FloatKind::LongDouble, &target),
244 rucc_base::float::Format::X87Extended
245 );
246 assert_eq!(float_format(FloatKind::Float, &target), rucc_base::float::Format::Single);
247 }
248
249 #[test]
250 fn an_interchange_type_names_a_format_and_an_extended_one_names_the_target() {
251 use rucc_base::float::Format;
252
253 for target in [&linux(), &target("aarch64-apple-darwin")] {
256 assert_eq!(float_format(FloatKind::Float16, target), Format::Half);
257 assert_eq!(float_format(FloatKind::Float32, target), Format::Single);
258 assert_eq!(float_format(FloatKind::Float64, target), Format::Double);
259 assert_eq!(float_format(FloatKind::Float128, target), Format::Quad);
260 assert_eq!(float_width(FloatKind::Float16, target), 16);
261 assert_eq!(float_width(FloatKind::Float32, target), 32);
262 assert_eq!(float_width(FloatKind::Float64, target), 64);
263 assert_eq!(float_width(FloatKind::Float128, target), 128);
264 assert_eq!(float_format(FloatKind::Float32x, target), Format::Double);
266 }
267
268 let x86 = linux();
272 assert_eq!(float_format(FloatKind::Float64x, &x86), Format::X87Extended);
273 assert_eq!(float_format(FloatKind::LongDouble, &x86), Format::X87Extended);
274 let mac = target("aarch64-apple-darwin");
275 assert_eq!(float_format(FloatKind::Float64x, &mac), Format::Quad);
276 assert_eq!(float_format(FloatKind::LongDouble, &mac), Format::Double);
277 assert_eq!(float_width(FloatKind::Float64x, &x86), 128);
280 assert_eq!(float_width(FloatKind::Float64x, &mac), 128);
281 }
282
283 #[test]
284 fn every_floating_type_is_as_wide_as_the_format_it_is_stored_in() {
285 let types = Types::new();
286 let sizes = |target: &TargetInfo| -> Vec<(u64, u64)> {
287 FloatKind::ALL
288 .iter()
289 .map(|&kind| {
290 let found = layout(&types, types.float(kind), target).expect("a complete type");
291 (found.size, found.align)
292 })
293 .collect()
294 };
295 assert_eq!(
299 sizes(&linux()),
300 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16), (16, 16)]
301 );
302 assert_eq!(
303 sizes(&target("aarch64-apple-darwin")),
304 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16)]
305 );
306 }
307
308 #[test]
309 fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
310 let types = Types::new();
313 let mut seen = Vec::new();
314 for kind in FloatKind::ALL {
315 seen.push(types.float(kind));
316 }
317 let mut sorted = seen.clone();
318 sorted.sort_unstable();
319 sorted.dedup();
320 assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
321
322 let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
323 assert_eq!(
324 names,
325 [
326 "_Float16",
327 "float",
328 "_Float32",
329 "double",
330 "_Float32x",
331 "_Float64",
332 "long double",
333 "_Float64x",
334 "_Float128",
335 ]
336 );
337 }
338
339 #[test]
340 fn the_same_type_asked_for_twice_is_the_same_id() {
341 let mut types = Types::new();
342 let a = types.pointer(types.int(IntKind::Int));
343 let b = types.pointer(types.int(IntKind::Int));
344 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
345 let c = types.pointer(types.int(IntKind::Long));
346 assert_ne!(a, c);
347 }
348
349 #[test]
350 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
351 let mut types = Types::new();
352 let int = types.int(IntKind::Int);
353 let konst = types.qualified(int, Qualifiers::CONST);
354 assert_ne!(int, konst);
355 assert_eq!(types.kind(konst), types.kind(int));
356 assert!(types.quals(konst).has(Qualifiers::CONST));
357 assert_eq!(types.unqualified(konst), int);
358 }
359
360 #[test]
361 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
362 let mut types = Types::new();
363 let int = types.int(IntKind::Int);
364 let a = types.qualified(int, Qualifiers::CONST);
365 let a = types.qualified(a, Qualifiers::VOLATILE);
366 let b = types.qualified(int, Qualifiers::VOLATILE);
367 let b = types.qualified(b, Qualifiers::CONST);
368 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
369 }
370
371 #[test]
372 fn qualifying_an_array_qualifies_its_element() {
373 let mut types = Types::new();
376 let int = types.int(IntKind::Int);
377 let array = types.array(int, ArrayLen::Fixed(4));
378 let konst = types.qualified(array, Qualifiers::CONST);
379 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
380 let TypeKind::Array { elem, len } = types.kind(konst) else {
381 panic!("still an array");
382 };
383 assert_eq!(len, ArrayLen::Fixed(4));
384 assert!(types.quals(elem).has(Qualifiers::CONST));
385 }
386
387 #[test]
388 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
389 let mut interner = Interner::new();
390 let mut types = Types::new();
391 let int = types.int(IntKind::Int);
392 let name = types.typedef(interner.intern("int32_t"), int);
393 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
394 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
395 assert!(types.is_sugar(name));
396 assert!(!types.is_sugar(int));
397 }
398
399 #[test]
400 fn sugar_below_the_outermost_node_is_resolved_too() {
401 let mut interner = Interner::new();
404 let mut types = Types::new();
405 let int = types.int(IntKind::Int);
406 let name = types.typedef(interner.intern("int32_t"), int);
407 let sugar_pointer = types.pointer(name);
408 let plain_pointer = types.pointer(int);
409 assert_ne!(sugar_pointer, plain_pointer);
410 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
411
412 let sugar_array = types.array(name, ArrayLen::Fixed(3));
413 let plain_array = types.array(int, ArrayLen::Fixed(3));
414 assert_eq!(types.canonical(sugar_array), plain_array);
415 }
416
417 #[test]
418 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
419 let mut interner = Interner::new();
420 let mut types = Types::new();
421 let int = types.int(IntKind::Int);
422 let mut current = int;
423 for i in 0..8 {
424 current = types.typedef(interner.intern(&format!("t{i}")), current);
425 }
426 assert_eq!(types.canonical(current), int);
427 }
428
429 #[test]
430 fn a_typedef_that_asked_for_an_alignment_says_what_it_is_and_not_what_it_is_at_least() {
431 let mut interner = Interner::new();
436 let mut types = Types::new();
437 let target = linux();
438 let int = types.int(IntKind::Int);
439 let low = types.aligned_typedef(interner.intern("L"), int, NonZeroU32::new(2).unwrap());
440 let high = types.aligned_typedef(interner.intern("H"), int, NonZeroU32::new(16).unwrap());
441
442 assert_eq!(layout(&types, low, &target), Ok(Layout::new(4, 2)));
443 assert_eq!(layout(&types, high, &target), Ok(Layout::new(4, 16)));
444 assert_eq!(layout(&types, int, &target), Ok(Layout::new(4, 4)));
447
448 assert_ne!(low, high);
451
452 let outer = types.aligned_typedef(interner.intern("M"), low, NonZeroU32::new(8).unwrap());
455 assert_eq!(types.align_override(outer), NonZeroU32::new(8));
456 let plain = types.typedef(interner.intern("N"), low);
457 assert_eq!(types.align_override(plain), NonZeroU32::new(2));
458 assert_eq!(types.align_override(int), None);
460 }
461
462 #[test]
463 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
464 let mut interner = Interner::new();
465 let mut types = Types::new();
466 let int = types.int(IntKind::Int);
467 let name = types.typedef(interner.intern("int32_t"), int);
468 let konst = types.qualified(name, Qualifiers::CONST);
469 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
470 let want = types.qualified(int, Qualifiers::CONST);
471 assert_eq!(types.canonical(konst), want);
472 }
473
474 #[test]
475 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
476 let mut interner = Interner::new();
479 let mut types = Types::new();
480 let int = types.int(IntKind::Int);
481 let array = types.array(int, ArrayLen::Fixed(4));
482 let name = types.typedef(interner.intern("A"), array);
483 let konst = types.qualified(name, Qualifiers::CONST);
484 let konst_int = types.qualified(int, Qualifiers::CONST);
485 let want = types.array(konst_int, ArrayLen::Fixed(4));
486 assert_eq!(types.canonical(konst), want);
487 }
488
489 #[test]
490 fn a_function_type_is_deduplicated_by_its_signature() {
491 let mut types = Types::new();
492 let int = types.int(IntKind::Int);
493 let long = types.int(IntKind::Long);
494 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
495 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
496 };
497 let a = make(&mut types, vec![int, long], false);
498 let b = make(&mut types, vec![int, long], false);
499 assert_eq!(a, b);
500 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
501 assert_ne!(a, make(&mut types, vec![long, int], false));
502 }
503
504 #[test]
505 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
506 let mut interner = Interner::new();
507 let mut types = Types::new();
508 let int = types.int(IntKind::Int);
509 let name = types.typedef(interner.intern("int32_t"), int);
510 let sugar = types.function(FunctionType {
511 ret: name,
512 params: vec![name],
513 variadic: false,
514 prototyped: true,
515 });
516 let plain = types.function(FunctionType {
517 ret: int,
518 params: vec![int],
519 variadic: false,
520 prototyped: true,
521 });
522 assert_ne!(sugar, plain);
523 assert_eq!(types.canonical(sugar), plain);
524 }
525
526 #[test]
527 fn a_record_is_its_declaration_and_not_its_members() {
528 let mut interner = Interner::new();
532 let mut types = Types::new();
533 let tag = interner.intern("point");
534 let first = types.declare_record(RecordKind::Struct, Some(tag));
535 let second = types.declare_record(RecordKind::Struct, Some(tag));
536 assert_ne!(types.record(first), types.record(second));
537 assert_eq!(types.record(first), types.record(first));
538 }
539
540 #[test]
541 fn a_record_has_no_layout_until_it_has_been_completed() {
542 let mut types = Types::new();
543 let id = types.declare_record(RecordKind::Struct, None);
544 let ty = types.record(id);
545 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
546 let long_long = types.int(IntKind::LongLong);
547 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
548 types.complete_record(id, laid_out);
549 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
550 }
551
552 #[test]
553 fn an_enum_takes_the_layout_of_its_underlying_type() {
554 let mut types = Types::new();
555 let id = types.declare_enum(None);
556 let ty = types.enumeration(id);
557 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
558 let int = types.int(IntKind::Int);
559 types.complete_enum(id, int, false);
560 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
561 }
562
563 #[test]
564 fn the_scalar_widths_come_from_the_target() {
565 let mut types = Types::new();
566 let linux = linux();
567 let windows = target("x86_64-pc-windows-msvc");
568 let darwin = target("aarch64-apple-darwin");
569
570 let long = types.int(IntKind::Long);
571 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
572 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
573
574 let ldouble = types.float(FloatKind::LongDouble);
575 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
576 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
577
578 let pointer = types.pointer(types.void());
579 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
580
581 let boolean = types.boolean();
582 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
583 }
584
585 #[test]
586 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
587 let mut types = Types::new();
590 let linux = linux();
591 let cfloat = types.complex(FloatKind::Float);
592 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
593 let cdouble = types.complex(FloatKind::Double);
594 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
595 let cldouble = types.complex(FloatKind::LongDouble);
596 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
597 let darwin = target("aarch64-apple-darwin");
598 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
599 }
600
601 #[test]
602 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
603 let mut types = Types::new();
606 let linux = linux();
607 let long_long = types.int(IntKind::LongLong);
608 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
609 let atomic = types.atomic(plain);
610 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
611 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
612
613 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
615 let atomic_odd = types.atomic(odd);
616 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
617
618 let int = types.int(IntKind::Int);
619 let atomic_int = types.atomic(int);
620 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
621 }
622
623 #[test]
624 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
625 let mut types = Types::new();
628 let linux = linux();
629 let darwin = target("aarch64-apple-darwin");
630 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
631 for (width, size, align) in cases {
632 let ty = types.bit_int(true, width);
633 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
634 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
635 }
636 for width in [65, 96, 128] {
637 let ty = types.bit_int(false, width);
638 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
639 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
640 }
641 let wide = types.bit_int(true, 129);
642 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
643 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
644 }
645
646 #[test]
647 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
648 let mut types = Types::new();
649 let linux = linux();
650 let int = types.int(IntKind::Int);
651 let ty = types.array(int, ArrayLen::Fixed(10));
652 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
653 let nested = types.array(ty, ArrayLen::Fixed(3));
654 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
655 }
656
657 #[test]
658 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
659 let mut types = Types::new();
660 let linux = linux();
661 let int = types.int(IntKind::Int);
662 for len in [ArrayLen::Unknown, ArrayLen::Star, ArrayLen::Variable(VlaId(0))] {
663 let ty = types.array(int, len);
664 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
665 }
666 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
667 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
668 }
669
670 #[test]
671 fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
672 let mut types = Types::new();
676 let linux = linux();
677 let max = linux.max_object_size();
678 let ch = types.int(IntKind::Char);
679 let fits = types.array(ch, ArrayLen::Fixed(max));
680 assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
681 let over = types.array(ch, ArrayLen::Fixed(max + 1));
682 assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
683 }
684
685 #[test]
686 fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
687 let mut types = Types::new();
692 let linux = linux();
693 let max = linux.max_object_size();
694 let ch = types.int(IntKind::Char);
695 let int = types.int(IntKind::Int);
696 let short = types.int(IntKind::Short);
697
698 let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
699 let members = [member(huge), member(int), member(int), member(int), member(int)];
700 let laid_out = lay_out(&types, RecordKind::Struct, &members);
701 assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
702
703 let brim = types.array(ch, ArrayLen::Fixed(max));
704 let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
705 assert_eq!(laid_out.layout, Layout::new(max, 1));
706
707 let over = [member(brim), member(ch)];
708 let options = RecordOptions::default();
709 let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
710 assert_eq!(error, Err(RecordError::TooLarge));
711 }
712
713 #[test]
714 fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
715 let mut types = Types::new();
720 let linux = linux();
721 let ch = types.int(IntKind::Char);
722 let int = types.int(IntKind::Int);
723 let mut interner = Interner::new();
724 let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
725 let members = [member(buf), bits(&mut interner, "x", int, 1)];
726 let laid_out = lay_out(&types, RecordKind::Struct, &members);
727 assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
728 let last = laid_out.fields[1];
729 assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
730 assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
731 }
732
733 #[test]
734 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
735 let mut types = Types::new();
736 let int = types.int(IntKind::Int);
737 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
738 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
739 assert_ne!(a, b);
740 }
741
742 #[test]
743 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
744 let mut types = Types::new();
747 let linux = linux();
748 let int = types.int(IntKind::Int);
749 let four = types.vector(int, 4);
750 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
751 let three = types.vector(int, 3);
752 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
753 let three_chars = types.vector(types.int(IntKind::Char), 3);
754 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
755 }
756
757 #[test]
758 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
759 let mut types = Types::new();
762 let linux = linux();
763 let void = types.void();
764 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
765 let int = types.int(IntKind::Int);
766 let function = types.function(FunctionType {
767 ret: int,
768 params: Vec::new(),
769 variadic: false,
770 prototyped: true,
771 });
772 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
773 let pointer_to_function = types.pointer(function);
774 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
775 }
776
777 #[test]
778 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
779 let types = Types::new();
780 let char_ = types.int(IntKind::Char);
781 let int = types.int(IntKind::Int);
782 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
783 assert_eq!(laid_out.layout, Layout::new(8, 4));
784 assert_eq!(offsets(&laid_out), [0, 32]);
785 assert_eq!(laid_out.fields[1].offset, 4);
786
787 let long_long = types.int(IntKind::LongLong);
789 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
790 assert_eq!(laid_out.layout, Layout::new(16, 8));
791 }
792
793 #[test]
794 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
795 let mut types = Types::new();
796 let char_ = types.int(IntKind::Char);
797 let int = types.int(IntKind::Int);
798 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
799 assert_eq!(laid_out.layout, Layout::new(4, 4));
800 assert_eq!(offsets(&laid_out), [0, 0]);
801
802 let nine = types.array(char_, ArrayLen::Fixed(9));
805 let short = types.int(IntKind::Short);
806 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
807 assert_eq!(laid_out.layout, Layout::new(10, 2));
808 }
809
810 #[test]
811 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
812 let mut interner = Interner::new();
815 let types = Types::new();
816 let char_ = types.int(IntKind::Char);
817 let int = types.int(IntKind::Int);
818 let long_long = types.int(IntKind::LongLong);
819
820 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
821 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
822 assert_eq!(laid_out.layout, Layout::new(4, 4));
823 assert_eq!(offsets(&laid_out), [0, 3]);
824
825 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
827 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
828 assert_eq!(laid_out.layout, Layout::new(8, 4));
829 assert_eq!(offsets(&laid_out), [0, 32]);
830
831 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
834 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
835 assert_eq!(laid_out.layout, Layout::new(8, 8));
836 assert_eq!(offsets(&laid_out), [0, 8]);
837
838 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
840 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
841 assert_eq!(offsets(&laid_out), [0, 8]);
842 }
843
844 #[test]
845 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
846 let types = Types::new();
847 let char_ = types.int(IntKind::Char);
848 let int = types.int(IntKind::Int);
849 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
850 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
851 assert_eq!(laid_out.layout, Layout::new(5, 1));
854 assert_eq!(offsets(&laid_out), [0, 32, 32]);
855 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
856 }
857
858 #[test]
859 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
860 let mut interner = Interner::new();
861 let types = Types::new();
862 let char_ = types.int(IntKind::Char);
863 let int = types.int(IntKind::Int);
864
865 let unnamed = [member(char_), unnamed_bits(int, 20)];
866 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
867 assert_eq!(unnamed.layout, Layout::new(4, 1));
868
869 let named = [member(char_), bits(&mut interner, "b", int, 20)];
870 let named = lay_out(&types, RecordKind::Struct, &named);
871 assert_eq!(named.layout, Layout::new(4, 4));
872 assert_eq!(offsets(&named), [0, 8], "the same place either way");
873
874 let wider = [member(char_), unnamed_bits(int, 30)];
877 let wider = lay_out(&types, RecordKind::Struct, &wider);
878 assert_eq!(wider.layout, Layout::new(8, 1));
879 assert_eq!(offsets(&wider), [0, 32]);
880 }
881
882 #[test]
883 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
884 let mut interner = Interner::new();
885 let types = Types::new();
886 let char_ = types.int(IntKind::Char);
887 let int = types.int(IntKind::Int);
888 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
889
890 let fields = [member(char_), member(int)];
891 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
892 .expect("a packed struct of two complete members");
893 assert_eq!(laid_out.layout, Layout::new(5, 1));
894 assert_eq!(offsets(&laid_out), [0, 8]);
895
896 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
897 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
898 .expect("a packed struct with a bit-field");
899 assert_eq!(laid_out.layout, Layout::new(5, 1));
900 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
901
902 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
905 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
906 .expect("a packed struct with a zero width bit-field");
907 assert_eq!(laid_out.layout, Layout::new(5, 1));
908 assert_eq!(offsets(&laid_out), [0, 32, 32]);
909 }
910
911 #[test]
912 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
913 let mut interner = Interner::new();
914 let types = Types::new();
915 let char_ = types.int(IntKind::Char);
916 let int = types.int(IntKind::Int);
917 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
918
919 let fields = [member(char_), member(int)];
920 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
921 .expect("a packed struct of two complete members");
922 assert_eq!(laid_out.layout, Layout::new(6, 2));
923 assert_eq!(offsets(&laid_out), [0, 16]);
924
925 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
929 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
930 .expect("a packed struct with a bit-field");
931 assert_eq!(laid_out.layout, Layout::new(6, 2));
932 assert_eq!(offsets(&laid_out), [0, 8]);
933
934 let fields = [member(char_), unnamed_bits(int, 30)];
937 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
938 .expect("a packed struct with an unnamed bit-field");
939 assert_eq!(laid_out.layout, Layout::new(5, 1));
940 }
941
942 #[test]
943 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
944 let types = Types::new();
945 let char_ = types.int(IntKind::Char);
946 let int = types.int(IntKind::Int);
947
948 let aligned = FieldDecl { align: Some(16), ..member(int) };
949 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
950 assert_eq!(laid_out.layout, Layout::new(32, 16));
951 assert_eq!(offsets(&laid_out), [0, 128]);
952
953 let options = RecordOptions { packed: true, align: Some(4), pack: None };
956 let fields = [member(char_), member(int)];
957 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
958 .expect("a packed struct with an alignment asked for");
959 assert_eq!(laid_out.layout, Layout::new(8, 4));
960 assert_eq!(offsets(&laid_out), [0, 8]);
961 }
962
963 #[test]
964 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
965 let mut types = Types::new();
967 let char_ = types.int(IntKind::Char);
968 let int = types.int(IntKind::Int);
969 let long_long = types.int(IntKind::LongLong);
970
971 let chars = types.array(char_, ArrayLen::Unknown);
972 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
973 assert_eq!(laid_out.layout, Layout::new(4, 4));
974 assert_eq!(offsets(&laid_out), [0, 32]);
975
976 let longs = types.array(long_long, ArrayLen::Unknown);
978 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
979 assert_eq!(laid_out.layout, Layout::new(8, 8));
980 assert_eq!(offsets(&laid_out), [0, 64]);
981
982 let fields = [member(chars), member(int)];
984 let error =
985 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
986 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
987 }
988
989 #[test]
990 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
991 let types = Types::new();
993 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
994 assert_eq!(laid_out.layout, Layout::new(0, 1));
995 }
996
997 #[test]
998 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
999 let types = Types::new();
1000 let int = types.int(IntKind::Int);
1001 let fields = [unnamed_bits(int, 33)];
1002 let error =
1003 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1004 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1005 assert_eq!(error, Err(want));
1006 }
1007
1008 #[test]
1009 fn a_record_reports_its_members_once_it_has_been_completed() {
1010 let mut interner = Interner::new();
1011 let mut types = Types::new();
1012 let char_ = types.int(IntKind::Char);
1013 let int = types.int(IntKind::Int);
1014 let name = interner.intern("count");
1015 let fields = [member(char_), FieldDecl::new(Some(name), int)];
1016 let id = types.declare_record(RecordKind::Struct, None);
1017 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1018 types.complete_record(id, laid_out);
1019 let ty = types.record(id);
1020 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1021 let field = types.field(id, name).expect("the member that was declared");
1022 assert_eq!(field.offset, 4);
1023 assert!(!field.is_bit_field());
1024 assert_eq!(types.field(id, interner.intern("missing")), None);
1025 }
1026
1027 #[test]
1028 fn a_nested_record_brings_its_own_alignment_with_it() {
1029 let mut types = Types::new();
1030 let char_ = types.int(IntKind::Char);
1031 let int = types.int(IntKind::Int);
1032 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1033 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1034 assert_eq!(laid_out.layout, Layout::new(8, 4));
1035 assert_eq!(offsets(&laid_out), [0, 32]);
1036
1037 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1040 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1041 assert_eq!(laid_out.layout, Layout::new(12, 4));
1042 assert_eq!(offsets(&laid_out), [0, 32]);
1043 }
1044
1045 #[test]
1046 fn everything_narrower_than_an_int_promotes_to_one() {
1047 let mut types = Types::new();
1051 let linux = linux();
1052 let int = types.int(IntKind::Int);
1053 let narrow =
1054 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1055 for kind in narrow {
1056 let ty = types.int(kind);
1057 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1058 }
1059 let boolean = types.boolean();
1060 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1061
1062 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1064 let ty = types.int(kind);
1065 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1066 }
1067 }
1068
1069 #[test]
1070 fn a_bit_int_is_not_promoted_at_all() {
1071 let mut types = Types::new();
1074 let linux = linux();
1075 let small = types.bit_int(true, 8);
1076 assert_eq!(promote(&mut types, small, &linux), small);
1077 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1078 }
1079
1080 #[test]
1081 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1082 let mut types = Types::new();
1083 let linux = linux();
1084 let int = types.int(IntKind::Int);
1085 let uint = types.int(IntKind::UInt);
1086 let ullong = types.int(IntKind::ULongLong);
1087
1088 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1090 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1092 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1094 let forty = types.bit_int(false, 40);
1099 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1100 assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1102 }
1103
1104 #[test]
1105 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1106 let mut types = Types::new();
1107 let linux = linux();
1108 let int = types.int(IntKind::Int);
1109 let short = types.int(IntKind::Short);
1110 let uint = types.int(IntKind::UInt);
1111
1112 let fixed = types.declare_enum(None);
1114 types.complete_enum(fixed, short, true);
1115 let fixed = types.enumeration(fixed);
1116 assert_eq!(promote(&mut types, fixed, &linux), int);
1117
1118 let unsigned = types.declare_enum(None);
1121 types.complete_enum(unsigned, uint, false);
1122 let unsigned = types.enumeration(unsigned);
1123 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1124
1125 let undecided = types.declare_enum(None);
1128 let undecided = types.enumeration(undecided);
1129 assert_eq!(promote(&mut types, undecided, &linux), int);
1130 }
1131
1132 #[test]
1133 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1134 let mut types = Types::new();
1137 let linux = linux();
1138 let int = types.int(IntKind::Int);
1139 let konst = types.qualified(int, Qualifiers::CONST);
1140 let atomic = types.atomic(konst);
1141 assert_eq!(promote(&mut types, atomic, &linux), int);
1142 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1143 }
1144
1145 #[test]
1146 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1147 let mut types = Types::new();
1149 let linux = linux();
1150 let cases = [
1151 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1152 (IntKind::Int, IntKind::Long, IntKind::Long),
1153 (IntKind::UInt, IntKind::Long, IntKind::Long),
1154 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1155 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1156 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1157 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1158 (IntKind::Char, IntKind::Char, IntKind::Int),
1159 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1160 ];
1161 for (left, right, want) in cases {
1162 let left = types.int(left);
1163 let right = types.int(right);
1164 let want = types.int(want);
1165 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1166 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1167 }
1168 }
1169
1170 #[test]
1171 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1172 let mut types = Types::new();
1176 let linux = linux();
1177 let signed = types.int(IntKind::Int128);
1178 let unsigned = types.int(IntKind::UInt128);
1179 for id in [signed, unsigned] {
1180 let laid_out = layout(&types, id, &linux).expect("a complete type");
1181 assert_eq!(laid_out.size, 16);
1182 assert_eq!(laid_out.align, 16);
1183 }
1184
1185 let ull = types.int(IntKind::ULongLong);
1189 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1190 assert_eq!(promote(&mut types, signed, &linux), signed);
1192 }
1193
1194 #[test]
1195 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1196 let mut types = Types::new();
1199 let linux = linux();
1200 let int128 = types.int(IntKind::Int128);
1201 let bit_int = types.bit_int(true, 128);
1202 assert_ne!(int128, bit_int);
1203 assert!(!compatible(&types, int128, bit_int));
1204 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1205 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1206 }
1207
1208 #[test]
1209 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1210 let mut types = Types::new();
1214 let linux = linux();
1215 let ulong = types.int(IntKind::ULong);
1216 let long_long = types.int(IntKind::LongLong);
1217 let want = types.int(IntKind::ULongLong);
1218 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1219
1220 let windows = target("x86_64-pc-windows-msvc");
1224 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1225 }
1226
1227 #[test]
1228 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1229 let mut types = Types::new();
1231 let linux = linux();
1232 let b40 = types.bit_int(true, 40);
1233 let ub40 = types.bit_int(false, 40);
1234 let b8 = types.bit_int(true, 8);
1235 let b32 = types.bit_int(true, 32);
1236 let int = types.int(IntKind::Int);
1237 let uint = types.int(IntKind::UInt);
1238 let long = types.int(IntKind::Long);
1239 let char_ = types.int(IntKind::Char);
1240
1241 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1243 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1245 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1247 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1248 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1251 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1254 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1255 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1257 }
1258
1259 #[test]
1260 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1261 let mut types = Types::new();
1262 let linux = linux();
1263 let float = types.float(FloatKind::Float);
1264 let double = types.float(FloatKind::Double);
1265 let long_double = types.float(FloatKind::LongDouble);
1266 let ullong = types.int(IntKind::ULongLong);
1267 let int = types.int(IntKind::Int);
1268
1269 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1270 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1271 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1272 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1275 }
1276
1277 #[test]
1278 fn a_mask_is_the_signed_integers_of_the_lane_width() {
1279 let mut types = Types::new();
1280 let linux = linux();
1281 let int = types.int(IntKind::Int);
1282 let float = types.float(FloatKind::Float);
1283 let short = types.int(IntKind::Short);
1284
1285 let four_ints = types.vector(int, 4);
1287 assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1288
1289 let uint = types.int(IntKind::UInt);
1292 let four_uints = types.vector(uint, 4);
1293 assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1294
1295 let four_floats = types.vector(float, 4);
1298 assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1299
1300 let two_shorts = types.vector(short, 2);
1302 assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1303
1304 assert_eq!(mask_of(&mut types, int, &linux), None);
1306 }
1307
1308 #[test]
1309 fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1310 let mut types = Types::new();
1311 let linux = linux();
1312 let int = types.int(IntKind::Int);
1313 let uint = types.int(IntKind::UInt);
1314 let float = types.float(FloatKind::Float);
1315 let short = types.int(IntKind::Short);
1316
1317 let four_ints = types.vector(int, 4);
1318 let four_uints = types.vector(uint, 4);
1319 let four_floats = types.vector(float, 4);
1320 let eight_shorts = types.vector(short, 8);
1321 let two_ints = types.vector(int, 2);
1322
1323 assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1326 assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1328 assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1330 assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1332
1333 assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1336 assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1338 assert!(!vectors_convertible(&types, four_ints, int, &linux));
1340 assert!(!vectors_convertible(&types, int, four_ints, &linux));
1341 }
1342
1343 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1348 let mut types = Types::new();
1349 let left = types.float(a);
1350 let right = types.float(b);
1351 let want = types.float(expected);
1352 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1353 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1354 }
1355
1356 #[test]
1357 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1358 let x86 = linux();
1362 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1363 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1364 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1365 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1366 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1367 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1368 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1369 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1370 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1371 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1372 }
1373
1374 #[test]
1375 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1376 let mac = target("aarch64-apple-darwin");
1380 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1381 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1382 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1383 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1384 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1385 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1386 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1387 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1390 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1391 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1392 }
1393
1394 #[test]
1395 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1396 let mut types = Types::new();
1397 let linux = linux();
1398 let cfloat = types.complex(FloatKind::Float);
1399 let cdouble = types.complex(FloatKind::Double);
1400 let cldouble = types.complex(FloatKind::LongDouble);
1401 let double = types.float(FloatKind::Double);
1402 let long_double = types.float(FloatKind::LongDouble);
1403 let float = types.float(FloatKind::Float);
1404 let int = types.int(IntKind::Int);
1405
1406 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1407 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1408 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1409 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1410 }
1411
1412 #[test]
1413 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1414 let mut types = Types::new();
1416 let linux = linux();
1417 let int = types.int(IntKind::Int);
1418 let pointer = types.pointer(int);
1419 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1420 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1421 let void = types.void();
1422 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1423 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1426 }
1427
1428 #[test]
1429 fn the_conversions_read_through_sugar() {
1430 let mut interner = Interner::new();
1431 let mut types = Types::new();
1432 let linux = linux();
1433 let char_ = types.int(IntKind::Char);
1434 let name = types.typedef(interner.intern("byte"), char_);
1435 let int = types.int(IntKind::Int);
1436 assert_eq!(promote(&mut types, name, &linux), int);
1437 }
1438
1439 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1441 let ret = types.void();
1442 types.function(FunctionType { ret, params, variadic, prototyped: true })
1443 }
1444
1445 fn old_style(types: &mut Types) -> TypeId {
1447 let ret = types.void();
1448 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1449 }
1450
1451 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1453 let id = types.declare_record(RecordKind::Struct, Some(tag));
1454 let laid_out = lay_out(types, RecordKind::Struct, fields);
1455 types.complete_record(id, laid_out);
1456 id
1457 }
1458
1459 #[test]
1460 fn a_type_is_compatible_with_itself_however_it_was_written() {
1461 let mut interner = Interner::new();
1462 let mut types = Types::new();
1463 let int = types.int(IntKind::Int);
1464 let name = types.typedef(interner.intern("int32_t"), int);
1465 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1466 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1467
1468 let konst = types.qualified(int, Qualifiers::CONST);
1471 assert!(!compatible(&types, konst, int));
1472 let konst_pointer = types.pointer(konst);
1473 let pointer = types.pointer(int);
1474 assert!(!compatible(&types, konst_pointer, pointer));
1475 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1476
1477 let char_ = types.int(IntKind::Char);
1480 let schar = types.int(IntKind::SChar);
1481 assert!(!compatible(&types, char_, schar));
1482 let atomic = types.atomic(int);
1484 assert!(!compatible(&types, atomic, int));
1485 }
1486
1487 #[test]
1488 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1489 let mut types = Types::new();
1492 let uint = types.int(IntKind::UInt);
1493 let int = types.int(IntKind::Int);
1494 let id = types.declare_enum(None);
1495 types.complete_enum(id, uint, false);
1496 let e = types.enumeration(id);
1497 assert!(compatible(&types, e, uint));
1498 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1499 assert!(!compatible(&types, e, int));
1500
1501 let other = types.declare_enum(None);
1504 types.complete_enum(other, uint, false);
1505 let other = types.enumeration(other);
1506 assert!(!compatible(&types, e, other));
1507
1508 let undecided = types.declare_enum(None);
1511 let undecided = types.enumeration(undecided);
1512 assert!(!compatible(&types, undecided, uint));
1513 assert!(compatible(&types, undecided, undecided));
1514 }
1515
1516 #[test]
1517 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1518 let mut types = Types::new();
1521 let int = types.int(IntKind::Int);
1522 let unknown = types.array(int, ArrayLen::Unknown);
1523 let four = types.array(int, ArrayLen::Fixed(4));
1524 let five = types.array(int, ArrayLen::Fixed(5));
1525 assert!(compatible(&types, unknown, four));
1526 assert!(!compatible(&types, four, five));
1527 assert_eq!(composite(&mut types, unknown, four), Some(four));
1528 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1529 assert_eq!(composite(&mut types, four, five), None);
1530
1531 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1534 assert!(compatible(&types, vla, four));
1535 assert_eq!(composite(&mut types, vla, four), Some(four));
1536
1537 let long = types.int(IntKind::Long);
1539 let longs = types.array(long, ArrayLen::Fixed(4));
1540 assert!(!compatible(&types, four, longs));
1541 }
1542
1543 #[test]
1544 fn a_parameter_declared_as_an_array_is_a_pointer() {
1545 let mut types = Types::new();
1549 let int = types.int(IntKind::Int);
1550 let three = types.array(int, ArrayLen::Fixed(3));
1551 let pointer = types.pointer(int);
1552 assert_eq!(adjust_parameter(&mut types, three), pointer);
1553
1554 let function = prototype(&mut types, vec![int], false);
1556 let function_pointer = types.pointer(function);
1557 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1558
1559 let konst = types.qualified(int, Qualifiers::CONST);
1562 assert_eq!(adjust_parameter(&mut types, konst), int);
1563 let to_konst = types.pointer(konst);
1564 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1565 }
1566
1567 #[test]
1568 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1569 let mut types = Types::new();
1573 let old = old_style(&mut types);
1574 let int = types.int(IntKind::Int);
1575 let long = types.int(IntKind::Long);
1576 let char_ = types.int(IntKind::Char);
1577 let float = types.float(FloatKind::Float);
1578 let double = types.float(FloatKind::Double);
1579
1580 let takes_int = prototype(&mut types, vec![int], false);
1581 assert!(compatible(&types, old, takes_int));
1582 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1583 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1585
1586 let pointer = types.pointer(int);
1587 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1588 let ty = prototype(&mut types, params, false);
1589 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1590 }
1591
1592 for params in [vec![char_], vec![float], vec![int, char_]] {
1595 let ty = prototype(&mut types, params, false);
1596 assert!(!compatible(&types, old, ty));
1597 assert_eq!(composite(&mut types, old, ty), None);
1598 }
1599
1600 let variadic = prototype(&mut types, vec![int], true);
1602 assert!(!compatible(&types, old, variadic));
1603
1604 let uint = types.int(IntKind::UInt);
1606 let id = types.declare_enum(None);
1607 types.complete_enum(id, uint, false);
1608 let e = types.enumeration(id);
1609 let takes_enum = prototype(&mut types, vec![e], false);
1610 assert!(compatible(&types, old, takes_enum));
1611
1612 assert!(compatible(&types, old, old));
1614
1615 let returns_int = types.function(FunctionType {
1617 ret: int,
1618 params: Vec::new(),
1619 variadic: false,
1620 prototyped: false,
1621 });
1622 assert!(!compatible(&types, returns_int, takes_int));
1623 }
1624
1625 #[test]
1626 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1627 let mut types = Types::new();
1631 let int = types.int(IntKind::Int);
1632 let takes_int = prototype(&mut types, vec![int], false);
1633 let takes_nothing = prototype(&mut types, Vec::new(), false);
1634 let old = old_style(&mut types);
1635 assert!(!compatible(&types, takes_nothing, takes_int));
1636 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1637 }
1638
1639 #[test]
1640 fn two_prototypes_have_to_agree_about_everything() {
1641 let mut types = Types::new();
1642 let int = types.int(IntKind::Int);
1643 let long = types.int(IntKind::Long);
1644 let base = prototype(&mut types, vec![int, int], false);
1645 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1646 let other = prototype(&mut types, other, false);
1647 assert!(!compatible(&types, base, other));
1648 }
1649 let variadic = prototype(&mut types, vec![int, int], true);
1650 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1651
1652 let four = types.array(int, ArrayLen::Fixed(4));
1655 let unknown = types.array(int, ArrayLen::Unknown);
1656 let to_four = types.pointer(four);
1657 let to_unknown = types.pointer(unknown);
1658 let a = prototype(&mut types, vec![to_four], false);
1659 let b = prototype(&mut types, vec![to_unknown], false);
1660 assert!(compatible(&types, a, b));
1661 assert_eq!(composite(&mut types, a, b), Some(a));
1663 }
1664
1665 #[test]
1666 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1667 let mut types = Types::new();
1668 let int = types.int(IntKind::Int);
1669 let four = types.array(int, ArrayLen::Fixed(4));
1670 let unknown = types.array(int, ArrayLen::Unknown);
1671 let to_four = types.pointer(four);
1672 let to_unknown = types.pointer(unknown);
1673 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1674
1675 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1677 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1678 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1679 }
1680
1681 #[test]
1682 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1683 let mut interner = Interner::new();
1687 let mut types = Types::new();
1688 let tag = interner.intern("point");
1689 let x = interner.intern("x");
1690 let y = interner.intern("y");
1691 let int = types.int(IntKind::Int);
1692 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1693
1694 let first = tagged(&mut types, tag, &members);
1695 let second = tagged(&mut types, tag, &members);
1696 let first = types.record(first);
1697 let second = types.record(second);
1698 assert_ne!(first, second, "still two declarations and two types");
1699 assert!(compatible(&types, first, second));
1700
1701 let z = interner.intern("z");
1704 let long = types.int(IntKind::Long);
1705 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1706 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1707 for other in [&renamed[..], &retyped[..], &members[..1]] {
1708 let other = tagged(&mut types, tag, other);
1709 let other = types.record(other);
1710 assert!(!compatible(&types, first, other));
1711 }
1712 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1713 let elsewhere = types.record(elsewhere);
1714 assert!(!compatible(&types, first, elsewhere));
1715
1716 let anonymous = record(&mut types, RecordKind::Struct, &members);
1719 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1720 assert!(!compatible(&types, anonymous, also_anonymous));
1721
1722 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1724 let incomplete = types.record(incomplete);
1725 assert!(!compatible(&types, first, incomplete));
1726 assert!(compatible(&types, incomplete, incomplete));
1727 }
1728
1729 #[test]
1730 fn a_self_referential_record_is_compared_without_going_round_forever() {
1731 let mut interner = Interner::new();
1735 let mut types = Types::new();
1736 let tag = interner.intern("node");
1737 let value = interner.intern("value");
1738 let next = interner.intern("next");
1739 let int = types.int(IntKind::Int);
1740
1741 let node = |types: &mut Types| {
1742 let id = types.declare_record(RecordKind::Struct, Some(tag));
1743 let ty = types.record(id);
1744 let pointer = types.pointer(ty);
1745 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1746 let laid_out = lay_out(types, RecordKind::Struct, &members);
1747 types.complete_record(id, laid_out);
1748 ty
1749 };
1750 let first = node(&mut types);
1751 let second = node(&mut types);
1752 assert_ne!(first, second);
1753 assert!(compatible(&types, first, second));
1754
1755 let id = types.declare_record(RecordKind::Struct, Some(tag));
1758 let ty = types.record(id);
1759 let pointer = types.pointer(ty);
1760 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1761 let laid_out = lay_out(&types, RecordKind::Struct, &members);
1762 types.complete_record(id, laid_out);
1763 assert!(!compatible(&types, first, ty));
1764 }
1765
1766 #[test]
1767 fn layout_reads_through_sugar() {
1768 let mut interner = Interner::new();
1769 let mut types = Types::new();
1770 let long = types.int(IntKind::Long);
1771 let name = types.typedef(interner.intern("word"), long);
1772 let array = types.array(name, ArrayLen::Fixed(4));
1773 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1774 }
1775}