Skip to main content

rucc_types/
lib.rs

1//! The C type system, interned, and layout computation.
2//!
3//! Design: `spec/07-types-and-semantics.md`. Layer rank 2, see `spec/18-package-layout.md`.
4//!
5//! There is one [`Types`] per translation unit and it owns every type in it. A [`TypeId`] is
6//! four bytes and two of them are equal exactly when they are the same type, which turns the
7//! question the compiler asks more often than any other into an integer comparison.
8//!
9//! Two ideas shape the rest of it.
10//!
11//! **Sugar is kept and never decided on.** `typedef int32_t;` gives a node that remembers the
12//! name and points at canonical `int`. Every semantic rule reads [`Types::canonical`] and sees
13//! `int`; every diagnostic reads the type as it was written and says `int32_t`. Compilers that
14//! throw the name away produce messages nobody can act on, and compilers that decide on the
15//! name produce wrong answers, and both are common. Sugar is not only at the outermost node,
16//! so `int32_t *` and `int32_t[4]` are sugar too and canonicalising rebuilds them.
17//!
18//! **`_Atomic` is a type, not a qualifier.** `const` and `volatile` and `restrict` are a
19//! bitmask in the interning key, because nothing about them changes what an object is. C lets
20//! `_Atomic` be written in the same position, but `_Atomic(T)` can have a different alignment
21//! from `T`, so it is a type constructor here and the parser is what maps the spelling onto
22//! it. Document 01 recorded a compiler that treated it as a qualifier and lost track of it,
23//! which is exactly the shortcut that makes atomics silently wrong.
24//!
25//! Layout comes out of [`TargetInfo`](rucc_target::TargetInfo) and never out of the host.
26//! `long` is four bytes on Windows and eight on Linux, and `long double` is eight bytes on
27//! Apple and sixteen on SysV x86-64, so a cross compiler that asks its own platform is wrong
28//! twice before it has read a line of C.
29//!
30//! ```
31//! use rucc_target::{TargetInfo, Triple};
32//! use rucc_types::{IntKind, Types, layout};
33//!
34//! let mut types = Types::new();
35//! let linux = TargetInfo::new("x86_64-unknown-linux-gnu".parse::<Triple>().unwrap());
36//! let windows = TargetInfo::new("x86_64-pc-windows-msvc".parse::<Triple>().unwrap());
37//!
38//! let long = types.int(IntKind::Long);
39//! assert_eq!(layout(&types, long, &linux).unwrap().size, 8);
40//! assert_eq!(layout(&types, long, &windows).unwrap().size, 4);
41//! ```
42//!
43//! Records are laid out by [`layout_record`], which takes the members and gives back their
44//! offsets, and the result is handed to [`Types::complete_record`] so that the record then has
45//! a size like any other type. Bit-fields, `packed`, `#pragma pack`, `aligned`, zero width
46//! bit-fields and flexible array members are all in there, and every one of their rules was
47//! measured against gcc and clang rather than read off a document.
48//!
49//! [`promote`] and [`usual_arithmetic`] are 6.3.1.1 and 6.3.1.8, the rules that decide what
50//! type an arithmetic expression has. Their answers were read out of gcc and clang with
51//! `_Generic` naming the type of every interesting pair, which is also how the C23 changes were
52//! pinned down: `_BitInt` does not promote, and an enumeration promotes through whatever it is
53//! represented in.
54//!
55//! `__int128` is one of the integer kinds rather than a `_BitInt(128)` in disguise. The two are
56//! different types: `__int128` is sixteen bytes aligned to sixteen everywhere, `_BitInt(128)` is
57//! aligned to its granule, and `__int128` outranks `long long` where a `_BitInt` is ranked by
58//! width alone. It is available on every target here, because all three architectures are
59//! 64-bit and GCC has it on every 64-bit target it supports.
60//!
61//! [`compatible`] and [`composite`] are 6.2.7, the relation that decides whether two
62//! declarations of one name are talking about the same thing and the type that is left when they
63//! are. Identity is not that relation: `int f(int a[3])` and `int f(int *a)` are different types
64//! and the same function. The composite is what a caller merging two declarations should keep,
65//! because it is the only one of the three types in play that knows both the array size and the
66//! parameter list.
67//!
68//! # Status
69//!
70//! The type universe, the interner, the canonical and sugar split, the qualifier rules, layout
71//! with records included, the arithmetic conversions, compatibility with the composite type, and
72//! [`spell`], which writes a type back as the C declaration it is, are implemented.
73//!
74//! Not here yet, and named so that the gap is not mistaken for a decision: the decimal floating
75//! types.
76//!
77//! Every crate in the workspace is published, and publishing implies a promise. This one is
78//! tier 3: its Rust API is explicitly unstable and will change without a major version bump.
79//! Depend on the `rucc` binary's behaviour, not on this.
80
81#![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
110/// The milestone in `spec/17-milestones.md` that fills this crate in.
111pub 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    /// Lays out a record with no attributes on it, on x86-64 Linux.
129    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    /// The offsets of the members, in bits, which is what a measurement of a real compiler
135    /// gives back once its byte offsets and its bit dumps are put together.
136    fn offsets(laid_out: &RecordLayout) -> Vec<u64> {
137        laid_out.fields.iter().map(|field| field.offset).collect()
138    }
139
140    /// A complete record type built out of the given members.
141    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    /// An ordinary member of the given type, unnamed, which is all most of these tests need.
149    fn member(ty: TypeId) -> FieldDecl {
150        FieldDecl::new(None, ty)
151    }
152
153    /// A named bit-field, which is what a measurement of a real compiler has to use to be able
154    /// to read the field back.
155    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    /// An unnamed bit-field, which occupies bits and raises nothing.
160    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        // 6.7.3p10, and not a shortcut. An array type has no qualifiers of its own, so if this
204        // put the `const` on the array then `const` on an array parameter would mean nothing.
205        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        // The bug this is here for: canonicalising only the top node leaves `int32_t *` and
232        // `int *` as different types, and then every rule stated on pointers stops firing.
233        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        // `typedef int A[4]; const A x;` declares an array of `const int`, which is where the
274        // array rule and the sugar rule have to agree with each other.
275        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        // Two structs written the same way in one translation unit are different types. The
326        // looser relation that does hold between them is compatibility, which is a separate
327        // question from identity and is answered elsewhere.
328        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        // `_Complex long double` on SysV x86-64 is thirty two bytes aligned to sixteen, which
385        // is the case that catches an implementation that aligns the pair to its own size.
386        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        // The whole reason `_Atomic` is a type here rather than a qualifier. A sixteen byte
401        // record is aligned to eight and the atomic version of it is aligned to sixteen.
402        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        // An odd size cannot be accessed atomically in one go, so nothing is raised.
411        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        // Measured with clang 18 on x86-64 Linux and clang on AArch64 Darwin. The two disagree
423        // above sixty four bits, which is why the granule is a target fact.
424        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        // What GCC does with a `vector_size` that is not already one, checked against clang on
479        // AArch64 Darwin, which accepts the three element case that GCC rejects outright.
480        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        // Kept apart because GNU C gives both of them a size of one and a different warning,
494        // and because a caller that cannot tell them apart cannot write either message.
495        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        // And the tail is padded, which is what makes an array of the thing work.
522        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        // Nine bytes and a short is ten, not nine and not sixteen: the size is rounded up to
537        // the alignment rather than to the largest member.
538        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        // Measured with gcc 13.3 on x86-64 Linux and clang on AArch64 Darwin, including where
547        // the bits landed, by setting each field to all ones and dumping the bytes.
548        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        // Thirty bits do not fit in what is left of the first int, so they start a new one.
560        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        // Thirty three bits of a `long long` do fit in what is left of the first one, because
566        // the unit is eight bytes rather than four, so they stay where they are.
567        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        // An ordinary member after a bit-field starts at the next byte it is allowed to.
573        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        // Five bytes aligned to one: the zero width field pushed the second `char` to offset
586        // four without giving the record the alignment of an `int`. Both compilers report that.
587        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        // The unit an unnamed field has to fit inside is still its own type's, so this one
609        // moves to bit thirty two and the record is eight bytes aligned to one.
610        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        // A zero width bit-field still rounds to its own type, packed or not, which is the
637        // whole reason a program writes one inside a packed structure.
638        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        // Six bytes with the field at bit eight, not at bit sixteen. Once the alignment has
660        // been capped below the type's own there is no boundary to move to, so the field stays
661        // put. Measured, because moving it is at least as plausible a reading.
662        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        // The same structure with the field unnamed is five bytes aligned to one, because the
669        // capped alignment reached it through the record and an unnamed field gives none back.
670        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        // `packed, aligned(4)` together: the members pack and the record does not, which is
688        // the combination the attribute pair exists for.
689        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        // What makes `malloc(sizeof(struct S) + n)` the idiom it is.
700        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        // The alignment still applies, so this is eight bytes of which one is the `char`.
711        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        // Anywhere but last it is an incomplete member, and which member is part of the answer.
717        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        // The GNU empty structure, which C itself does not have and which real headers do.
726        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        // An anonymous member is an ordinary member with no name, so the same code lays it out
772        // and the four bytes of padding after the `char` are there either way.
773        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        // Measured by naming the type of `+x` with `_Generic` in gcc 13.3 and clang 18. Every
782        // one of these answers `int`, including the unsigned ones, because an `int` holds every
783        // value a sixteen bit unsigned type has.
784        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        // From `int` up, a type is its own promotion.
797        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        // C23 6.3.1.1p2, and the point of the type. `_BitInt(8) + _BitInt(8)` stays eight bits
806        // wide where `char + char` is an `int`, which is what makes the width mean something.
807        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        // Three bits of an unsigned field all fit in an `int`, so it is signed afterwards.
823        assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
824        // Thirty two of them do not.
825        assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
826        // Twenty bits of a signed field, which is an `int` either way.
827        assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
828        // Forty bits keep the declared type. The C17 wording says `unsigned int` here, which
829        // would silently drop eight bits; both compilers answer the declared type instead.
830        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        // `enum E : short` promotes the same way a `short` does, which is to `int`.
842        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        // An enumeration all of whose enumerators are non-negative is represented in
848        // `unsigned int` by both compilers, and then it promotes to itself.
849        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        // An enumeration nobody has decided on yet answers `int`, so that an expression using
855        // one is still checkable while the diagnostic about it is being written.
856        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        // By the time a value is being promoted the lvalue conversion has already happened, so
864        // `_Atomic const int` and `int` are the same operand.
865        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        // Every row measured with `_Generic` in gcc 13.3 and clang 18 on x86-64 Linux.
877        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        // Measured on gcc 13.3 on x86-64 Linux and clang on AArch64 Darwin, both of which
902        // report the same size, the same alignment, and an offset of sixteen for a member
903        // after a `char`.
904        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        // `__int128 + unsigned long long` is `__int128`, because it wins on rank and is wide
915        // enough to hold every value the other side had. Both compilers agree, and it is the
916        // one pair that says the rank is above `long long` rather than beside it.
917        let ull = types.int(IntKind::ULongLong);
918        assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
919        // And it is its own promotion, the way every type at or above `int` is.
920        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        // Same width, different types. The alignment is the visible difference on x86-64,
926        // where a `_BitInt` is aligned to its sixty four bit granule and `__int128` is not.
927        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        // `unsigned long + long long` is `unsigned long long` on Linux: the `long long` wins on
940        // rank and cannot hold every value of the `unsigned long`, so neither operand's own
941        // type is the answer. This is the arm programs are surprised by.
942        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        // The same pair on Windows, where `long` is thirty two bits, comes out as `long long`,
950        // because there it does hold every value. A host-driven implementation gets one of
951        // these two wrong.
952        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        // Measured with clang 18 on x86-64 Linux, which is the compiler that has `_BitInt`.
959        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        // Wider than an `int`, so it outranks one.
971        assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
972        // Narrower than a `long`, so it loses to one.
973        assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
974        // The same width as an `int`, and a standard type wins the tie.
975        assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
976        assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
977        // The other side promotes first, so a `char` next to a narrow `_BitInt` is an `int`
978        // and the `_BitInt` loses to it.
979        assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
980        // Unsigned and higher ranked wins outright, and unsigned and lower ranked loses to a
981        // signed type wide enough to hold it.
982        assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
983        assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
984        // Two bit-precise types of the same width and different signedness.
985        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        // Sixty four bits of unsigned integer against a `float`, which is a `float` and loses
1002        // most of them. That is the rule rather than an oversight.
1003        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        // The caller is the one holding the span, so this says no rather than guessing.
1027        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        // And a type that is not arithmetic is still its own promotion, so a caller may promote
1036        // first and ask questions afterwards.
1037        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    /// A prototype returning `void`.
1052    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    /// `void f()` as it means before C23: a declaration that says nothing about the parameters.
1058    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    /// A complete record with the given tag and members.
1064    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        // The qualifiers have to match exactly, which is what keeps `const int *` and `int *`
1081        // apart as parameter types.
1082        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        // And a different type is a different type. `char` is not `signed char` even on a target
1090        // where the two have the same range, which is why they are separate kinds here.
1091        let char_ = types.int(IntKind::Char);
1092        let schar = types.int(IntKind::SChar);
1093        assert!(!compatible(&types, char_, schar));
1094        // `_Atomic int` is not `int` either, since it is a type and not a qualifier.
1095        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        // gcc 13.3 and clang 18 both represent `enum E { A, B }` in `unsigned int`, and both
1102        // accept a redeclaration that writes the representation instead of the tag.
1103        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        // Two enumeration declarations are two types. Each is compatible with what it is
1114        // represented in, and that does not make them compatible with each other.
1115        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        // One nobody has decided on yet is compatible with nothing but itself, because the
1121        // answer is not known rather than no.
1122        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        // `extern int a[]; int a[4];` is a complete array of four afterwards, which gcc reports
1131        // as a `sizeof` of sixteen. A compiler that keeps the first type has lost the size.
1132        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        // A variable length array is compatible with both, because its size is not something a
1144        // declaration can be checked against.
1145        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        // The element types have to be compatible too, and the composite reaches into them.
1150        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        // `int fn(int p[3])` and `int fn(int *p)` are one declaration and one definition, which
1158        // both compilers accept. The adjustment is part of forming the parameter type, so two
1159        // functions written either way are not merely compatible but identical.
1160        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        // A function parameter becomes a pointer to the function the same way.
1167        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        // And the qualifiers on the outermost node go, so `void f(const int)` and `void f(int)`
1172        // declare the same function. The pointee of a `const int *` keeps its own.
1173        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        // Measured with gcc 13.3 in C17 mode, which is the compiler that still has the old
1182        // meaning of `()`. It names the rule in its own diagnostic: an argument type that has a
1183        // default promotion cannot match an empty parameter name list declaration.
1184        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        // The composite is the prototype, so the calls written before it can still be checked.
1196        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        // A `char` promotes to `int` and a `float` to `double`, so a call through the old style
1205        // declaration would have passed something else and the two conflict.
1206        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        // An ellipsis conflicts too, which gcc also says in as many words.
1213        let variadic = prototype(&mut types, vec![int], true);
1214        assert!(!compatible(&types, old, variadic));
1215
1216        // An enumeration parameter comes through when what it is represented in does.
1217        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        // Two old style declarations agree about nothing and so cannot disagree.
1225        assert!(compatible(&types, old, old));
1226
1227        // The return type still has to match, which is the one part `()` does say.
1228        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        // The dialect decides what `()` means and the parser records the decision, so the same
1240        // pair of declarations is a redeclaration in C17 and a conflict in C23. Both compilers
1241        // report exactly that.
1242        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        // The parameters are compared with the same rules as anything else, so an array size
1265        // inside a parameter's type is compared and an unknown one is not.
1266        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        // And the composite takes the size, which is the whole reason it exists.
1274        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        // The pointer's own qualifiers survive, since a compatible pair has the same ones.
1288        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        // C23 6.2.7p1, which is what lets one header be included twice. clang 18 implements it
1296        // and gcc 13.3 still rejects the redefinition, so this is a divergence rather than a
1297        // reading; in the older dialects the redefinition never gets as far as being compared.
1298        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        // A different member name, a different member type, a different count, a different tag
1314        // and a different keyword are each enough to make them different types.
1315        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        // An anonymous record is compatible with nothing but itself: there is no name by which
1329        // a second declaration could be claiming to be the same type.
1330        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        // Nor is an incomplete declaration, which has no members to compare.
1335        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        // `struct node { int value; struct node *next; }` declared twice. Comparing the two
1344        // reaches the same pair again through the pointer, and the second time it is an
1345        // assumption rather than a question.
1346        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        // The guard is an assumption and not an answer, so a difference below the cycle is still
1368        // found: the same structure with the two members the other way round is a different one.
1369        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}