1#![doc(html_root_url = "https://docs.rs/rucc-types/0.2.9")]
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<u64> {
139 laid_out.fields.iter().map(|field| field.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 the_same_type_asked_for_twice_is_the_same_id() {
247 let mut types = Types::new();
248 let a = types.pointer(types.int(IntKind::Int));
249 let b = types.pointer(types.int(IntKind::Int));
250 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
251 let c = types.pointer(types.int(IntKind::Long));
252 assert_ne!(a, c);
253 }
254
255 #[test]
256 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
257 let mut types = Types::new();
258 let int = types.int(IntKind::Int);
259 let konst = types.qualified(int, Qualifiers::CONST);
260 assert_ne!(int, konst);
261 assert_eq!(types.kind(konst), types.kind(int));
262 assert!(types.quals(konst).has(Qualifiers::CONST));
263 assert_eq!(types.unqualified(konst), int);
264 }
265
266 #[test]
267 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
268 let mut types = Types::new();
269 let int = types.int(IntKind::Int);
270 let a = types.qualified(int, Qualifiers::CONST);
271 let a = types.qualified(a, Qualifiers::VOLATILE);
272 let b = types.qualified(int, Qualifiers::VOLATILE);
273 let b = types.qualified(b, Qualifiers::CONST);
274 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
275 }
276
277 #[test]
278 fn qualifying_an_array_qualifies_its_element() {
279 let mut types = Types::new();
282 let int = types.int(IntKind::Int);
283 let array = types.array(int, ArrayLen::Fixed(4));
284 let konst = types.qualified(array, Qualifiers::CONST);
285 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
286 let TypeKind::Array { elem, len } = types.kind(konst) else {
287 panic!("still an array");
288 };
289 assert_eq!(len, ArrayLen::Fixed(4));
290 assert!(types.quals(elem).has(Qualifiers::CONST));
291 }
292
293 #[test]
294 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
295 let mut interner = Interner::new();
296 let mut types = Types::new();
297 let int = types.int(IntKind::Int);
298 let name = types.typedef(interner.intern("int32_t"), int);
299 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
300 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
301 assert!(types.is_sugar(name));
302 assert!(!types.is_sugar(int));
303 }
304
305 #[test]
306 fn sugar_below_the_outermost_node_is_resolved_too() {
307 let mut interner = Interner::new();
310 let mut types = Types::new();
311 let int = types.int(IntKind::Int);
312 let name = types.typedef(interner.intern("int32_t"), int);
313 let sugar_pointer = types.pointer(name);
314 let plain_pointer = types.pointer(int);
315 assert_ne!(sugar_pointer, plain_pointer);
316 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
317
318 let sugar_array = types.array(name, ArrayLen::Fixed(3));
319 let plain_array = types.array(int, ArrayLen::Fixed(3));
320 assert_eq!(types.canonical(sugar_array), plain_array);
321 }
322
323 #[test]
324 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
325 let mut interner = Interner::new();
326 let mut types = Types::new();
327 let int = types.int(IntKind::Int);
328 let mut current = int;
329 for i in 0..8 {
330 current = types.typedef(interner.intern(&format!("t{i}")), current);
331 }
332 assert_eq!(types.canonical(current), int);
333 }
334
335 #[test]
336 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
337 let mut interner = Interner::new();
338 let mut types = Types::new();
339 let int = types.int(IntKind::Int);
340 let name = types.typedef(interner.intern("int32_t"), int);
341 let konst = types.qualified(name, Qualifiers::CONST);
342 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
343 let want = types.qualified(int, Qualifiers::CONST);
344 assert_eq!(types.canonical(konst), want);
345 }
346
347 #[test]
348 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
349 let mut interner = Interner::new();
352 let mut types = Types::new();
353 let int = types.int(IntKind::Int);
354 let array = types.array(int, ArrayLen::Fixed(4));
355 let name = types.typedef(interner.intern("A"), array);
356 let konst = types.qualified(name, Qualifiers::CONST);
357 let konst_int = types.qualified(int, Qualifiers::CONST);
358 let want = types.array(konst_int, ArrayLen::Fixed(4));
359 assert_eq!(types.canonical(konst), want);
360 }
361
362 #[test]
363 fn a_function_type_is_deduplicated_by_its_signature() {
364 let mut types = Types::new();
365 let int = types.int(IntKind::Int);
366 let long = types.int(IntKind::Long);
367 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
368 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
369 };
370 let a = make(&mut types, vec![int, long], false);
371 let b = make(&mut types, vec![int, long], false);
372 assert_eq!(a, b);
373 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
374 assert_ne!(a, make(&mut types, vec![long, int], false));
375 }
376
377 #[test]
378 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
379 let mut interner = Interner::new();
380 let mut types = Types::new();
381 let int = types.int(IntKind::Int);
382 let name = types.typedef(interner.intern("int32_t"), int);
383 let sugar = types.function(FunctionType {
384 ret: name,
385 params: vec![name],
386 variadic: false,
387 prototyped: true,
388 });
389 let plain = types.function(FunctionType {
390 ret: int,
391 params: vec![int],
392 variadic: false,
393 prototyped: true,
394 });
395 assert_ne!(sugar, plain);
396 assert_eq!(types.canonical(sugar), plain);
397 }
398
399 #[test]
400 fn a_record_is_its_declaration_and_not_its_members() {
401 let mut interner = Interner::new();
405 let mut types = Types::new();
406 let tag = interner.intern("point");
407 let first = types.declare_record(RecordKind::Struct, Some(tag));
408 let second = types.declare_record(RecordKind::Struct, Some(tag));
409 assert_ne!(types.record(first), types.record(second));
410 assert_eq!(types.record(first), types.record(first));
411 }
412
413 #[test]
414 fn a_record_has_no_layout_until_it_has_been_completed() {
415 let mut types = Types::new();
416 let id = types.declare_record(RecordKind::Struct, None);
417 let ty = types.record(id);
418 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
419 let long_long = types.int(IntKind::LongLong);
420 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
421 types.complete_record(id, laid_out);
422 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
423 }
424
425 #[test]
426 fn an_enum_takes_the_layout_of_its_underlying_type() {
427 let mut types = Types::new();
428 let id = types.declare_enum(None);
429 let ty = types.enumeration(id);
430 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
431 let int = types.int(IntKind::Int);
432 types.complete_enum(id, int, false);
433 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
434 }
435
436 #[test]
437 fn the_scalar_widths_come_from_the_target() {
438 let mut types = Types::new();
439 let linux = linux();
440 let windows = target("x86_64-pc-windows-msvc");
441 let darwin = target("aarch64-apple-darwin");
442
443 let long = types.int(IntKind::Long);
444 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
445 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
446
447 let ldouble = types.float(FloatKind::LongDouble);
448 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
449 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
450
451 let pointer = types.pointer(types.void());
452 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
453
454 let boolean = types.boolean();
455 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
456 }
457
458 #[test]
459 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
460 let mut types = Types::new();
463 let linux = linux();
464 let cfloat = types.complex(FloatKind::Float);
465 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
466 let cdouble = types.complex(FloatKind::Double);
467 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
468 let cldouble = types.complex(FloatKind::LongDouble);
469 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
470 let darwin = target("aarch64-apple-darwin");
471 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
472 }
473
474 #[test]
475 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
476 let mut types = Types::new();
479 let linux = linux();
480 let long_long = types.int(IntKind::LongLong);
481 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
482 let atomic = types.atomic(plain);
483 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
484 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
485
486 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
488 let atomic_odd = types.atomic(odd);
489 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
490
491 let int = types.int(IntKind::Int);
492 let atomic_int = types.atomic(int);
493 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
494 }
495
496 #[test]
497 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
498 let mut types = Types::new();
501 let linux = linux();
502 let darwin = target("aarch64-apple-darwin");
503 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
504 for (width, size, align) in cases {
505 let ty = types.bit_int(true, width);
506 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
507 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
508 }
509 for width in [65, 96, 128] {
510 let ty = types.bit_int(false, width);
511 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
512 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
513 }
514 let wide = types.bit_int(true, 129);
515 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
516 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
517 }
518
519 #[test]
520 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
521 let mut types = Types::new();
522 let linux = linux();
523 let int = types.int(IntKind::Int);
524 let ty = types.array(int, ArrayLen::Fixed(10));
525 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
526 let nested = types.array(ty, ArrayLen::Fixed(3));
527 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
528 }
529
530 #[test]
531 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
532 let mut types = Types::new();
533 let linux = linux();
534 let int = types.int(IntKind::Int);
535 for len in [ArrayLen::Unknown, ArrayLen::Star, ArrayLen::Variable(VlaId(0))] {
536 let ty = types.array(int, len);
537 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
538 }
539 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
540 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
541 }
542
543 #[test]
544 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
545 let mut types = Types::new();
546 let int = types.int(IntKind::Int);
547 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
548 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
549 assert_ne!(a, b);
550 }
551
552 #[test]
553 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
554 let mut types = Types::new();
557 let linux = linux();
558 let int = types.int(IntKind::Int);
559 let four = types.vector(int, 4);
560 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
561 let three = types.vector(int, 3);
562 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
563 let three_chars = types.vector(types.int(IntKind::Char), 3);
564 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
565 }
566
567 #[test]
568 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
569 let mut types = Types::new();
572 let linux = linux();
573 let void = types.void();
574 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
575 let int = types.int(IntKind::Int);
576 let function = types.function(FunctionType {
577 ret: int,
578 params: Vec::new(),
579 variadic: false,
580 prototyped: true,
581 });
582 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
583 let pointer_to_function = types.pointer(function);
584 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
585 }
586
587 #[test]
588 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
589 let types = Types::new();
590 let char_ = types.int(IntKind::Char);
591 let int = types.int(IntKind::Int);
592 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
593 assert_eq!(laid_out.layout, Layout::new(8, 4));
594 assert_eq!(offsets(&laid_out), [0, 32]);
595 assert_eq!(laid_out.fields[1].byte_offset(), 4);
596
597 let long_long = types.int(IntKind::LongLong);
599 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
600 assert_eq!(laid_out.layout, Layout::new(16, 8));
601 }
602
603 #[test]
604 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
605 let mut types = Types::new();
606 let char_ = types.int(IntKind::Char);
607 let int = types.int(IntKind::Int);
608 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
609 assert_eq!(laid_out.layout, Layout::new(4, 4));
610 assert_eq!(offsets(&laid_out), [0, 0]);
611
612 let nine = types.array(char_, ArrayLen::Fixed(9));
615 let short = types.int(IntKind::Short);
616 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
617 assert_eq!(laid_out.layout, Layout::new(10, 2));
618 }
619
620 #[test]
621 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
622 let mut interner = Interner::new();
625 let types = Types::new();
626 let char_ = types.int(IntKind::Char);
627 let int = types.int(IntKind::Int);
628 let long_long = types.int(IntKind::LongLong);
629
630 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
631 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
632 assert_eq!(laid_out.layout, Layout::new(4, 4));
633 assert_eq!(offsets(&laid_out), [0, 3]);
634
635 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
637 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
638 assert_eq!(laid_out.layout, Layout::new(8, 4));
639 assert_eq!(offsets(&laid_out), [0, 32]);
640
641 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
644 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
645 assert_eq!(laid_out.layout, Layout::new(8, 8));
646 assert_eq!(offsets(&laid_out), [0, 8]);
647
648 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
650 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
651 assert_eq!(offsets(&laid_out), [0, 8]);
652 }
653
654 #[test]
655 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
656 let types = Types::new();
657 let char_ = types.int(IntKind::Char);
658 let int = types.int(IntKind::Int);
659 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
660 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
661 assert_eq!(laid_out.layout, Layout::new(5, 1));
664 assert_eq!(offsets(&laid_out), [0, 32, 32]);
665 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
666 }
667
668 #[test]
669 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
670 let mut interner = Interner::new();
671 let types = Types::new();
672 let char_ = types.int(IntKind::Char);
673 let int = types.int(IntKind::Int);
674
675 let unnamed = [member(char_), unnamed_bits(int, 20)];
676 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
677 assert_eq!(unnamed.layout, Layout::new(4, 1));
678
679 let named = [member(char_), bits(&mut interner, "b", int, 20)];
680 let named = lay_out(&types, RecordKind::Struct, &named);
681 assert_eq!(named.layout, Layout::new(4, 4));
682 assert_eq!(offsets(&named), [0, 8], "the same place either way");
683
684 let wider = [member(char_), unnamed_bits(int, 30)];
687 let wider = lay_out(&types, RecordKind::Struct, &wider);
688 assert_eq!(wider.layout, Layout::new(8, 1));
689 assert_eq!(offsets(&wider), [0, 32]);
690 }
691
692 #[test]
693 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
694 let mut interner = Interner::new();
695 let types = Types::new();
696 let char_ = types.int(IntKind::Char);
697 let int = types.int(IntKind::Int);
698 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
699
700 let fields = [member(char_), member(int)];
701 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
702 .expect("a packed struct of two complete members");
703 assert_eq!(laid_out.layout, Layout::new(5, 1));
704 assert_eq!(offsets(&laid_out), [0, 8]);
705
706 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
707 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
708 .expect("a packed struct with a bit-field");
709 assert_eq!(laid_out.layout, Layout::new(5, 1));
710 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
711
712 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
715 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
716 .expect("a packed struct with a zero width bit-field");
717 assert_eq!(laid_out.layout, Layout::new(5, 1));
718 assert_eq!(offsets(&laid_out), [0, 32, 32]);
719 }
720
721 #[test]
722 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
723 let mut interner = Interner::new();
724 let types = Types::new();
725 let char_ = types.int(IntKind::Char);
726 let int = types.int(IntKind::Int);
727 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
728
729 let fields = [member(char_), member(int)];
730 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
731 .expect("a packed struct of two complete members");
732 assert_eq!(laid_out.layout, Layout::new(6, 2));
733 assert_eq!(offsets(&laid_out), [0, 16]);
734
735 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
739 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
740 .expect("a packed struct with a bit-field");
741 assert_eq!(laid_out.layout, Layout::new(6, 2));
742 assert_eq!(offsets(&laid_out), [0, 8]);
743
744 let fields = [member(char_), unnamed_bits(int, 30)];
747 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
748 .expect("a packed struct with an unnamed bit-field");
749 assert_eq!(laid_out.layout, Layout::new(5, 1));
750 }
751
752 #[test]
753 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
754 let types = Types::new();
755 let char_ = types.int(IntKind::Char);
756 let int = types.int(IntKind::Int);
757
758 let aligned = FieldDecl { align: Some(16), ..member(int) };
759 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
760 assert_eq!(laid_out.layout, Layout::new(32, 16));
761 assert_eq!(offsets(&laid_out), [0, 128]);
762
763 let options = RecordOptions { packed: true, align: Some(4), pack: None };
766 let fields = [member(char_), member(int)];
767 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
768 .expect("a packed struct with an alignment asked for");
769 assert_eq!(laid_out.layout, Layout::new(8, 4));
770 assert_eq!(offsets(&laid_out), [0, 8]);
771 }
772
773 #[test]
774 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
775 let mut types = Types::new();
777 let char_ = types.int(IntKind::Char);
778 let int = types.int(IntKind::Int);
779 let long_long = types.int(IntKind::LongLong);
780
781 let chars = types.array(char_, ArrayLen::Unknown);
782 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
783 assert_eq!(laid_out.layout, Layout::new(4, 4));
784 assert_eq!(offsets(&laid_out), [0, 32]);
785
786 let longs = types.array(long_long, ArrayLen::Unknown);
788 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
789 assert_eq!(laid_out.layout, Layout::new(8, 8));
790 assert_eq!(offsets(&laid_out), [0, 64]);
791
792 let fields = [member(chars), member(int)];
794 let error =
795 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
796 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
797 }
798
799 #[test]
800 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
801 let types = Types::new();
803 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
804 assert_eq!(laid_out.layout, Layout::new(0, 1));
805 }
806
807 #[test]
808 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
809 let types = Types::new();
810 let int = types.int(IntKind::Int);
811 let fields = [unnamed_bits(int, 33)];
812 let error =
813 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
814 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
815 assert_eq!(error, Err(want));
816 }
817
818 #[test]
819 fn a_record_reports_its_members_once_it_has_been_completed() {
820 let mut interner = Interner::new();
821 let mut types = Types::new();
822 let char_ = types.int(IntKind::Char);
823 let int = types.int(IntKind::Int);
824 let name = interner.intern("count");
825 let fields = [member(char_), FieldDecl::new(Some(name), int)];
826 let id = types.declare_record(RecordKind::Struct, None);
827 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
828 types.complete_record(id, laid_out);
829 let ty = types.record(id);
830 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
831 let field = types.field(id, name).expect("the member that was declared");
832 assert_eq!(field.byte_offset(), 4);
833 assert!(!field.is_bit_field());
834 assert_eq!(types.field(id, interner.intern("missing")), None);
835 }
836
837 #[test]
838 fn a_nested_record_brings_its_own_alignment_with_it() {
839 let mut types = Types::new();
840 let char_ = types.int(IntKind::Char);
841 let int = types.int(IntKind::Int);
842 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
843 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
844 assert_eq!(laid_out.layout, Layout::new(8, 4));
845 assert_eq!(offsets(&laid_out), [0, 32]);
846
847 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
850 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
851 assert_eq!(laid_out.layout, Layout::new(12, 4));
852 assert_eq!(offsets(&laid_out), [0, 32]);
853 }
854
855 #[test]
856 fn everything_narrower_than_an_int_promotes_to_one() {
857 let mut types = Types::new();
861 let linux = linux();
862 let int = types.int(IntKind::Int);
863 let narrow =
864 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
865 for kind in narrow {
866 let ty = types.int(kind);
867 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
868 }
869 let boolean = types.boolean();
870 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
871
872 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
874 let ty = types.int(kind);
875 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
876 }
877 }
878
879 #[test]
880 fn a_bit_int_is_not_promoted_at_all() {
881 let mut types = Types::new();
884 let linux = linux();
885 let small = types.bit_int(true, 8);
886 assert_eq!(promote(&mut types, small, &linux), small);
887 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
888 }
889
890 #[test]
891 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
892 let mut types = Types::new();
893 let linux = linux();
894 let int = types.int(IntKind::Int);
895 let uint = types.int(IntKind::UInt);
896 let ullong = types.int(IntKind::ULongLong);
897
898 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
900 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
902 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
904 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), ullong);
907 }
908
909 #[test]
910 fn an_enumeration_promotes_through_what_it_is_represented_in() {
911 let mut types = Types::new();
912 let linux = linux();
913 let int = types.int(IntKind::Int);
914 let short = types.int(IntKind::Short);
915 let uint = types.int(IntKind::UInt);
916
917 let fixed = types.declare_enum(None);
919 types.complete_enum(fixed, short, true);
920 let fixed = types.enumeration(fixed);
921 assert_eq!(promote(&mut types, fixed, &linux), int);
922
923 let unsigned = types.declare_enum(None);
926 types.complete_enum(unsigned, uint, false);
927 let unsigned = types.enumeration(unsigned);
928 assert_eq!(promote(&mut types, unsigned, &linux), uint);
929
930 let undecided = types.declare_enum(None);
933 let undecided = types.enumeration(undecided);
934 assert_eq!(promote(&mut types, undecided, &linux), int);
935 }
936
937 #[test]
938 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
939 let mut types = Types::new();
942 let linux = linux();
943 let int = types.int(IntKind::Int);
944 let konst = types.qualified(int, Qualifiers::CONST);
945 let atomic = types.atomic(konst);
946 assert_eq!(promote(&mut types, atomic, &linux), int);
947 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
948 }
949
950 #[test]
951 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
952 let mut types = Types::new();
954 let linux = linux();
955 let cases = [
956 (IntKind::Int, IntKind::UInt, IntKind::UInt),
957 (IntKind::Int, IntKind::Long, IntKind::Long),
958 (IntKind::UInt, IntKind::Long, IntKind::Long),
959 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
960 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
961 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
962 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
963 (IntKind::Char, IntKind::Char, IntKind::Int),
964 (IntKind::UChar, IntKind::UShort, IntKind::Int),
965 ];
966 for (left, right, want) in cases {
967 let left = types.int(left);
968 let right = types.int(right);
969 let want = types.int(want);
970 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
971 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
972 }
973 }
974
975 #[test]
976 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
977 let mut types = Types::new();
981 let linux = linux();
982 let signed = types.int(IntKind::Int128);
983 let unsigned = types.int(IntKind::UInt128);
984 for id in [signed, unsigned] {
985 let laid_out = layout(&types, id, &linux).expect("a complete type");
986 assert_eq!(laid_out.size, 16);
987 assert_eq!(laid_out.align, 16);
988 }
989
990 let ull = types.int(IntKind::ULongLong);
994 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
995 assert_eq!(promote(&mut types, signed, &linux), signed);
997 }
998
999 #[test]
1000 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1001 let mut types = Types::new();
1004 let linux = linux();
1005 let int128 = types.int(IntKind::Int128);
1006 let bit_int = types.bit_int(true, 128);
1007 assert_ne!(int128, bit_int);
1008 assert!(!compatible(&types, int128, bit_int));
1009 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1010 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1011 }
1012
1013 #[test]
1014 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1015 let mut types = Types::new();
1019 let linux = linux();
1020 let ulong = types.int(IntKind::ULong);
1021 let long_long = types.int(IntKind::LongLong);
1022 let want = types.int(IntKind::ULongLong);
1023 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1024
1025 let windows = target("x86_64-pc-windows-msvc");
1029 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1030 }
1031
1032 #[test]
1033 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1034 let mut types = Types::new();
1036 let linux = linux();
1037 let b40 = types.bit_int(true, 40);
1038 let ub40 = types.bit_int(false, 40);
1039 let b8 = types.bit_int(true, 8);
1040 let b32 = types.bit_int(true, 32);
1041 let int = types.int(IntKind::Int);
1042 let uint = types.int(IntKind::UInt);
1043 let long = types.int(IntKind::Long);
1044 let char_ = types.int(IntKind::Char);
1045
1046 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1048 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1050 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1052 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1053 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1056 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1059 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1060 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1062 }
1063
1064 #[test]
1065 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1066 let mut types = Types::new();
1067 let linux = linux();
1068 let float = types.float(FloatKind::Float);
1069 let double = types.float(FloatKind::Double);
1070 let long_double = types.float(FloatKind::LongDouble);
1071 let ullong = types.int(IntKind::ULongLong);
1072 let int = types.int(IntKind::Int);
1073
1074 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1075 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1076 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1077 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1080 }
1081
1082 #[test]
1083 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1084 let mut types = Types::new();
1085 let linux = linux();
1086 let cfloat = types.complex(FloatKind::Float);
1087 let cdouble = types.complex(FloatKind::Double);
1088 let cldouble = types.complex(FloatKind::LongDouble);
1089 let double = types.float(FloatKind::Double);
1090 let long_double = types.float(FloatKind::LongDouble);
1091 let float = types.float(FloatKind::Float);
1092 let int = types.int(IntKind::Int);
1093
1094 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1095 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1096 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1097 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1098 }
1099
1100 #[test]
1101 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1102 let mut types = Types::new();
1104 let linux = linux();
1105 let int = types.int(IntKind::Int);
1106 let pointer = types.pointer(int);
1107 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1108 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1109 let void = types.void();
1110 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1111 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1114 }
1115
1116 #[test]
1117 fn the_conversions_read_through_sugar() {
1118 let mut interner = Interner::new();
1119 let mut types = Types::new();
1120 let linux = linux();
1121 let char_ = types.int(IntKind::Char);
1122 let name = types.typedef(interner.intern("byte"), char_);
1123 let int = types.int(IntKind::Int);
1124 assert_eq!(promote(&mut types, name, &linux), int);
1125 }
1126
1127 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1129 let ret = types.void();
1130 types.function(FunctionType { ret, params, variadic, prototyped: true })
1131 }
1132
1133 fn old_style(types: &mut Types) -> TypeId {
1135 let ret = types.void();
1136 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1137 }
1138
1139 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1141 let id = types.declare_record(RecordKind::Struct, Some(tag));
1142 let laid_out = lay_out(types, RecordKind::Struct, fields);
1143 types.complete_record(id, laid_out);
1144 id
1145 }
1146
1147 #[test]
1148 fn a_type_is_compatible_with_itself_however_it_was_written() {
1149 let mut interner = Interner::new();
1150 let mut types = Types::new();
1151 let int = types.int(IntKind::Int);
1152 let name = types.typedef(interner.intern("int32_t"), int);
1153 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1154 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1155
1156 let konst = types.qualified(int, Qualifiers::CONST);
1159 assert!(!compatible(&types, konst, int));
1160 let konst_pointer = types.pointer(konst);
1161 let pointer = types.pointer(int);
1162 assert!(!compatible(&types, konst_pointer, pointer));
1163 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1164
1165 let char_ = types.int(IntKind::Char);
1168 let schar = types.int(IntKind::SChar);
1169 assert!(!compatible(&types, char_, schar));
1170 let atomic = types.atomic(int);
1172 assert!(!compatible(&types, atomic, int));
1173 }
1174
1175 #[test]
1176 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1177 let mut types = Types::new();
1180 let uint = types.int(IntKind::UInt);
1181 let int = types.int(IntKind::Int);
1182 let id = types.declare_enum(None);
1183 types.complete_enum(id, uint, false);
1184 let e = types.enumeration(id);
1185 assert!(compatible(&types, e, uint));
1186 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1187 assert!(!compatible(&types, e, int));
1188
1189 let other = types.declare_enum(None);
1192 types.complete_enum(other, uint, false);
1193 let other = types.enumeration(other);
1194 assert!(!compatible(&types, e, other));
1195
1196 let undecided = types.declare_enum(None);
1199 let undecided = types.enumeration(undecided);
1200 assert!(!compatible(&types, undecided, uint));
1201 assert!(compatible(&types, undecided, undecided));
1202 }
1203
1204 #[test]
1205 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1206 let mut types = Types::new();
1209 let int = types.int(IntKind::Int);
1210 let unknown = types.array(int, ArrayLen::Unknown);
1211 let four = types.array(int, ArrayLen::Fixed(4));
1212 let five = types.array(int, ArrayLen::Fixed(5));
1213 assert!(compatible(&types, unknown, four));
1214 assert!(!compatible(&types, four, five));
1215 assert_eq!(composite(&mut types, unknown, four), Some(four));
1216 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1217 assert_eq!(composite(&mut types, four, five), None);
1218
1219 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1222 assert!(compatible(&types, vla, four));
1223 assert_eq!(composite(&mut types, vla, four), Some(four));
1224
1225 let long = types.int(IntKind::Long);
1227 let longs = types.array(long, ArrayLen::Fixed(4));
1228 assert!(!compatible(&types, four, longs));
1229 }
1230
1231 #[test]
1232 fn a_parameter_declared_as_an_array_is_a_pointer() {
1233 let mut types = Types::new();
1237 let int = types.int(IntKind::Int);
1238 let three = types.array(int, ArrayLen::Fixed(3));
1239 let pointer = types.pointer(int);
1240 assert_eq!(adjust_parameter(&mut types, three), pointer);
1241
1242 let function = prototype(&mut types, vec![int], false);
1244 let function_pointer = types.pointer(function);
1245 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1246
1247 let konst = types.qualified(int, Qualifiers::CONST);
1250 assert_eq!(adjust_parameter(&mut types, konst), int);
1251 let to_konst = types.pointer(konst);
1252 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1253 }
1254
1255 #[test]
1256 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1257 let mut types = Types::new();
1261 let old = old_style(&mut types);
1262 let int = types.int(IntKind::Int);
1263 let long = types.int(IntKind::Long);
1264 let char_ = types.int(IntKind::Char);
1265 let float = types.float(FloatKind::Float);
1266 let double = types.float(FloatKind::Double);
1267
1268 let takes_int = prototype(&mut types, vec![int], false);
1269 assert!(compatible(&types, old, takes_int));
1270 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1271 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1273
1274 let pointer = types.pointer(int);
1275 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1276 let ty = prototype(&mut types, params, false);
1277 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1278 }
1279
1280 for params in [vec![char_], vec![float], vec![int, char_]] {
1283 let ty = prototype(&mut types, params, false);
1284 assert!(!compatible(&types, old, ty));
1285 assert_eq!(composite(&mut types, old, ty), None);
1286 }
1287
1288 let variadic = prototype(&mut types, vec![int], true);
1290 assert!(!compatible(&types, old, variadic));
1291
1292 let uint = types.int(IntKind::UInt);
1294 let id = types.declare_enum(None);
1295 types.complete_enum(id, uint, false);
1296 let e = types.enumeration(id);
1297 let takes_enum = prototype(&mut types, vec![e], false);
1298 assert!(compatible(&types, old, takes_enum));
1299
1300 assert!(compatible(&types, old, old));
1302
1303 let returns_int = types.function(FunctionType {
1305 ret: int,
1306 params: Vec::new(),
1307 variadic: false,
1308 prototyped: false,
1309 });
1310 assert!(!compatible(&types, returns_int, takes_int));
1311 }
1312
1313 #[test]
1314 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1315 let mut types = Types::new();
1319 let int = types.int(IntKind::Int);
1320 let takes_int = prototype(&mut types, vec![int], false);
1321 let takes_nothing = prototype(&mut types, Vec::new(), false);
1322 let old = old_style(&mut types);
1323 assert!(!compatible(&types, takes_nothing, takes_int));
1324 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1325 }
1326
1327 #[test]
1328 fn two_prototypes_have_to_agree_about_everything() {
1329 let mut types = Types::new();
1330 let int = types.int(IntKind::Int);
1331 let long = types.int(IntKind::Long);
1332 let base = prototype(&mut types, vec![int, int], false);
1333 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1334 let other = prototype(&mut types, other, false);
1335 assert!(!compatible(&types, base, other));
1336 }
1337 let variadic = prototype(&mut types, vec![int, int], true);
1338 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1339
1340 let four = types.array(int, ArrayLen::Fixed(4));
1343 let unknown = types.array(int, ArrayLen::Unknown);
1344 let to_four = types.pointer(four);
1345 let to_unknown = types.pointer(unknown);
1346 let a = prototype(&mut types, vec![to_four], false);
1347 let b = prototype(&mut types, vec![to_unknown], false);
1348 assert!(compatible(&types, a, b));
1349 assert_eq!(composite(&mut types, a, b), Some(a));
1351 }
1352
1353 #[test]
1354 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1355 let mut types = Types::new();
1356 let int = types.int(IntKind::Int);
1357 let four = types.array(int, ArrayLen::Fixed(4));
1358 let unknown = types.array(int, ArrayLen::Unknown);
1359 let to_four = types.pointer(four);
1360 let to_unknown = types.pointer(unknown);
1361 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1362
1363 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1365 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1366 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1367 }
1368
1369 #[test]
1370 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1371 let mut interner = Interner::new();
1375 let mut types = Types::new();
1376 let tag = interner.intern("point");
1377 let x = interner.intern("x");
1378 let y = interner.intern("y");
1379 let int = types.int(IntKind::Int);
1380 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1381
1382 let first = tagged(&mut types, tag, &members);
1383 let second = tagged(&mut types, tag, &members);
1384 let first = types.record(first);
1385 let second = types.record(second);
1386 assert_ne!(first, second, "still two declarations and two types");
1387 assert!(compatible(&types, first, second));
1388
1389 let z = interner.intern("z");
1392 let long = types.int(IntKind::Long);
1393 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1394 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1395 for other in [&renamed[..], &retyped[..], &members[..1]] {
1396 let other = tagged(&mut types, tag, other);
1397 let other = types.record(other);
1398 assert!(!compatible(&types, first, other));
1399 }
1400 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1401 let elsewhere = types.record(elsewhere);
1402 assert!(!compatible(&types, first, elsewhere));
1403
1404 let anonymous = record(&mut types, RecordKind::Struct, &members);
1407 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1408 assert!(!compatible(&types, anonymous, also_anonymous));
1409
1410 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1412 let incomplete = types.record(incomplete);
1413 assert!(!compatible(&types, first, incomplete));
1414 assert!(compatible(&types, incomplete, incomplete));
1415 }
1416
1417 #[test]
1418 fn a_self_referential_record_is_compared_without_going_round_forever() {
1419 let mut interner = Interner::new();
1423 let mut types = Types::new();
1424 let tag = interner.intern("node");
1425 let value = interner.intern("value");
1426 let next = interner.intern("next");
1427 let int = types.int(IntKind::Int);
1428
1429 let node = |types: &mut Types| {
1430 let id = types.declare_record(RecordKind::Struct, Some(tag));
1431 let ty = types.record(id);
1432 let pointer = types.pointer(ty);
1433 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1434 let laid_out = lay_out(types, RecordKind::Struct, &members);
1435 types.complete_record(id, laid_out);
1436 ty
1437 };
1438 let first = node(&mut types);
1439 let second = node(&mut types);
1440 assert_ne!(first, second);
1441 assert!(compatible(&types, first, second));
1442
1443 let id = types.declare_record(RecordKind::Struct, Some(tag));
1446 let ty = types.record(id);
1447 let pointer = types.pointer(ty);
1448 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1449 let laid_out = lay_out(&types, RecordKind::Struct, &members);
1450 types.complete_record(id, laid_out);
1451 assert!(!compatible(&types, first, ty));
1452 }
1453
1454 #[test]
1455 fn layout_reads_through_sugar() {
1456 let mut interner = Interner::new();
1457 let mut types = Types::new();
1458 let long = types.int(IntKind::Long);
1459 let name = types.typedef(interner.intern("word"), long);
1460 let array = types.array(name, ArrayLen::Fixed(4));
1461 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1462 }
1463}