1#![doc(html_root_url = "https://docs.rs/rucc-types/0.2.6")]
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::{Layout, LayoutError, float_width, int_width, layout};
104pub use crate::print::{declare, spell};
105pub use crate::record::{
106 Field, FieldDecl, RecordError, RecordLayout, RecordOptions, layout_record,
107};
108pub use crate::types::{EnumInfo, RecordInfo, TypeId, Types};
109
110pub const MILESTONE: &str = "M2";
112
113#[cfg(test)]
114mod tests {
115 use rucc_base::{Interner, Symbol};
116 use rucc_target::{TargetInfo, Triple};
117
118 use super::*;
119
120 fn target(triple: &str) -> TargetInfo {
121 TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
122 }
123
124 fn linux() -> TargetInfo {
125 target("x86_64-unknown-linux-gnu")
126 }
127
128 fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
130 layout_record(types, kind, fields, &RecordOptions::default(), &linux())
131 .expect("a record every member of which has a layout")
132 }
133
134 fn offsets(laid_out: &RecordLayout) -> Vec<u64> {
137 laid_out.fields.iter().map(|field| field.offset).collect()
138 }
139
140 fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
142 let id = types.declare_record(kind, None);
143 let laid_out = lay_out(types, kind, fields);
144 types.complete_record(id, laid_out);
145 types.record(id)
146 }
147
148 fn member(ty: TypeId) -> FieldDecl {
150 FieldDecl::new(None, ty)
151 }
152
153 fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
156 FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
157 }
158
159 fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
161 FieldDecl::bit_field(None, ty, width)
162 }
163
164 #[test]
165 fn milestone_is_recorded() {
166 assert!(MILESTONE.starts_with('M'));
167 }
168
169 #[test]
170 fn the_same_type_asked_for_twice_is_the_same_id() {
171 let mut types = Types::new();
172 let a = types.pointer(types.int(IntKind::Int));
173 let b = types.pointer(types.int(IntKind::Int));
174 assert_eq!(a, b, "interning is what makes type identity an integer comparison");
175 let c = types.pointer(types.int(IntKind::Long));
176 assert_ne!(a, c);
177 }
178
179 #[test]
180 fn a_qualifier_makes_a_different_type_with_the_same_shape() {
181 let mut types = Types::new();
182 let int = types.int(IntKind::Int);
183 let konst = types.qualified(int, Qualifiers::CONST);
184 assert_ne!(int, konst);
185 assert_eq!(types.kind(konst), types.kind(int));
186 assert!(types.quals(konst).has(Qualifiers::CONST));
187 assert_eq!(types.unqualified(konst), int);
188 }
189
190 #[test]
191 fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
192 let mut types = Types::new();
193 let int = types.int(IntKind::Int);
194 let a = types.qualified(int, Qualifiers::CONST);
195 let a = types.qualified(a, Qualifiers::VOLATILE);
196 let b = types.qualified(int, Qualifiers::VOLATILE);
197 let b = types.qualified(b, Qualifiers::CONST);
198 assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
199 }
200
201 #[test]
202 fn qualifying_an_array_qualifies_its_element() {
203 let mut types = Types::new();
206 let int = types.int(IntKind::Int);
207 let array = types.array(int, ArrayLen::Fixed(4));
208 let konst = types.qualified(array, Qualifiers::CONST);
209 assert!(types.quals(konst).is_none(), "the array itself is unqualified");
210 let TypeKind::Array { elem, len } = types.kind(konst) else {
211 panic!("still an array");
212 };
213 assert_eq!(len, ArrayLen::Fixed(4));
214 assert!(types.quals(elem).has(Qualifiers::CONST));
215 }
216
217 #[test]
218 fn a_typedef_is_a_different_type_that_means_the_same_thing() {
219 let mut interner = Interner::new();
220 let mut types = Types::new();
221 let int = types.int(IntKind::Int);
222 let name = types.typedef(interner.intern("int32_t"), int);
223 assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
224 assert_eq!(types.canonical(name), int, "and no rule ever sees it");
225 assert!(types.is_sugar(name));
226 assert!(!types.is_sugar(int));
227 }
228
229 #[test]
230 fn sugar_below_the_outermost_node_is_resolved_too() {
231 let mut interner = Interner::new();
234 let mut types = Types::new();
235 let int = types.int(IntKind::Int);
236 let name = types.typedef(interner.intern("int32_t"), int);
237 let sugar_pointer = types.pointer(name);
238 let plain_pointer = types.pointer(int);
239 assert_ne!(sugar_pointer, plain_pointer);
240 assert_eq!(types.canonical(sugar_pointer), plain_pointer);
241
242 let sugar_array = types.array(name, ArrayLen::Fixed(3));
243 let plain_array = types.array(int, ArrayLen::Fixed(3));
244 assert_eq!(types.canonical(sugar_array), plain_array);
245 }
246
247 #[test]
248 fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
249 let mut interner = Interner::new();
250 let mut types = Types::new();
251 let int = types.int(IntKind::Int);
252 let mut current = int;
253 for i in 0..8 {
254 current = types.typedef(interner.intern(&format!("t{i}")), current);
255 }
256 assert_eq!(types.canonical(current), int);
257 }
258
259 #[test]
260 fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
261 let mut interner = Interner::new();
262 let mut types = Types::new();
263 let int = types.int(IntKind::Int);
264 let name = types.typedef(interner.intern("int32_t"), int);
265 let konst = types.qualified(name, Qualifiers::CONST);
266 assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
267 let want = types.qualified(int, Qualifiers::CONST);
268 assert_eq!(types.canonical(konst), want);
269 }
270
271 #[test]
272 fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
273 let mut interner = Interner::new();
276 let mut types = Types::new();
277 let int = types.int(IntKind::Int);
278 let array = types.array(int, ArrayLen::Fixed(4));
279 let name = types.typedef(interner.intern("A"), array);
280 let konst = types.qualified(name, Qualifiers::CONST);
281 let konst_int = types.qualified(int, Qualifiers::CONST);
282 let want = types.array(konst_int, ArrayLen::Fixed(4));
283 assert_eq!(types.canonical(konst), want);
284 }
285
286 #[test]
287 fn a_function_type_is_deduplicated_by_its_signature() {
288 let mut types = Types::new();
289 let int = types.int(IntKind::Int);
290 let long = types.int(IntKind::Long);
291 let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
292 types.function(FunctionType { ret: int, params, variadic, prototyped: true })
293 };
294 let a = make(&mut types, vec![int, long], false);
295 let b = make(&mut types, vec![int, long], false);
296 assert_eq!(a, b);
297 assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
298 assert_ne!(a, make(&mut types, vec![long, int], false));
299 }
300
301 #[test]
302 fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
303 let mut interner = Interner::new();
304 let mut types = Types::new();
305 let int = types.int(IntKind::Int);
306 let name = types.typedef(interner.intern("int32_t"), int);
307 let sugar = types.function(FunctionType {
308 ret: name,
309 params: vec![name],
310 variadic: false,
311 prototyped: true,
312 });
313 let plain = types.function(FunctionType {
314 ret: int,
315 params: vec![int],
316 variadic: false,
317 prototyped: true,
318 });
319 assert_ne!(sugar, plain);
320 assert_eq!(types.canonical(sugar), plain);
321 }
322
323 #[test]
324 fn a_record_is_its_declaration_and_not_its_members() {
325 let mut interner = Interner::new();
329 let mut types = Types::new();
330 let tag = interner.intern("point");
331 let first = types.declare_record(RecordKind::Struct, Some(tag));
332 let second = types.declare_record(RecordKind::Struct, Some(tag));
333 assert_ne!(types.record(first), types.record(second));
334 assert_eq!(types.record(first), types.record(first));
335 }
336
337 #[test]
338 fn a_record_has_no_layout_until_it_has_been_completed() {
339 let mut types = Types::new();
340 let id = types.declare_record(RecordKind::Struct, None);
341 let ty = types.record(id);
342 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
343 let long_long = types.int(IntKind::LongLong);
344 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
345 types.complete_record(id, laid_out);
346 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
347 }
348
349 #[test]
350 fn an_enum_takes_the_layout_of_its_underlying_type() {
351 let mut types = Types::new();
352 let id = types.declare_enum(None);
353 let ty = types.enumeration(id);
354 assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
355 let int = types.int(IntKind::Int);
356 types.complete_enum(id, int, false);
357 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
358 }
359
360 #[test]
361 fn the_scalar_widths_come_from_the_target() {
362 let mut types = Types::new();
363 let linux = linux();
364 let windows = target("x86_64-pc-windows-msvc");
365 let darwin = target("aarch64-apple-darwin");
366
367 let long = types.int(IntKind::Long);
368 assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
369 assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
370
371 let ldouble = types.float(FloatKind::LongDouble);
372 assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
373 assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
374
375 let pointer = types.pointer(types.void());
376 assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
377
378 let boolean = types.boolean();
379 assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
380 }
381
382 #[test]
383 fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
384 let mut types = Types::new();
387 let linux = linux();
388 let cfloat = types.complex(FloatKind::Float);
389 assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
390 let cdouble = types.complex(FloatKind::Double);
391 assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
392 let cldouble = types.complex(FloatKind::LongDouble);
393 assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
394 let darwin = target("aarch64-apple-darwin");
395 assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
396 }
397
398 #[test]
399 fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
400 let mut types = Types::new();
403 let linux = linux();
404 let long_long = types.int(IntKind::LongLong);
405 let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
406 let atomic = types.atomic(plain);
407 assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
408 assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
409
410 let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
412 let atomic_odd = types.atomic(odd);
413 assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
414
415 let int = types.int(IntKind::Int);
416 let atomic_int = types.atomic(int);
417 assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
418 }
419
420 #[test]
421 fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
422 let mut types = Types::new();
425 let linux = linux();
426 let darwin = target("aarch64-apple-darwin");
427 let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
428 for (width, size, align) in cases {
429 let ty = types.bit_int(true, width);
430 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
431 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
432 }
433 for width in [65, 96, 128] {
434 let ty = types.bit_int(false, width);
435 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
436 assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
437 }
438 let wide = types.bit_int(true, 129);
439 assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
440 assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
441 }
442
443 #[test]
444 fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
445 let mut types = Types::new();
446 let linux = linux();
447 let int = types.int(IntKind::Int);
448 let ty = types.array(int, ArrayLen::Fixed(10));
449 assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
450 let nested = types.array(ty, ArrayLen::Fixed(3));
451 assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
452 }
453
454 #[test]
455 fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
456 let mut types = Types::new();
457 let linux = linux();
458 let int = types.int(IntKind::Int);
459 for len in [ArrayLen::Unknown, ArrayLen::Star, ArrayLen::Variable(VlaId(0))] {
460 let ty = types.array(int, len);
461 assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
462 }
463 let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
464 assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
465 }
466
467 #[test]
468 fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
469 let mut types = Types::new();
470 let int = types.int(IntKind::Int);
471 let a = types.array(int, ArrayLen::Variable(VlaId(0)));
472 let b = types.array(int, ArrayLen::Variable(VlaId(1)));
473 assert_ne!(a, b);
474 }
475
476 #[test]
477 fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
478 let mut types = Types::new();
481 let linux = linux();
482 let int = types.int(IntKind::Int);
483 let four = types.vector(int, 4);
484 assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
485 let three = types.vector(int, 3);
486 assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
487 let three_chars = types.vector(types.int(IntKind::Char), 3);
488 assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
489 }
490
491 #[test]
492 fn the_types_without_a_size_say_which_kind_of_without_they_are() {
493 let mut types = Types::new();
496 let linux = linux();
497 let void = types.void();
498 assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
499 let int = types.int(IntKind::Int);
500 let function = types.function(FunctionType {
501 ret: int,
502 params: Vec::new(),
503 variadic: false,
504 prototyped: true,
505 });
506 assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
507 let pointer_to_function = types.pointer(function);
508 assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
509 }
510
511 #[test]
512 fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
513 let types = Types::new();
514 let char_ = types.int(IntKind::Char);
515 let int = types.int(IntKind::Int);
516 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
517 assert_eq!(laid_out.layout, Layout::new(8, 4));
518 assert_eq!(offsets(&laid_out), [0, 32]);
519 assert_eq!(laid_out.fields[1].byte_offset(), 4);
520
521 let long_long = types.int(IntKind::LongLong);
523 let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
524 assert_eq!(laid_out.layout, Layout::new(16, 8));
525 }
526
527 #[test]
528 fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
529 let mut types = Types::new();
530 let char_ = types.int(IntKind::Char);
531 let int = types.int(IntKind::Int);
532 let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
533 assert_eq!(laid_out.layout, Layout::new(4, 4));
534 assert_eq!(offsets(&laid_out), [0, 0]);
535
536 let nine = types.array(char_, ArrayLen::Fixed(9));
539 let short = types.int(IntKind::Short);
540 let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
541 assert_eq!(laid_out.layout, Layout::new(10, 2));
542 }
543
544 #[test]
545 fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
546 let mut interner = Interner::new();
549 let types = Types::new();
550 let char_ = types.int(IntKind::Char);
551 let int = types.int(IntKind::Int);
552 let long_long = types.int(IntKind::LongLong);
553
554 let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
555 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
556 assert_eq!(laid_out.layout, Layout::new(4, 4));
557 assert_eq!(offsets(&laid_out), [0, 3]);
558
559 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
561 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
562 assert_eq!(laid_out.layout, Layout::new(8, 4));
563 assert_eq!(offsets(&laid_out), [0, 32]);
564
565 let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
568 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
569 assert_eq!(laid_out.layout, Layout::new(8, 8));
570 assert_eq!(offsets(&laid_out), [0, 8]);
571
572 let fields = [bits(&mut interner, "a", int, 3), member(char_)];
574 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
575 assert_eq!(offsets(&laid_out), [0, 8]);
576 }
577
578 #[test]
579 fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
580 let types = Types::new();
581 let char_ = types.int(IntKind::Char);
582 let int = types.int(IntKind::Int);
583 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
584 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
585 assert_eq!(laid_out.layout, Layout::new(5, 1));
588 assert_eq!(offsets(&laid_out), [0, 32, 32]);
589 assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
590 }
591
592 #[test]
593 fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
594 let mut interner = Interner::new();
595 let types = Types::new();
596 let char_ = types.int(IntKind::Char);
597 let int = types.int(IntKind::Int);
598
599 let unnamed = [member(char_), unnamed_bits(int, 20)];
600 let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
601 assert_eq!(unnamed.layout, Layout::new(4, 1));
602
603 let named = [member(char_), bits(&mut interner, "b", int, 20)];
604 let named = lay_out(&types, RecordKind::Struct, &named);
605 assert_eq!(named.layout, Layout::new(4, 4));
606 assert_eq!(offsets(&named), [0, 8], "the same place either way");
607
608 let wider = [member(char_), unnamed_bits(int, 30)];
611 let wider = lay_out(&types, RecordKind::Struct, &wider);
612 assert_eq!(wider.layout, Layout::new(8, 1));
613 assert_eq!(offsets(&wider), [0, 32]);
614 }
615
616 #[test]
617 fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
618 let mut interner = Interner::new();
619 let types = Types::new();
620 let char_ = types.int(IntKind::Char);
621 let int = types.int(IntKind::Int);
622 let packed = RecordOptions { packed: true, ..RecordOptions::default() };
623
624 let fields = [member(char_), member(int)];
625 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
626 .expect("a packed struct of two complete members");
627 assert_eq!(laid_out.layout, Layout::new(5, 1));
628 assert_eq!(offsets(&laid_out), [0, 8]);
629
630 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
631 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
632 .expect("a packed struct with a bit-field");
633 assert_eq!(laid_out.layout, Layout::new(5, 1));
634 assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
635
636 let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
639 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
640 .expect("a packed struct with a zero width bit-field");
641 assert_eq!(laid_out.layout, Layout::new(5, 1));
642 assert_eq!(offsets(&laid_out), [0, 32, 32]);
643 }
644
645 #[test]
646 fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
647 let mut interner = Interner::new();
648 let types = Types::new();
649 let char_ = types.int(IntKind::Char);
650 let int = types.int(IntKind::Int);
651 let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
652
653 let fields = [member(char_), member(int)];
654 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
655 .expect("a packed struct of two complete members");
656 assert_eq!(laid_out.layout, Layout::new(6, 2));
657 assert_eq!(offsets(&laid_out), [0, 16]);
658
659 let fields = [member(char_), bits(&mut interner, "b", int, 30)];
663 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
664 .expect("a packed struct with a bit-field");
665 assert_eq!(laid_out.layout, Layout::new(6, 2));
666 assert_eq!(offsets(&laid_out), [0, 8]);
667
668 let fields = [member(char_), unnamed_bits(int, 30)];
671 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
672 .expect("a packed struct with an unnamed bit-field");
673 assert_eq!(laid_out.layout, Layout::new(5, 1));
674 }
675
676 #[test]
677 fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
678 let types = Types::new();
679 let char_ = types.int(IntKind::Char);
680 let int = types.int(IntKind::Int);
681
682 let aligned = FieldDecl { align: Some(16), ..member(int) };
683 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
684 assert_eq!(laid_out.layout, Layout::new(32, 16));
685 assert_eq!(offsets(&laid_out), [0, 128]);
686
687 let options = RecordOptions { packed: true, align: Some(4), pack: None };
690 let fields = [member(char_), member(int)];
691 let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
692 .expect("a packed struct with an alignment asked for");
693 assert_eq!(laid_out.layout, Layout::new(8, 4));
694 assert_eq!(offsets(&laid_out), [0, 8]);
695 }
696
697 #[test]
698 fn a_flexible_array_member_costs_nothing_but_its_alignment() {
699 let mut types = Types::new();
701 let char_ = types.int(IntKind::Char);
702 let int = types.int(IntKind::Int);
703 let long_long = types.int(IntKind::LongLong);
704
705 let chars = types.array(char_, ArrayLen::Unknown);
706 let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
707 assert_eq!(laid_out.layout, Layout::new(4, 4));
708 assert_eq!(offsets(&laid_out), [0, 32]);
709
710 let longs = types.array(long_long, ArrayLen::Unknown);
712 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
713 assert_eq!(laid_out.layout, Layout::new(8, 8));
714 assert_eq!(offsets(&laid_out), [0, 64]);
715
716 let fields = [member(chars), member(int)];
718 let error =
719 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
720 assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
721 }
722
723 #[test]
724 fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
725 let types = Types::new();
727 let laid_out = lay_out(&types, RecordKind::Struct, &[]);
728 assert_eq!(laid_out.layout, Layout::new(0, 1));
729 }
730
731 #[test]
732 fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
733 let types = Types::new();
734 let int = types.int(IntKind::Int);
735 let fields = [unnamed_bits(int, 33)];
736 let error =
737 layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
738 let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
739 assert_eq!(error, Err(want));
740 }
741
742 #[test]
743 fn a_record_reports_its_members_once_it_has_been_completed() {
744 let mut interner = Interner::new();
745 let mut types = Types::new();
746 let char_ = types.int(IntKind::Char);
747 let int = types.int(IntKind::Int);
748 let name = interner.intern("count");
749 let fields = [member(char_), FieldDecl::new(Some(name), int)];
750 let id = types.declare_record(RecordKind::Struct, None);
751 let laid_out = lay_out(&types, RecordKind::Struct, &fields);
752 types.complete_record(id, laid_out);
753 let ty = types.record(id);
754 assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
755 let field = types.field(id, name).expect("the member that was declared");
756 assert_eq!(field.byte_offset(), 4);
757 assert!(!field.is_bit_field());
758 assert_eq!(types.field(id, interner.intern("missing")), None);
759 }
760
761 #[test]
762 fn a_nested_record_brings_its_own_alignment_with_it() {
763 let mut types = Types::new();
764 let char_ = types.int(IntKind::Char);
765 let int = types.int(IntKind::Int);
766 let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
767 let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
768 assert_eq!(laid_out.layout, Layout::new(8, 4));
769 assert_eq!(offsets(&laid_out), [0, 32]);
770
771 let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
774 let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
775 assert_eq!(laid_out.layout, Layout::new(12, 4));
776 assert_eq!(offsets(&laid_out), [0, 32]);
777 }
778
779 #[test]
780 fn everything_narrower_than_an_int_promotes_to_one() {
781 let mut types = Types::new();
785 let linux = linux();
786 let int = types.int(IntKind::Int);
787 let narrow =
788 [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
789 for kind in narrow {
790 let ty = types.int(kind);
791 assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
792 }
793 let boolean = types.boolean();
794 assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
795
796 for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
798 let ty = types.int(kind);
799 assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
800 }
801 }
802
803 #[test]
804 fn a_bit_int_is_not_promoted_at_all() {
805 let mut types = Types::new();
808 let linux = linux();
809 let small = types.bit_int(true, 8);
810 assert_eq!(promote(&mut types, small, &linux), small);
811 assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
812 }
813
814 #[test]
815 fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
816 let mut types = Types::new();
817 let linux = linux();
818 let int = types.int(IntKind::Int);
819 let uint = types.int(IntKind::UInt);
820 let ullong = types.int(IntKind::ULongLong);
821
822 assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
824 assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
826 assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
828 assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), ullong);
831 }
832
833 #[test]
834 fn an_enumeration_promotes_through_what_it_is_represented_in() {
835 let mut types = Types::new();
836 let linux = linux();
837 let int = types.int(IntKind::Int);
838 let short = types.int(IntKind::Short);
839 let uint = types.int(IntKind::UInt);
840
841 let fixed = types.declare_enum(None);
843 types.complete_enum(fixed, short, true);
844 let fixed = types.enumeration(fixed);
845 assert_eq!(promote(&mut types, fixed, &linux), int);
846
847 let unsigned = types.declare_enum(None);
850 types.complete_enum(unsigned, uint, false);
851 let unsigned = types.enumeration(unsigned);
852 assert_eq!(promote(&mut types, unsigned, &linux), uint);
853
854 let undecided = types.declare_enum(None);
857 let undecided = types.enumeration(undecided);
858 assert_eq!(promote(&mut types, undecided, &linux), int);
859 }
860
861 #[test]
862 fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
863 let mut types = Types::new();
866 let linux = linux();
867 let int = types.int(IntKind::Int);
868 let konst = types.qualified(int, Qualifiers::CONST);
869 let atomic = types.atomic(konst);
870 assert_eq!(promote(&mut types, atomic, &linux), int);
871 assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
872 }
873
874 #[test]
875 fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
876 let mut types = Types::new();
878 let linux = linux();
879 let cases = [
880 (IntKind::Int, IntKind::UInt, IntKind::UInt),
881 (IntKind::Int, IntKind::Long, IntKind::Long),
882 (IntKind::UInt, IntKind::Long, IntKind::Long),
883 (IntKind::UInt, IntKind::ULong, IntKind::ULong),
884 (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
885 (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
886 (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
887 (IntKind::Char, IntKind::Char, IntKind::Int),
888 (IntKind::UChar, IntKind::UShort, IntKind::Int),
889 ];
890 for (left, right, want) in cases {
891 let left = types.int(left);
892 let right = types.int(right);
893 let want = types.int(want);
894 assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
895 assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
896 }
897 }
898
899 #[test]
900 fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
901 let mut types = Types::new();
905 let linux = linux();
906 let signed = types.int(IntKind::Int128);
907 let unsigned = types.int(IntKind::UInt128);
908 for id in [signed, unsigned] {
909 let laid_out = layout(&types, id, &linux).expect("a complete type");
910 assert_eq!(laid_out.size, 16);
911 assert_eq!(laid_out.align, 16);
912 }
913
914 let ull = types.int(IntKind::ULongLong);
918 assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
919 assert_eq!(promote(&mut types, signed, &linux), signed);
921 }
922
923 #[test]
924 fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
925 let mut types = Types::new();
928 let linux = linux();
929 let int128 = types.int(IntKind::Int128);
930 let bit_int = types.bit_int(true, 128);
931 assert_ne!(int128, bit_int);
932 assert!(!compatible(&types, int128, bit_int));
933 assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
934 assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
935 }
936
937 #[test]
938 fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
939 let mut types = Types::new();
943 let linux = linux();
944 let ulong = types.int(IntKind::ULong);
945 let long_long = types.int(IntKind::LongLong);
946 let want = types.int(IntKind::ULongLong);
947 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
948
949 let windows = target("x86_64-pc-windows-msvc");
953 assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
954 }
955
956 #[test]
957 fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
958 let mut types = Types::new();
960 let linux = linux();
961 let b40 = types.bit_int(true, 40);
962 let ub40 = types.bit_int(false, 40);
963 let b8 = types.bit_int(true, 8);
964 let b32 = types.bit_int(true, 32);
965 let int = types.int(IntKind::Int);
966 let uint = types.int(IntKind::UInt);
967 let long = types.int(IntKind::Long);
968 let char_ = types.int(IntKind::Char);
969
970 assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
972 assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
974 assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
976 assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
977 assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
980 assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
983 assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
984 assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
986 }
987
988 #[test]
989 fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
990 let mut types = Types::new();
991 let linux = linux();
992 let float = types.float(FloatKind::Float);
993 let double = types.float(FloatKind::Double);
994 let long_double = types.float(FloatKind::LongDouble);
995 let ullong = types.int(IntKind::ULongLong);
996 let int = types.int(IntKind::Int);
997
998 assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
999 assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1000 assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1001 assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1004 }
1005
1006 #[test]
1007 fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1008 let mut types = Types::new();
1009 let linux = linux();
1010 let cfloat = types.complex(FloatKind::Float);
1011 let cdouble = types.complex(FloatKind::Double);
1012 let cldouble = types.complex(FloatKind::LongDouble);
1013 let double = types.float(FloatKind::Double);
1014 let long_double = types.float(FloatKind::LongDouble);
1015 let float = types.float(FloatKind::Float);
1016 let int = types.int(IntKind::Int);
1017
1018 assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1019 assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1020 assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1021 assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1022 }
1023
1024 #[test]
1025 fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1026 let mut types = Types::new();
1028 let linux = linux();
1029 let int = types.int(IntKind::Int);
1030 let pointer = types.pointer(int);
1031 assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1032 assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1033 let void = types.void();
1034 assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1035 assert_eq!(promote(&mut types, pointer, &linux), pointer);
1038 }
1039
1040 #[test]
1041 fn the_conversions_read_through_sugar() {
1042 let mut interner = Interner::new();
1043 let mut types = Types::new();
1044 let linux = linux();
1045 let char_ = types.int(IntKind::Char);
1046 let name = types.typedef(interner.intern("byte"), char_);
1047 let int = types.int(IntKind::Int);
1048 assert_eq!(promote(&mut types, name, &linux), int);
1049 }
1050
1051 fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1053 let ret = types.void();
1054 types.function(FunctionType { ret, params, variadic, prototyped: true })
1055 }
1056
1057 fn old_style(types: &mut Types) -> TypeId {
1059 let ret = types.void();
1060 types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1061 }
1062
1063 fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1065 let id = types.declare_record(RecordKind::Struct, Some(tag));
1066 let laid_out = lay_out(types, RecordKind::Struct, fields);
1067 types.complete_record(id, laid_out);
1068 id
1069 }
1070
1071 #[test]
1072 fn a_type_is_compatible_with_itself_however_it_was_written() {
1073 let mut interner = Interner::new();
1074 let mut types = Types::new();
1075 let int = types.int(IntKind::Int);
1076 let name = types.typedef(interner.intern("int32_t"), int);
1077 assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1078 assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1079
1080 let konst = types.qualified(int, Qualifiers::CONST);
1083 assert!(!compatible(&types, konst, int));
1084 let konst_pointer = types.pointer(konst);
1085 let pointer = types.pointer(int);
1086 assert!(!compatible(&types, konst_pointer, pointer));
1087 assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1088
1089 let char_ = types.int(IntKind::Char);
1092 let schar = types.int(IntKind::SChar);
1093 assert!(!compatible(&types, char_, schar));
1094 let atomic = types.atomic(int);
1096 assert!(!compatible(&types, atomic, int));
1097 }
1098
1099 #[test]
1100 fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1101 let mut types = Types::new();
1104 let uint = types.int(IntKind::UInt);
1105 let int = types.int(IntKind::Int);
1106 let id = types.declare_enum(None);
1107 types.complete_enum(id, uint, false);
1108 let e = types.enumeration(id);
1109 assert!(compatible(&types, e, uint));
1110 assert!(compatible(&types, uint, e), "and the relation is symmetric");
1111 assert!(!compatible(&types, e, int));
1112
1113 let other = types.declare_enum(None);
1116 types.complete_enum(other, uint, false);
1117 let other = types.enumeration(other);
1118 assert!(!compatible(&types, e, other));
1119
1120 let undecided = types.declare_enum(None);
1123 let undecided = types.enumeration(undecided);
1124 assert!(!compatible(&types, undecided, uint));
1125 assert!(compatible(&types, undecided, undecided));
1126 }
1127
1128 #[test]
1129 fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1130 let mut types = Types::new();
1133 let int = types.int(IntKind::Int);
1134 let unknown = types.array(int, ArrayLen::Unknown);
1135 let four = types.array(int, ArrayLen::Fixed(4));
1136 let five = types.array(int, ArrayLen::Fixed(5));
1137 assert!(compatible(&types, unknown, four));
1138 assert!(!compatible(&types, four, five));
1139 assert_eq!(composite(&mut types, unknown, four), Some(four));
1140 assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1141 assert_eq!(composite(&mut types, four, five), None);
1142
1143 let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1146 assert!(compatible(&types, vla, four));
1147 assert_eq!(composite(&mut types, vla, four), Some(four));
1148
1149 let long = types.int(IntKind::Long);
1151 let longs = types.array(long, ArrayLen::Fixed(4));
1152 assert!(!compatible(&types, four, longs));
1153 }
1154
1155 #[test]
1156 fn a_parameter_declared_as_an_array_is_a_pointer() {
1157 let mut types = Types::new();
1161 let int = types.int(IntKind::Int);
1162 let three = types.array(int, ArrayLen::Fixed(3));
1163 let pointer = types.pointer(int);
1164 assert_eq!(adjust_parameter(&mut types, three), pointer);
1165
1166 let function = prototype(&mut types, vec![int], false);
1168 let function_pointer = types.pointer(function);
1169 assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1170
1171 let konst = types.qualified(int, Qualifiers::CONST);
1174 assert_eq!(adjust_parameter(&mut types, konst), int);
1175 let to_konst = types.pointer(konst);
1176 assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1177 }
1178
1179 #[test]
1180 fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1181 let mut types = Types::new();
1185 let old = old_style(&mut types);
1186 let int = types.int(IntKind::Int);
1187 let long = types.int(IntKind::Long);
1188 let char_ = types.int(IntKind::Char);
1189 let float = types.float(FloatKind::Float);
1190 let double = types.float(FloatKind::Double);
1191
1192 let takes_int = prototype(&mut types, vec![int], false);
1193 assert!(compatible(&types, old, takes_int));
1194 assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1195 assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1197
1198 let pointer = types.pointer(int);
1199 for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1200 let ty = prototype(&mut types, params, false);
1201 assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1202 }
1203
1204 for params in [vec![char_], vec![float], vec![int, char_]] {
1207 let ty = prototype(&mut types, params, false);
1208 assert!(!compatible(&types, old, ty));
1209 assert_eq!(composite(&mut types, old, ty), None);
1210 }
1211
1212 let variadic = prototype(&mut types, vec![int], true);
1214 assert!(!compatible(&types, old, variadic));
1215
1216 let uint = types.int(IntKind::UInt);
1218 let id = types.declare_enum(None);
1219 types.complete_enum(id, uint, false);
1220 let e = types.enumeration(id);
1221 let takes_enum = prototype(&mut types, vec![e], false);
1222 assert!(compatible(&types, old, takes_enum));
1223
1224 assert!(compatible(&types, old, old));
1226
1227 let returns_int = types.function(FunctionType {
1229 ret: int,
1230 params: Vec::new(),
1231 variadic: false,
1232 prototyped: false,
1233 });
1234 assert!(!compatible(&types, returns_int, takes_int));
1235 }
1236
1237 #[test]
1238 fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1239 let mut types = Types::new();
1243 let int = types.int(IntKind::Int);
1244 let takes_int = prototype(&mut types, vec![int], false);
1245 let takes_nothing = prototype(&mut types, Vec::new(), false);
1246 let old = old_style(&mut types);
1247 assert!(!compatible(&types, takes_nothing, takes_int));
1248 assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1249 }
1250
1251 #[test]
1252 fn two_prototypes_have_to_agree_about_everything() {
1253 let mut types = Types::new();
1254 let int = types.int(IntKind::Int);
1255 let long = types.int(IntKind::Long);
1256 let base = prototype(&mut types, vec![int, int], false);
1257 for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1258 let other = prototype(&mut types, other, false);
1259 assert!(!compatible(&types, base, other));
1260 }
1261 let variadic = prototype(&mut types, vec![int, int], true);
1262 assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1263
1264 let four = types.array(int, ArrayLen::Fixed(4));
1267 let unknown = types.array(int, ArrayLen::Unknown);
1268 let to_four = types.pointer(four);
1269 let to_unknown = types.pointer(unknown);
1270 let a = prototype(&mut types, vec![to_four], false);
1271 let b = prototype(&mut types, vec![to_unknown], false);
1272 assert!(compatible(&types, a, b));
1273 assert_eq!(composite(&mut types, a, b), Some(a));
1275 }
1276
1277 #[test]
1278 fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1279 let mut types = Types::new();
1280 let int = types.int(IntKind::Int);
1281 let four = types.array(int, ArrayLen::Fixed(4));
1282 let unknown = types.array(int, ArrayLen::Unknown);
1283 let to_four = types.pointer(four);
1284 let to_unknown = types.pointer(unknown);
1285 assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1286
1287 let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1289 let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1290 assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1291 }
1292
1293 #[test]
1294 fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1295 let mut interner = Interner::new();
1299 let mut types = Types::new();
1300 let tag = interner.intern("point");
1301 let x = interner.intern("x");
1302 let y = interner.intern("y");
1303 let int = types.int(IntKind::Int);
1304 let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1305
1306 let first = tagged(&mut types, tag, &members);
1307 let second = tagged(&mut types, tag, &members);
1308 let first = types.record(first);
1309 let second = types.record(second);
1310 assert_ne!(first, second, "still two declarations and two types");
1311 assert!(compatible(&types, first, second));
1312
1313 let z = interner.intern("z");
1316 let long = types.int(IntKind::Long);
1317 let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1318 let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1319 for other in [&renamed[..], &retyped[..], &members[..1]] {
1320 let other = tagged(&mut types, tag, other);
1321 let other = types.record(other);
1322 assert!(!compatible(&types, first, other));
1323 }
1324 let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1325 let elsewhere = types.record(elsewhere);
1326 assert!(!compatible(&types, first, elsewhere));
1327
1328 let anonymous = record(&mut types, RecordKind::Struct, &members);
1331 let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1332 assert!(!compatible(&types, anonymous, also_anonymous));
1333
1334 let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1336 let incomplete = types.record(incomplete);
1337 assert!(!compatible(&types, first, incomplete));
1338 assert!(compatible(&types, incomplete, incomplete));
1339 }
1340
1341 #[test]
1342 fn a_self_referential_record_is_compared_without_going_round_forever() {
1343 let mut interner = Interner::new();
1347 let mut types = Types::new();
1348 let tag = interner.intern("node");
1349 let value = interner.intern("value");
1350 let next = interner.intern("next");
1351 let int = types.int(IntKind::Int);
1352
1353 let node = |types: &mut Types| {
1354 let id = types.declare_record(RecordKind::Struct, Some(tag));
1355 let ty = types.record(id);
1356 let pointer = types.pointer(ty);
1357 let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1358 let laid_out = lay_out(types, RecordKind::Struct, &members);
1359 types.complete_record(id, laid_out);
1360 ty
1361 };
1362 let first = node(&mut types);
1363 let second = node(&mut types);
1364 assert_ne!(first, second);
1365 assert!(compatible(&types, first, second));
1366
1367 let id = types.declare_record(RecordKind::Struct, Some(tag));
1370 let ty = types.record(id);
1371 let pointer = types.pointer(ty);
1372 let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1373 let laid_out = lay_out(&types, RecordKind::Struct, &members);
1374 types.complete_record(id, laid_out);
1375 assert!(!compatible(&types, first, ty));
1376 }
1377
1378 #[test]
1379 fn layout_reads_through_sugar() {
1380 let mut interner = Interner::new();
1381 let mut types = Types::new();
1382 let long = types.int(IntKind::Long);
1383 let name = types.typedef(interner.intern("word"), long);
1384 let array = types.array(name, ArrayLen::Fixed(4));
1385 assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1386 }
1387}