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