1#![doc(html_root_url = "https://docs.rs/rucc-types/0.3.3")]
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 rucc_base::{Interner, Symbol};
118 use rucc_target::{TargetInfo, Triple};
119
120 use super::*;
121
122 fn target(triple: &str) -> TargetInfo {
123 TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
124 }
125
126 fn linux() -> TargetInfo {
127 target("x86_64-unknown-linux-gnu")
128 }
129
130 fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
132 layout_record(types, kind, fields, &RecordOptions::default(), &linux())
133 .expect("a record every member of which has a layout")
134 }
135
136 fn offsets(laid_out: &RecordLayout) -> Vec<u128> {
139 laid_out.fields.iter().map(Field::bit_offset).collect()
140 }
141
142 fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
144 let id = types.declare_record(kind, None);
145 let laid_out = lay_out(types, kind, fields);
146 types.complete_record(id, laid_out);
147 types.record(id)
148 }
149
150 fn member(ty: TypeId) -> FieldDecl {
152 FieldDecl::new(None, ty)
153 }
154
155 fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
158 FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
159 }
160
161 fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
163 FieldDecl::bit_field(None, ty, width)
164 }
165
166 #[test]
167 fn milestone_is_recorded() {
168 assert!(MILESTONE.starts_with('M'));
169 }
170
171 #[test]
172 fn an_integer_type_answers_with_the_width_of_its_value_and_not_of_its_object() {
173 let mut interner = Interner::new();
174 let mut types = Types::new();
175 let target = linux();
176
177 let boolean = types.boolean();
180 let bits = types.bit_int(true, 37);
181 let short = types.int(IntKind::Short);
183 let alias = types.typedef(interner.intern("word"), short);
184 let unsigned_char = types.int(IntKind::UChar);
185 let atomic = types.atomic(unsigned_char);
186
187 let shape = |ty| integer_info(&types, ty, &target).expect("an integer type");
188 assert_eq!(shape(boolean), IntegerInfo::new(false, 1));
189 assert_eq!(shape(bits), IntegerInfo::new(true, 37));
190 assert_eq!(shape(types.int(IntKind::Int)), IntegerInfo::new(true, 32));
191 assert_eq!(shape(types.int(IntKind::ULong)), IntegerInfo::new(false, 64));
192 assert_eq!(shape(alias), IntegerInfo::new(true, 16));
193 assert_eq!(shape(atomic), IntegerInfo::new(false, 8));
194
195 assert_eq!(integer_info(&types, types.float(FloatKind::Double), &target), None);
196 }
197
198 #[test]
199 fn an_enumeration_answers_with_the_type_the_enumerators_are_kept_in() {
200 let mut interner = Interner::new();
201 let mut types = Types::new();
202 let target = linux();
203
204 let colour = types.declare_enum(Some(interner.intern("colour")));
207 let ty = types.enumeration(colour);
208 assert_eq!(integer_info(&types, ty, &target), None);
209
210 let underlying = types.int(IntKind::ULong);
211 types.complete_enum(colour, underlying, true);
212 assert_eq!(integer_info(&types, ty, &target), Some(IntegerInfo::new(false, 64)));
213 }
214
215 #[test]
216 fn a_value_stored_in_an_integer_type_keeps_the_bits_the_type_has_room_for() {
217 let char_type = IntegerInfo::new(true, 8);
218 assert_eq!(char_type.wrap(300), 44);
219 assert!(!char_type.holds(300));
220 assert!(char_type.holds(-128));
221
222 assert_eq!(IntegerInfo::new(false, 32).wrap(-1), 4_294_967_295);
223 assert_eq!(IntegerInfo::new(false, 8).wrap(-1), 255);
224
225 assert!(IntegerInfo::new(false, 128).holds(i128::MIN));
228 assert!(IntegerInfo::new(true, 128).holds(i128::MIN));
229 assert_eq!(IntegerInfo::new(true, 128).wrap(i128::MAX), i128::MAX);
230 }
231
232 #[test]
233 fn a_long_double_has_a_format_the_size_does_not_give_away() {
234 let target = linux();
235 assert_eq!(float_width(FloatKind::LongDouble, &target), 128);
238 assert_eq!(
239 float_format(FloatKind::LongDouble, &target),
240 rucc_base::float::Format::X87Extended
241 );
242 assert_eq!(float_format(FloatKind::Float, &target), rucc_base::float::Format::Single);
243 }
244
245 #[test]
246 fn an_interchange_type_names_a_format_and_an_extended_one_names_the_target() {
247 use rucc_base::float::Format;
248
249 for target in [&linux(), &target("aarch64-apple-darwin")] {
252 assert_eq!(float_format(FloatKind::Float16, target), Format::Half);
253 assert_eq!(float_format(FloatKind::Float32, target), Format::Single);
254 assert_eq!(float_format(FloatKind::Float64, target), Format::Double);
255 assert_eq!(float_format(FloatKind::Float128, target), Format::Quad);
256 assert_eq!(float_width(FloatKind::Float16, target), 16);
257 assert_eq!(float_width(FloatKind::Float32, target), 32);
258 assert_eq!(float_width(FloatKind::Float64, target), 64);
259 assert_eq!(float_width(FloatKind::Float128, target), 128);
260 assert_eq!(float_format(FloatKind::Float32x, target), Format::Double);
262 }
263
264 let x86 = linux();
268 assert_eq!(float_format(FloatKind::Float64x, &x86), Format::X87Extended);
269 assert_eq!(float_format(FloatKind::LongDouble, &x86), Format::X87Extended);
270 let mac = target("aarch64-apple-darwin");
271 assert_eq!(float_format(FloatKind::Float64x, &mac), Format::Quad);
272 assert_eq!(float_format(FloatKind::LongDouble, &mac), Format::Double);
273 assert_eq!(float_width(FloatKind::Float64x, &x86), 128);
276 assert_eq!(float_width(FloatKind::Float64x, &mac), 128);
277 }
278
279 #[test]
280 fn every_floating_type_is_as_wide_as_the_format_it_is_stored_in() {
281 let types = Types::new();
282 let sizes = |target: &TargetInfo| -> Vec<(u64, u64)> {
283 FloatKind::ALL
284 .iter()
285 .map(|&kind| {
286 let found = layout(&types, types.float(kind), target).expect("a complete type");
287 (found.size, found.align)
288 })
289 .collect()
290 };
291 assert_eq!(
295 sizes(&linux()),
296 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16), (16, 16)]
297 );
298 assert_eq!(
299 sizes(&target("aarch64-apple-darwin")),
300 [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16)]
301 );
302 }
303
304 #[test]
305 fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
306 let types = Types::new();
309 let mut seen = Vec::new();
310 for kind in FloatKind::ALL {
311 seen.push(types.float(kind));
312 }
313 let mut sorted = seen.clone();
314 sorted.sort_unstable();
315 sorted.dedup();
316 assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
317
318 let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
319 assert_eq!(
320 names,
321 [
322 "_Float16",
323 "float",
324 "_Float32",
325 "double",
326 "_Float32x",
327 "_Float64",
328 "long double",
329 "_Float64x",
330 "_Float128",
331 ]
332 );
333 }
334
335 #[test]
336 fn the_same_type_asked_for_twice_is_the_same_id() {
337 let mut types = Types::new();
338 let a = types.pointer(types.int(IntKind::Int));
339 let b = types.pointer(types.int(IntKind::Int));
340 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
341 let c = types.pointer(types.int(IntKind::Long));
342 assert_ne!(a, c);
343 }
344
345 #[test]
346 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
347 let mut types = Types::new();
348 let int = types.int(IntKind::Int);
349 let konst = types.qualified(int, Qualifiers::CONST);
350 assert_ne!(int, konst);
351 assert_eq!(types.kind(konst), types.kind(int));
352 assert!(types.quals(konst).has(Qualifiers::CONST));
353 assert_eq!(types.unqualified(konst), int);
354 }
355
356 #[test]
357 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
358 let mut types = Types::new();
359 let int = types.int(IntKind::Int);
360 let a = types.qualified(int, Qualifiers::CONST);
361 let a = types.qualified(a, Qualifiers::VOLATILE);
362 let b = types.qualified(int, Qualifiers::VOLATILE);
363 let b = types.qualified(b, Qualifiers::CONST);
364 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
365 }
366
367 #[test]
368 fn qualifying_an_array_qualifies_its_element() {
369 let mut types = Types::new();
372 let int = types.int(IntKind::Int);
373 let array = types.array(int, ArrayLen::Fixed(4));
374 let konst = types.qualified(array, Qualifiers::CONST);
375 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
376 let TypeKind::Array { elem, len } = types.kind(konst) else {
377 panic!("still an array");
378 };
379 assert_eq!(len, ArrayLen::Fixed(4));
380 assert!(types.quals(elem).has(Qualifiers::CONST));
381 }
382
383 #[test]
384 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
385 let mut interner = Interner::new();
386 let mut types = Types::new();
387 let int = types.int(IntKind::Int);
388 let name = types.typedef(interner.intern("int32_t"), int);
389 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
390 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
391 assert!(types.is_sugar(name));
392 assert!(!types.is_sugar(int));
393 }
394
395 #[test]
396 fn sugar_below_the_outermost_node_is_resolved_too() {
397 let mut interner = Interner::new();
400 let mut types = Types::new();
401 let int = types.int(IntKind::Int);
402 let name = types.typedef(interner.intern("int32_t"), int);
403 let sugar_pointer = types.pointer(name);
404 let plain_pointer = types.pointer(int);
405 assert_ne!(sugar_pointer, plain_pointer);
406 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
407
408 let sugar_array = types.array(name, ArrayLen::Fixed(3));
409 let plain_array = types.array(int, ArrayLen::Fixed(3));
410 assert_eq!(types.canonical(sugar_array), plain_array);
411 }
412
413 #[test]
414 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
415 let mut interner = Interner::new();
416 let mut types = Types::new();
417 let int = types.int(IntKind::Int);
418 let mut current = int;
419 for i in 0..8 {
420 current = types.typedef(interner.intern(&format!("t{i}")), current);
421 }
422 assert_eq!(types.canonical(current), int);
423 }
424
425 #[test]
426 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
427 let mut interner = Interner::new();
428 let mut types = Types::new();
429 let int = types.int(IntKind::Int);
430 let name = types.typedef(interner.intern("int32_t"), int);
431 let konst = types.qualified(name, Qualifiers::CONST);
432 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
433 let want = types.qualified(int, Qualifiers::CONST);
434 assert_eq!(types.canonical(konst), want);
435 }
436
437 #[test]
438 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
439 let mut interner = Interner::new();
442 let mut types = Types::new();
443 let int = types.int(IntKind::Int);
444 let array = types.array(int, ArrayLen::Fixed(4));
445 let name = types.typedef(interner.intern("A"), array);
446 let konst = types.qualified(name, Qualifiers::CONST);
447 let konst_int = types.qualified(int, Qualifiers::CONST);
448 let want = types.array(konst_int, ArrayLen::Fixed(4));
449 assert_eq!(types.canonical(konst), want);
450 }
451
452 #[test]
453 fn a_function_type_is_deduplicated_by_its_signature() {
454 let mut types = Types::new();
455 let int = types.int(IntKind::Int);
456 let long = types.int(IntKind::Long);
457 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
458 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
459 };
460 let a = make(&mut types, vec![int, long], false);
461 let b = make(&mut types, vec![int, long], false);
462 assert_eq!(a, b);
463 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
464 assert_ne!(a, make(&mut types, vec![long, int], false));
465 }
466
467 #[test]
468 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
469 let mut interner = Interner::new();
470 let mut types = Types::new();
471 let int = types.int(IntKind::Int);
472 let name = types.typedef(interner.intern("int32_t"), int);
473 let sugar = types.function(FunctionType {
474 ret: name,
475 params: vec![name],
476 variadic: false,
477 prototyped: true,
478 });
479 let plain = types.function(FunctionType {
480 ret: int,
481 params: vec![int],
482 variadic: false,
483 prototyped: true,
484 });
485 assert_ne!(sugar, plain);
486 assert_eq!(types.canonical(sugar), plain);
487 }
488
489 #[test]
490 fn a_record_is_its_declaration_and_not_its_members() {
491 let mut interner = Interner::new();
495 let mut types = Types::new();
496 let tag = interner.intern("point");
497 let first = types.declare_record(RecordKind::Struct, Some(tag));
498 let second = types.declare_record(RecordKind::Struct, Some(tag));
499 assert_ne!(types.record(first), types.record(second));
500 assert_eq!(types.record(first), types.record(first));
501 }
502
503 #[test]
504 fn a_record_has_no_layout_until_it_has_been_completed() {
505 let mut types = Types::new();
506 let id = types.declare_record(RecordKind::Struct, None);
507 let ty = types.record(id);
508 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
509 let long_long = types.int(IntKind::LongLong);
510 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
511 types.complete_record(id, laid_out);
512 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
513 }
514
515 #[test]
516 fn an_enum_takes_the_layout_of_its_underlying_type() {
517 let mut types = Types::new();
518 let id = types.declare_enum(None);
519 let ty = types.enumeration(id);
520 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
521 let int = types.int(IntKind::Int);
522 types.complete_enum(id, int, false);
523 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
524 }
525
526 #[test]
527 fn the_scalar_widths_come_from_the_target() {
528 let mut types = Types::new();
529 let linux = linux();
530 let windows = target("x86_64-pc-windows-msvc");
531 let darwin = target("aarch64-apple-darwin");
532
533 let long = types.int(IntKind::Long);
534 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
535 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
536
537 let ldouble = types.float(FloatKind::LongDouble);
538 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
539 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
540
541 let pointer = types.pointer(types.void());
542 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
543
544 let boolean = types.boolean();
545 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
546 }
547
548 #[test]
549 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
550 let mut types = Types::new();
553 let linux = linux();
554 let cfloat = types.complex(FloatKind::Float);
555 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
556 let cdouble = types.complex(FloatKind::Double);
557 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
558 let cldouble = types.complex(FloatKind::LongDouble);
559 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
560 let darwin = target("aarch64-apple-darwin");
561 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
562 }
563
564 #[test]
565 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
566 let mut types = Types::new();
569 let linux = linux();
570 let long_long = types.int(IntKind::LongLong);
571 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
572 let atomic = types.atomic(plain);
573 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
574 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
575
576 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
578 let atomic_odd = types.atomic(odd);
579 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
580
581 let int = types.int(IntKind::Int);
582 let atomic_int = types.atomic(int);
583 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
584 }
585
586 #[test]
587 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
588 let mut types = Types::new();
591 let linux = linux();
592 let darwin = target("aarch64-apple-darwin");
593 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
594 for (width, size, align) in cases {
595 let ty = types.bit_int(true, width);
596 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
597 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
598 }
599 for width in [65, 96, 128] {
600 let ty = types.bit_int(false, width);
601 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
602 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
603 }
604 let wide = types.bit_int(true, 129);
605 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
606 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
607 }
608
609 #[test]
610 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
611 let mut types = Types::new();
612 let linux = linux();
613 let int = types.int(IntKind::Int);
614 let ty = types.array(int, ArrayLen::Fixed(10));
615 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
616 let nested = types.array(ty, ArrayLen::Fixed(3));
617 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
618 }
619
620 #[test]
621 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
622 let mut types = Types::new();
623 let linux = linux();
624 let int = types.int(IntKind::Int);
625 for len in [ArrayLen::Unknown, ArrayLen::Star, ArrayLen::Variable(VlaId(0))] {
626 let ty = types.array(int, len);
627 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
628 }
629 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
630 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
631 }
632
633 #[test]
634 fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
635 let mut types = Types::new();
639 let linux = linux();
640 let max = linux.max_object_size();
641 let ch = types.int(IntKind::Char);
642 let fits = types.array(ch, ArrayLen::Fixed(max));
643 assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
644 let over = types.array(ch, ArrayLen::Fixed(max + 1));
645 assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
646 }
647
648 #[test]
649 fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
650 let mut types = Types::new();
655 let linux = linux();
656 let max = linux.max_object_size();
657 let ch = types.int(IntKind::Char);
658 let int = types.int(IntKind::Int);
659 let short = types.int(IntKind::Short);
660
661 let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
662 let members = [member(huge), member(int), member(int), member(int), member(int)];
663 let laid_out = lay_out(&types, RecordKind::Struct, &members);
664 assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
665
666 let brim = types.array(ch, ArrayLen::Fixed(max));
667 let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
668 assert_eq!(laid_out.layout, Layout::new(max, 1));
669
670 let over = [member(brim), member(ch)];
671 let options = RecordOptions::default();
672 let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
673 assert_eq!(error, Err(RecordError::TooLarge));
674 }
675
676 #[test]
677 fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
678 let mut types = Types::new();
683 let linux = linux();
684 let ch = types.int(IntKind::Char);
685 let int = types.int(IntKind::Int);
686 let mut interner = Interner::new();
687 let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
688 let members = [member(buf), bits(&mut interner, "x", int, 1)];
689 let laid_out = lay_out(&types, RecordKind::Struct, &members);
690 assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
691 let last = laid_out.fields[1];
692 assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
693 assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
694 }
695
696 #[test]
697 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
698 let mut types = Types::new();
699 let int = types.int(IntKind::Int);
700 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
701 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
702 assert_ne!(a, b);
703 }
704
705 #[test]
706 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
707 let mut types = Types::new();
710 let linux = linux();
711 let int = types.int(IntKind::Int);
712 let four = types.vector(int, 4);
713 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
714 let three = types.vector(int, 3);
715 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
716 let three_chars = types.vector(types.int(IntKind::Char), 3);
717 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
718 }
719
720 #[test]
721 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
722 let mut types = Types::new();
725 let linux = linux();
726 let void = types.void();
727 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
728 let int = types.int(IntKind::Int);
729 let function = types.function(FunctionType {
730 ret: int,
731 params: Vec::new(),
732 variadic: false,
733 prototyped: true,
734 });
735 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
736 let pointer_to_function = types.pointer(function);
737 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
738 }
739
740 #[test]
741 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
742 let types = Types::new();
743 let char_ = types.int(IntKind::Char);
744 let int = types.int(IntKind::Int);
745 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
746 assert_eq!(laid_out.layout, Layout::new(8, 4));
747 assert_eq!(offsets(&laid_out), [0, 32]);
748 assert_eq!(laid_out.fields[1].offset, 4);
749
750 let long_long = types.int(IntKind::LongLong);
752 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
753 assert_eq!(laid_out.layout, Layout::new(16, 8));
754 }
755
756 #[test]
757 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
758 let mut types = Types::new();
759 let char_ = types.int(IntKind::Char);
760 let int = types.int(IntKind::Int);
761 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
762 assert_eq!(laid_out.layout, Layout::new(4, 4));
763 assert_eq!(offsets(&laid_out), [0, 0]);
764
765 let nine = types.array(char_, ArrayLen::Fixed(9));
768 let short = types.int(IntKind::Short);
769 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
770 assert_eq!(laid_out.layout, Layout::new(10, 2));
771 }
772
773 #[test]
774 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
775 let mut interner = Interner::new();
778 let types = Types::new();
779 let char_ = types.int(IntKind::Char);
780 let int = types.int(IntKind::Int);
781 let long_long = types.int(IntKind::LongLong);
782
783 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
784 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
785 assert_eq!(laid_out.layout, Layout::new(4, 4));
786 assert_eq!(offsets(&laid_out), [0, 3]);
787
788 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
790 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
791 assert_eq!(laid_out.layout, Layout::new(8, 4));
792 assert_eq!(offsets(&laid_out), [0, 32]);
793
794 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
797 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
798 assert_eq!(laid_out.layout, Layout::new(8, 8));
799 assert_eq!(offsets(&laid_out), [0, 8]);
800
801 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
803 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
804 assert_eq!(offsets(&laid_out), [0, 8]);
805 }
806
807 #[test]
808 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
809 let types = Types::new();
810 let char_ = types.int(IntKind::Char);
811 let int = types.int(IntKind::Int);
812 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
813 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
814 assert_eq!(laid_out.layout, Layout::new(5, 1));
817 assert_eq!(offsets(&laid_out), [0, 32, 32]);
818 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
819 }
820
821 #[test]
822 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
823 let mut interner = Interner::new();
824 let types = Types::new();
825 let char_ = types.int(IntKind::Char);
826 let int = types.int(IntKind::Int);
827
828 let unnamed = [member(char_), unnamed_bits(int, 20)];
829 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
830 assert_eq!(unnamed.layout, Layout::new(4, 1));
831
832 let named = [member(char_), bits(&mut interner, "b", int, 20)];
833 let named = lay_out(&types, RecordKind::Struct, &named);
834 assert_eq!(named.layout, Layout::new(4, 4));
835 assert_eq!(offsets(&named), [0, 8], "the same place either way");
836
837 let wider = [member(char_), unnamed_bits(int, 30)];
840 let wider = lay_out(&types, RecordKind::Struct, &wider);
841 assert_eq!(wider.layout, Layout::new(8, 1));
842 assert_eq!(offsets(&wider), [0, 32]);
843 }
844
845 #[test]
846 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
847 let mut interner = Interner::new();
848 let types = Types::new();
849 let char_ = types.int(IntKind::Char);
850 let int = types.int(IntKind::Int);
851 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
852
853 let fields = [member(char_), member(int)];
854 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
855 .expect("a packed struct of two complete members");
856 assert_eq!(laid_out.layout, Layout::new(5, 1));
857 assert_eq!(offsets(&laid_out), [0, 8]);
858
859 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
860 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
861 .expect("a packed struct with a bit-field");
862 assert_eq!(laid_out.layout, Layout::new(5, 1));
863 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
864
865 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
868 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
869 .expect("a packed struct with a zero width bit-field");
870 assert_eq!(laid_out.layout, Layout::new(5, 1));
871 assert_eq!(offsets(&laid_out), [0, 32, 32]);
872 }
873
874 #[test]
875 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
876 let mut interner = Interner::new();
877 let types = Types::new();
878 let char_ = types.int(IntKind::Char);
879 let int = types.int(IntKind::Int);
880 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
881
882 let fields = [member(char_), member(int)];
883 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
884 .expect("a packed struct of two complete members");
885 assert_eq!(laid_out.layout, Layout::new(6, 2));
886 assert_eq!(offsets(&laid_out), [0, 16]);
887
888 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
892 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
893 .expect("a packed struct with a bit-field");
894 assert_eq!(laid_out.layout, Layout::new(6, 2));
895 assert_eq!(offsets(&laid_out), [0, 8]);
896
897 let fields = [member(char_), unnamed_bits(int, 30)];
900 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
901 .expect("a packed struct with an unnamed bit-field");
902 assert_eq!(laid_out.layout, Layout::new(5, 1));
903 }
904
905 #[test]
906 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
907 let types = Types::new();
908 let char_ = types.int(IntKind::Char);
909 let int = types.int(IntKind::Int);
910
911 let aligned = FieldDecl { align: Some(16), ..member(int) };
912 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
913 assert_eq!(laid_out.layout, Layout::new(32, 16));
914 assert_eq!(offsets(&laid_out), [0, 128]);
915
916 let options = RecordOptions { packed: true, align: Some(4), pack: None };
919 let fields = [member(char_), member(int)];
920 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
921 .expect("a packed struct with an alignment asked for");
922 assert_eq!(laid_out.layout, Layout::new(8, 4));
923 assert_eq!(offsets(&laid_out), [0, 8]);
924 }
925
926 #[test]
927 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
928 let mut types = Types::new();
930 let char_ = types.int(IntKind::Char);
931 let int = types.int(IntKind::Int);
932 let long_long = types.int(IntKind::LongLong);
933
934 let chars = types.array(char_, ArrayLen::Unknown);
935 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
936 assert_eq!(laid_out.layout, Layout::new(4, 4));
937 assert_eq!(offsets(&laid_out), [0, 32]);
938
939 let longs = types.array(long_long, ArrayLen::Unknown);
941 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
942 assert_eq!(laid_out.layout, Layout::new(8, 8));
943 assert_eq!(offsets(&laid_out), [0, 64]);
944
945 let fields = [member(chars), member(int)];
947 let error =
948 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
949 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
950 }
951
952 #[test]
953 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
954 let types = Types::new();
956 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
957 assert_eq!(laid_out.layout, Layout::new(0, 1));
958 }
959
960 #[test]
961 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
962 let types = Types::new();
963 let int = types.int(IntKind::Int);
964 let fields = [unnamed_bits(int, 33)];
965 let error =
966 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
967 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
968 assert_eq!(error, Err(want));
969 }
970
971 #[test]
972 fn a_record_reports_its_members_once_it_has_been_completed() {
973 let mut interner = Interner::new();
974 let mut types = Types::new();
975 let char_ = types.int(IntKind::Char);
976 let int = types.int(IntKind::Int);
977 let name = interner.intern("count");
978 let fields = [member(char_), FieldDecl::new(Some(name), int)];
979 let id = types.declare_record(RecordKind::Struct, None);
980 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
981 types.complete_record(id, laid_out);
982 let ty = types.record(id);
983 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
984 let field = types.field(id, name).expect("the member that was declared");
985 assert_eq!(field.offset, 4);
986 assert!(!field.is_bit_field());
987 assert_eq!(types.field(id, interner.intern("missing")), None);
988 }
989
990 #[test]
991 fn a_nested_record_brings_its_own_alignment_with_it() {
992 let mut types = Types::new();
993 let char_ = types.int(IntKind::Char);
994 let int = types.int(IntKind::Int);
995 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
996 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
997 assert_eq!(laid_out.layout, Layout::new(8, 4));
998 assert_eq!(offsets(&laid_out), [0, 32]);
999
1000 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1003 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1004 assert_eq!(laid_out.layout, Layout::new(12, 4));
1005 assert_eq!(offsets(&laid_out), [0, 32]);
1006 }
1007
1008 #[test]
1009 fn everything_narrower_than_an_int_promotes_to_one() {
1010 let mut types = Types::new();
1014 let linux = linux();
1015 let int = types.int(IntKind::Int);
1016 let narrow =
1017 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1018 for kind in narrow {
1019 let ty = types.int(kind);
1020 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1021 }
1022 let boolean = types.boolean();
1023 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1024
1025 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1027 let ty = types.int(kind);
1028 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1029 }
1030 }
1031
1032 #[test]
1033 fn a_bit_int_is_not_promoted_at_all() {
1034 let mut types = Types::new();
1037 let linux = linux();
1038 let small = types.bit_int(true, 8);
1039 assert_eq!(promote(&mut types, small, &linux), small);
1040 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1041 }
1042
1043 #[test]
1044 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1045 let mut types = Types::new();
1046 let linux = linux();
1047 let int = types.int(IntKind::Int);
1048 let uint = types.int(IntKind::UInt);
1049 let ullong = types.int(IntKind::ULongLong);
1050
1051 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1053 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1055 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1057 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), ullong);
1060 }
1061
1062 #[test]
1063 fn an_enumeration_promotes_through_what_it_is_represented_in() {
1064 let mut types = Types::new();
1065 let linux = linux();
1066 let int = types.int(IntKind::Int);
1067 let short = types.int(IntKind::Short);
1068 let uint = types.int(IntKind::UInt);
1069
1070 let fixed = types.declare_enum(None);
1072 types.complete_enum(fixed, short, true);
1073 let fixed = types.enumeration(fixed);
1074 assert_eq!(promote(&mut types, fixed, &linux), int);
1075
1076 let unsigned = types.declare_enum(None);
1079 types.complete_enum(unsigned, uint, false);
1080 let unsigned = types.enumeration(unsigned);
1081 assert_eq!(promote(&mut types, unsigned, &linux), uint);
1082
1083 let undecided = types.declare_enum(None);
1086 let undecided = types.enumeration(undecided);
1087 assert_eq!(promote(&mut types, undecided, &linux), int);
1088 }
1089
1090 #[test]
1091 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1092 let mut types = Types::new();
1095 let linux = linux();
1096 let int = types.int(IntKind::Int);
1097 let konst = types.qualified(int, Qualifiers::CONST);
1098 let atomic = types.atomic(konst);
1099 assert_eq!(promote(&mut types, atomic, &linux), int);
1100 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1101 }
1102
1103 #[test]
1104 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1105 let mut types = Types::new();
1107 let linux = linux();
1108 let cases = [
1109 (IntKind::Int, IntKind::UInt, IntKind::UInt),
1110 (IntKind::Int, IntKind::Long, IntKind::Long),
1111 (IntKind::UInt, IntKind::Long, IntKind::Long),
1112 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1113 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1114 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1115 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1116 (IntKind::Char, IntKind::Char, IntKind::Int),
1117 (IntKind::UChar, IntKind::UShort, IntKind::Int),
1118 ];
1119 for (left, right, want) in cases {
1120 let left = types.int(left);
1121 let right = types.int(right);
1122 let want = types.int(want);
1123 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1124 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1125 }
1126 }
1127
1128 #[test]
1129 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1130 let mut types = Types::new();
1134 let linux = linux();
1135 let signed = types.int(IntKind::Int128);
1136 let unsigned = types.int(IntKind::UInt128);
1137 for id in [signed, unsigned] {
1138 let laid_out = layout(&types, id, &linux).expect("a complete type");
1139 assert_eq!(laid_out.size, 16);
1140 assert_eq!(laid_out.align, 16);
1141 }
1142
1143 let ull = types.int(IntKind::ULongLong);
1147 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1148 assert_eq!(promote(&mut types, signed, &linux), signed);
1150 }
1151
1152 #[test]
1153 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1154 let mut types = Types::new();
1157 let linux = linux();
1158 let int128 = types.int(IntKind::Int128);
1159 let bit_int = types.bit_int(true, 128);
1160 assert_ne!(int128, bit_int);
1161 assert!(!compatible(&types, int128, bit_int));
1162 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1163 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1164 }
1165
1166 #[test]
1167 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1168 let mut types = Types::new();
1172 let linux = linux();
1173 let ulong = types.int(IntKind::ULong);
1174 let long_long = types.int(IntKind::LongLong);
1175 let want = types.int(IntKind::ULongLong);
1176 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1177
1178 let windows = target("x86_64-pc-windows-msvc");
1182 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1183 }
1184
1185 #[test]
1186 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1187 let mut types = Types::new();
1189 let linux = linux();
1190 let b40 = types.bit_int(true, 40);
1191 let ub40 = types.bit_int(false, 40);
1192 let b8 = types.bit_int(true, 8);
1193 let b32 = types.bit_int(true, 32);
1194 let int = types.int(IntKind::Int);
1195 let uint = types.int(IntKind::UInt);
1196 let long = types.int(IntKind::Long);
1197 let char_ = types.int(IntKind::Char);
1198
1199 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1201 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1203 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1205 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1206 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1209 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1212 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1213 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1215 }
1216
1217 #[test]
1218 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1219 let mut types = Types::new();
1220 let linux = linux();
1221 let float = types.float(FloatKind::Float);
1222 let double = types.float(FloatKind::Double);
1223 let long_double = types.float(FloatKind::LongDouble);
1224 let ullong = types.int(IntKind::ULongLong);
1225 let int = types.int(IntKind::Int);
1226
1227 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1228 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1229 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1230 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1233 }
1234
1235 fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1240 let mut types = Types::new();
1241 let left = types.float(a);
1242 let right = types.float(b);
1243 let want = types.float(expected);
1244 assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1245 assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1246 }
1247
1248 #[test]
1249 fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1250 let x86 = linux();
1254 combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1255 combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1256 combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1257 combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1258 combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1259 combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1260 combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1261 combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1262 combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1263 combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1264 }
1265
1266 #[test]
1267 fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1268 let mac = target("aarch64-apple-darwin");
1272 combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1273 combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1274 combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1275 combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1276 combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1277 combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1278 combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1279 combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1282 combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1283 combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1284 }
1285
1286 #[test]
1287 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1288 let mut types = Types::new();
1289 let linux = linux();
1290 let cfloat = types.complex(FloatKind::Float);
1291 let cdouble = types.complex(FloatKind::Double);
1292 let cldouble = types.complex(FloatKind::LongDouble);
1293 let double = types.float(FloatKind::Double);
1294 let long_double = types.float(FloatKind::LongDouble);
1295 let float = types.float(FloatKind::Float);
1296 let int = types.int(IntKind::Int);
1297
1298 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1299 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1300 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1301 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1302 }
1303
1304 #[test]
1305 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1306 let mut types = Types::new();
1308 let linux = linux();
1309 let int = types.int(IntKind::Int);
1310 let pointer = types.pointer(int);
1311 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1312 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1313 let void = types.void();
1314 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1315 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1318 }
1319
1320 #[test]
1321 fn the_conversions_read_through_sugar() {
1322 let mut interner = Interner::new();
1323 let mut types = Types::new();
1324 let linux = linux();
1325 let char_ = types.int(IntKind::Char);
1326 let name = types.typedef(interner.intern("byte"), char_);
1327 let int = types.int(IntKind::Int);
1328 assert_eq!(promote(&mut types, name, &linux), int);
1329 }
1330
1331 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1333 let ret = types.void();
1334 types.function(FunctionType { ret, params, variadic, prototyped: true })
1335 }
1336
1337 fn old_style(types: &mut Types) -> TypeId {
1339 let ret = types.void();
1340 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1341 }
1342
1343 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1345 let id = types.declare_record(RecordKind::Struct, Some(tag));
1346 let laid_out = lay_out(types, RecordKind::Struct, fields);
1347 types.complete_record(id, laid_out);
1348 id
1349 }
1350
1351 #[test]
1352 fn a_type_is_compatible_with_itself_however_it_was_written() {
1353 let mut interner = Interner::new();
1354 let mut types = Types::new();
1355 let int = types.int(IntKind::Int);
1356 let name = types.typedef(interner.intern("int32_t"), int);
1357 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1358 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1359
1360 let konst = types.qualified(int, Qualifiers::CONST);
1363 assert!(!compatible(&types, konst, int));
1364 let konst_pointer = types.pointer(konst);
1365 let pointer = types.pointer(int);
1366 assert!(!compatible(&types, konst_pointer, pointer));
1367 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1368
1369 let char_ = types.int(IntKind::Char);
1372 let schar = types.int(IntKind::SChar);
1373 assert!(!compatible(&types, char_, schar));
1374 let atomic = types.atomic(int);
1376 assert!(!compatible(&types, atomic, int));
1377 }
1378
1379 #[test]
1380 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1381 let mut types = Types::new();
1384 let uint = types.int(IntKind::UInt);
1385 let int = types.int(IntKind::Int);
1386 let id = types.declare_enum(None);
1387 types.complete_enum(id, uint, false);
1388 let e = types.enumeration(id);
1389 assert!(compatible(&types, e, uint));
1390 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1391 assert!(!compatible(&types, e, int));
1392
1393 let other = types.declare_enum(None);
1396 types.complete_enum(other, uint, false);
1397 let other = types.enumeration(other);
1398 assert!(!compatible(&types, e, other));
1399
1400 let undecided = types.declare_enum(None);
1403 let undecided = types.enumeration(undecided);
1404 assert!(!compatible(&types, undecided, uint));
1405 assert!(compatible(&types, undecided, undecided));
1406 }
1407
1408 #[test]
1409 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1410 let mut types = Types::new();
1413 let int = types.int(IntKind::Int);
1414 let unknown = types.array(int, ArrayLen::Unknown);
1415 let four = types.array(int, ArrayLen::Fixed(4));
1416 let five = types.array(int, ArrayLen::Fixed(5));
1417 assert!(compatible(&types, unknown, four));
1418 assert!(!compatible(&types, four, five));
1419 assert_eq!(composite(&mut types, unknown, four), Some(four));
1420 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1421 assert_eq!(composite(&mut types, four, five), None);
1422
1423 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1426 assert!(compatible(&types, vla, four));
1427 assert_eq!(composite(&mut types, vla, four), Some(four));
1428
1429 let long = types.int(IntKind::Long);
1431 let longs = types.array(long, ArrayLen::Fixed(4));
1432 assert!(!compatible(&types, four, longs));
1433 }
1434
1435 #[test]
1436 fn a_parameter_declared_as_an_array_is_a_pointer() {
1437 let mut types = Types::new();
1441 let int = types.int(IntKind::Int);
1442 let three = types.array(int, ArrayLen::Fixed(3));
1443 let pointer = types.pointer(int);
1444 assert_eq!(adjust_parameter(&mut types, three), pointer);
1445
1446 let function = prototype(&mut types, vec![int], false);
1448 let function_pointer = types.pointer(function);
1449 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1450
1451 let konst = types.qualified(int, Qualifiers::CONST);
1454 assert_eq!(adjust_parameter(&mut types, konst), int);
1455 let to_konst = types.pointer(konst);
1456 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1457 }
1458
1459 #[test]
1460 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1461 let mut types = Types::new();
1465 let old = old_style(&mut types);
1466 let int = types.int(IntKind::Int);
1467 let long = types.int(IntKind::Long);
1468 let char_ = types.int(IntKind::Char);
1469 let float = types.float(FloatKind::Float);
1470 let double = types.float(FloatKind::Double);
1471
1472 let takes_int = prototype(&mut types, vec![int], false);
1473 assert!(compatible(&types, old, takes_int));
1474 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1475 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1477
1478 let pointer = types.pointer(int);
1479 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1480 let ty = prototype(&mut types, params, false);
1481 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1482 }
1483
1484 for params in [vec![char_], vec![float], vec![int, char_]] {
1487 let ty = prototype(&mut types, params, false);
1488 assert!(!compatible(&types, old, ty));
1489 assert_eq!(composite(&mut types, old, ty), None);
1490 }
1491
1492 let variadic = prototype(&mut types, vec![int], true);
1494 assert!(!compatible(&types, old, variadic));
1495
1496 let uint = types.int(IntKind::UInt);
1498 let id = types.declare_enum(None);
1499 types.complete_enum(id, uint, false);
1500 let e = types.enumeration(id);
1501 let takes_enum = prototype(&mut types, vec![e], false);
1502 assert!(compatible(&types, old, takes_enum));
1503
1504 assert!(compatible(&types, old, old));
1506
1507 let returns_int = types.function(FunctionType {
1509 ret: int,
1510 params: Vec::new(),
1511 variadic: false,
1512 prototyped: false,
1513 });
1514 assert!(!compatible(&types, returns_int, takes_int));
1515 }
1516
1517 #[test]
1518 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1519 let mut types = Types::new();
1523 let int = types.int(IntKind::Int);
1524 let takes_int = prototype(&mut types, vec![int], false);
1525 let takes_nothing = prototype(&mut types, Vec::new(), false);
1526 let old = old_style(&mut types);
1527 assert!(!compatible(&types, takes_nothing, takes_int));
1528 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1529 }
1530
1531 #[test]
1532 fn two_prototypes_have_to_agree_about_everything() {
1533 let mut types = Types::new();
1534 let int = types.int(IntKind::Int);
1535 let long = types.int(IntKind::Long);
1536 let base = prototype(&mut types, vec![int, int], false);
1537 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1538 let other = prototype(&mut types, other, false);
1539 assert!(!compatible(&types, base, other));
1540 }
1541 let variadic = prototype(&mut types, vec![int, int], true);
1542 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1543
1544 let four = types.array(int, ArrayLen::Fixed(4));
1547 let unknown = types.array(int, ArrayLen::Unknown);
1548 let to_four = types.pointer(four);
1549 let to_unknown = types.pointer(unknown);
1550 let a = prototype(&mut types, vec![to_four], false);
1551 let b = prototype(&mut types, vec![to_unknown], false);
1552 assert!(compatible(&types, a, b));
1553 assert_eq!(composite(&mut types, a, b), Some(a));
1555 }
1556
1557 #[test]
1558 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1559 let mut types = Types::new();
1560 let int = types.int(IntKind::Int);
1561 let four = types.array(int, ArrayLen::Fixed(4));
1562 let unknown = types.array(int, ArrayLen::Unknown);
1563 let to_four = types.pointer(four);
1564 let to_unknown = types.pointer(unknown);
1565 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1566
1567 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1569 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1570 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1571 }
1572
1573 #[test]
1574 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1575 let mut interner = Interner::new();
1579 let mut types = Types::new();
1580 let tag = interner.intern("point");
1581 let x = interner.intern("x");
1582 let y = interner.intern("y");
1583 let int = types.int(IntKind::Int);
1584 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1585
1586 let first = tagged(&mut types, tag, &members);
1587 let second = tagged(&mut types, tag, &members);
1588 let first = types.record(first);
1589 let second = types.record(second);
1590 assert_ne!(first, second, "still two declarations and two types");
1591 assert!(compatible(&types, first, second));
1592
1593 let z = interner.intern("z");
1596 let long = types.int(IntKind::Long);
1597 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1598 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1599 for other in [&renamed[..], &retyped[..], &members[..1]] {
1600 let other = tagged(&mut types, tag, other);
1601 let other = types.record(other);
1602 assert!(!compatible(&types, first, other));
1603 }
1604 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1605 let elsewhere = types.record(elsewhere);
1606 assert!(!compatible(&types, first, elsewhere));
1607
1608 let anonymous = record(&mut types, RecordKind::Struct, &members);
1611 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1612 assert!(!compatible(&types, anonymous, also_anonymous));
1613
1614 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1616 let incomplete = types.record(incomplete);
1617 assert!(!compatible(&types, first, incomplete));
1618 assert!(compatible(&types, incomplete, incomplete));
1619 }
1620
1621 #[test]
1622 fn a_self_referential_record_is_compared_without_going_round_forever() {
1623 let mut interner = Interner::new();
1627 let mut types = Types::new();
1628 let tag = interner.intern("node");
1629 let value = interner.intern("value");
1630 let next = interner.intern("next");
1631 let int = types.int(IntKind::Int);
1632
1633 let node = |types: &mut Types| {
1634 let id = types.declare_record(RecordKind::Struct, Some(tag));
1635 let ty = types.record(id);
1636 let pointer = types.pointer(ty);
1637 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1638 let laid_out = lay_out(types, RecordKind::Struct, &members);
1639 types.complete_record(id, laid_out);
1640 ty
1641 };
1642 let first = node(&mut types);
1643 let second = node(&mut types);
1644 assert_ne!(first, second);
1645 assert!(compatible(&types, first, second));
1646
1647 let id = types.declare_record(RecordKind::Struct, Some(tag));
1650 let ty = types.record(id);
1651 let pointer = types.pointer(ty);
1652 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1653 let laid_out = lay_out(&types, RecordKind::Struct, &members);
1654 types.complete_record(id, laid_out);
1655 assert!(!compatible(&types, first, ty));
1656 }
1657
1658 #[test]
1659 fn layout_reads_through_sugar() {
1660 let mut interner = Interner::new();
1661 let mut types = Types::new();
1662 let long = types.int(IntKind::Long);
1663 let name = types.typedef(interner.intern("word"), long);
1664 let array = types.array(name, ArrayLen::Fixed(4));
1665 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1666 }
1667}