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