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.3.0")]
82
83mod classify;
84mod compat;
85mod convert;
86mod kind;
87mod layout;
88mod print;
89mod record;
90mod types;
91
92pub use crate::classify::{
93    element, is_aggregate, is_arithmetic, is_array, is_atomic, is_complete, is_complex,
94    is_floating, is_function, is_integer, is_modifiable, is_object, is_pointer, is_real,
95    is_real_floating, is_record, is_scalar, is_vector, is_void, pointee,
96};
97pub use crate::compat::{adjust_parameter, compatible, composite};
98pub use crate::convert::{promote, promote_bit_field, usual_arithmetic};
99pub use crate::kind::{
100    ArrayLen, EnumId, FloatKind, FunctionId, FunctionType, IntKind, Qualifiers, RecordId,
101    RecordKind, Type, TypeKind, VlaId,
102};
103pub use crate::layout::{
104    IntegerInfo, Layout, LayoutError, float_format, float_width, int_width, integer_info, layout,
105};
106pub use crate::print::{declare, spell};
107pub use crate::record::{
108    Field, FieldDecl, RecordError, RecordLayout, RecordOptions, layout_record,
109};
110pub use crate::types::{EnumInfo, RecordInfo, TypeId, Types};
111
112/// The milestone in `spec/17-milestones.md` that fills this crate in.
113pub const MILESTONE: &str = "M2";
114
115#[cfg(test)]
116mod tests {
117    use rucc_base::{Interner, Symbol};
118    use rucc_target::{TargetInfo, Triple};
119
120    use super::*;
121
122    fn target(triple: &str) -> TargetInfo {
123        TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
124    }
125
126    fn linux() -> TargetInfo {
127        target("x86_64-unknown-linux-gnu")
128    }
129
130    /// Lays out a record with no attributes on it, on x86-64 Linux.
131    fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
132        layout_record(types, kind, fields, &RecordOptions::default(), &linux())
133            .expect("a record every member of which has a layout")
134    }
135
136    /// The offsets of the members, in bits, which is what a measurement of a real compiler
137    /// gives back once its byte offsets and its bit dumps are put together.
138    fn offsets(laid_out: &RecordLayout) -> Vec<u128> {
139        laid_out.fields.iter().map(Field::bit_offset).collect()
140    }
141
142    /// A complete record type built out of the given members.
143    fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
144        let id = types.declare_record(kind, None);
145        let laid_out = lay_out(types, kind, fields);
146        types.complete_record(id, laid_out);
147        types.record(id)
148    }
149
150    /// An ordinary member of the given type, unnamed, which is all most of these tests need.
151    fn member(ty: TypeId) -> FieldDecl {
152        FieldDecl::new(None, ty)
153    }
154
155    /// A named bit-field, which is what a measurement of a real compiler has to use to be able
156    /// to read the field back.
157    fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
158        FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
159    }
160
161    /// An unnamed bit-field, which occupies bits and raises nothing.
162    fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
163        FieldDecl::bit_field(None, ty, width)
164    }
165
166    #[test]
167    fn milestone_is_recorded() {
168        assert!(MILESTONE.starts_with('M'));
169    }
170
171    #[test]
172    fn an_integer_type_answers_with_the_width_of_its_value_and_not_of_its_object() {
173        let mut interner = Interner::new();
174        let mut types = Types::new();
175        let target = linux();
176
177        // A `bool` is one byte and holds one bit, and a `_BitInt(37)` is eight bytes and holds
178        // thirty seven. Folding a constant in the size rather than the width gets both wrong.
179        let boolean = types.boolean();
180        let bits = types.bit_int(true, 37);
181        // Through the sugar, the qualifiers and `_Atomic`, none of which is part of a value.
182        let short = types.int(IntKind::Short);
183        let alias = types.typedef(interner.intern("word"), short);
184        let unsigned_char = types.int(IntKind::UChar);
185        let atomic = types.atomic(unsigned_char);
186
187        let shape = |ty| integer_info(&types, ty, &target).expect("an integer type");
188        assert_eq!(shape(boolean), IntegerInfo::new(false, 1));
189        assert_eq!(shape(bits), IntegerInfo::new(true, 37));
190        assert_eq!(shape(types.int(IntKind::Int)), IntegerInfo::new(true, 32));
191        assert_eq!(shape(types.int(IntKind::ULong)), IntegerInfo::new(false, 64));
192        assert_eq!(shape(alias), IntegerInfo::new(true, 16));
193        assert_eq!(shape(atomic), IntegerInfo::new(false, 8));
194
195        assert_eq!(integer_info(&types, types.float(FloatKind::Double), &target), None);
196    }
197
198    #[test]
199    fn an_enumeration_answers_with_the_type_the_enumerators_are_kept_in() {
200        let mut interner = Interner::new();
201        let mut types = Types::new();
202        let target = linux();
203
204        // An enumeration that has not been completed has no underlying type yet, and the answer
205        // is that there is no answer rather than a guess at `int` that a later `: long` unsays.
206        let colour = types.declare_enum(Some(interner.intern("colour")));
207        let ty = types.enumeration(colour);
208        assert_eq!(integer_info(&types, ty, &target), None);
209
210        let underlying = types.int(IntKind::ULong);
211        types.complete_enum(colour, underlying, true);
212        assert_eq!(integer_info(&types, ty, &target), Some(IntegerInfo::new(false, 64)));
213    }
214
215    #[test]
216    fn a_value_stored_in_an_integer_type_keeps_the_bits_the_type_has_room_for() {
217        let char_type = IntegerInfo::new(true, 8);
218        assert_eq!(char_type.wrap(300), 44);
219        assert!(!char_type.holds(300));
220        assert!(char_type.holds(-128));
221
222        assert_eq!(IntegerInfo::new(false, 32).wrap(-1), 4_294_967_295);
223        assert_eq!(IntegerInfo::new(false, 8).wrap(-1), 255);
224
225        // Every pattern is a value of a hundred and twenty eight bit type, of either signedness,
226        // which is what stops the folding from inventing an overflow at the widest type there is.
227        assert!(IntegerInfo::new(false, 128).holds(i128::MIN));
228        assert!(IntegerInfo::new(true, 128).holds(i128::MIN));
229        assert_eq!(IntegerInfo::new(true, 128).wrap(i128::MAX), i128::MAX);
230    }
231
232    #[test]
233    fn a_long_double_has_a_format_the_size_does_not_give_away() {
234        let target = linux();
235        // Sixteen bytes on SysV x86-64 and eighty bits of x87 inside them. A compiler that
236        // picked the format by the size would fold every one of those constants too finely.
237        assert_eq!(float_width(FloatKind::LongDouble, &target), 128);
238        assert_eq!(
239            float_format(FloatKind::LongDouble, &target),
240            rucc_base::float::Format::X87Extended
241        );
242        assert_eq!(float_format(FloatKind::Float, &target), rucc_base::float::Format::Single);
243    }
244
245    #[test]
246    fn an_interchange_type_names_a_format_and_an_extended_one_names_the_target() {
247        use rucc_base::float::Format;
248
249        // The four `_FloatN` types are the same format everywhere, which is the point of them,
250        // so a program that wants binary128 can say so and get it or get told it cannot.
251        for target in [&linux(), &target("aarch64-apple-darwin")] {
252            assert_eq!(float_format(FloatKind::Float16, target), Format::Half);
253            assert_eq!(float_format(FloatKind::Float32, target), Format::Single);
254            assert_eq!(float_format(FloatKind::Float64, target), Format::Double);
255            assert_eq!(float_format(FloatKind::Float128, target), Format::Quad);
256            assert_eq!(float_width(FloatKind::Float16, target), 16);
257            assert_eq!(float_width(FloatKind::Float32, target), 32);
258            assert_eq!(float_width(FloatKind::Float64, target), 64);
259            assert_eq!(float_width(FloatKind::Float128, target), 128);
260            // `_Float32x` is `double` on every target this compiles for.
261            assert_eq!(float_format(FloatKind::Float32x, target), Format::Double);
262        }
263
264        // `_Float64x` is the one that moves, and it moves with the processor rather than with
265        // the operating system, so it stays eighty bits of x87 on x86-64 where `long double`
266        // is the same thing and is quad on Apple where `long double` is only a `double`.
267        let x86 = linux();
268        assert_eq!(float_format(FloatKind::Float64x, &x86), Format::X87Extended);
269        assert_eq!(float_format(FloatKind::LongDouble, &x86), Format::X87Extended);
270        let mac = target("aarch64-apple-darwin");
271        assert_eq!(float_format(FloatKind::Float64x, &mac), Format::Quad);
272        assert_eq!(float_format(FloatKind::LongDouble, &mac), Format::Double);
273        // Sixteen bytes either way, because the x87 eighty bits are stored padded, which is
274        // the same reason `long double` is sixteen bytes on x86-64 and not ten.
275        assert_eq!(float_width(FloatKind::Float64x, &x86), 128);
276        assert_eq!(float_width(FloatKind::Float64x, &mac), 128);
277    }
278
279    #[test]
280    fn every_floating_type_is_as_wide_as_the_format_it_is_stored_in() {
281        let types = Types::new();
282        let sizes = |target: &TargetInfo| -> Vec<(u64, u64)> {
283            FloatKind::ALL
284                .iter()
285                .map(|&kind| {
286                    let found = layout(&types, types.float(kind), target).expect("a complete type");
287                    (found.size, found.align)
288                })
289                .collect()
290        };
291        // Read off gcc 16 with `sizeof` and `_Alignof`, in the order of `FloatKind::ALL`. The
292        // two targets differ in one place, which is `long double`, and the eighty bit x87 value
293        // that `long double` and `_Float64x` hold on x86-64 takes sixteen bytes to store.
294        assert_eq!(
295            sizes(&linux()),
296            [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16), (16, 16)]
297        );
298        assert_eq!(
299            sizes(&target("aarch64-apple-darwin")),
300            [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16)]
301        );
302    }
303
304    #[test]
305    fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
306        // Nine types and nine ids, which is what makes `_Float64` and `double` two types that
307        // `_Generic` can tell apart rather than one type with two spellings.
308        let types = Types::new();
309        let mut seen = Vec::new();
310        for kind in FloatKind::ALL {
311            seen.push(types.float(kind));
312        }
313        let mut sorted = seen.clone();
314        sorted.sort_unstable();
315        sorted.dedup();
316        assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
317
318        let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
319        assert_eq!(
320            names,
321            [
322                "_Float16",
323                "float",
324                "_Float32",
325                "double",
326                "_Float32x",
327                "_Float64",
328                "long double",
329                "_Float64x",
330                "_Float128",
331            ]
332        );
333    }
334
335    #[test]
336    fn the_same_type_asked_for_twice_is_the_same_id() {
337        let mut types = Types::new();
338        let a = types.pointer(types.int(IntKind::Int));
339        let b = types.pointer(types.int(IntKind::Int));
340        assert_eq!(a, b, "interning is what makes type identity an integer comparison");
341        let c = types.pointer(types.int(IntKind::Long));
342        assert_ne!(a, c);
343    }
344
345    #[test]
346    fn a_qualifier_makes_a_different_type_with_the_same_shape() {
347        let mut types = Types::new();
348        let int = types.int(IntKind::Int);
349        let konst = types.qualified(int, Qualifiers::CONST);
350        assert_ne!(int, konst);
351        assert_eq!(types.kind(konst), types.kind(int));
352        assert!(types.quals(konst).has(Qualifiers::CONST));
353        assert_eq!(types.unqualified(konst), int);
354    }
355
356    #[test]
357    fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
358        let mut types = Types::new();
359        let int = types.int(IntKind::Int);
360        let a = types.qualified(int, Qualifiers::CONST);
361        let a = types.qualified(a, Qualifiers::VOLATILE);
362        let b = types.qualified(int, Qualifiers::VOLATILE);
363        let b = types.qualified(b, Qualifiers::CONST);
364        assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
365    }
366
367    #[test]
368    fn qualifying_an_array_qualifies_its_element() {
369        // 6.7.3p10, and not a shortcut. An array type has no qualifiers of its own, so if this
370        // put the `const` on the array then `const` on an array parameter would mean nothing.
371        let mut types = Types::new();
372        let int = types.int(IntKind::Int);
373        let array = types.array(int, ArrayLen::Fixed(4));
374        let konst = types.qualified(array, Qualifiers::CONST);
375        assert!(types.quals(konst).is_none(), "the array itself is unqualified");
376        let TypeKind::Array { elem, len } = types.kind(konst) else {
377            panic!("still an array");
378        };
379        assert_eq!(len, ArrayLen::Fixed(4));
380        assert!(types.quals(elem).has(Qualifiers::CONST));
381    }
382
383    #[test]
384    fn a_typedef_is_a_different_type_that_means_the_same_thing() {
385        let mut interner = Interner::new();
386        let mut types = Types::new();
387        let int = types.int(IntKind::Int);
388        let name = types.typedef(interner.intern("int32_t"), int);
389        assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
390        assert_eq!(types.canonical(name), int, "and no rule ever sees it");
391        assert!(types.is_sugar(name));
392        assert!(!types.is_sugar(int));
393    }
394
395    #[test]
396    fn sugar_below_the_outermost_node_is_resolved_too() {
397        // The bug this is here for: canonicalising only the top node leaves `int32_t *` and
398        // `int *` as different types, and then every rule stated on pointers stops firing.
399        let mut interner = Interner::new();
400        let mut types = Types::new();
401        let int = types.int(IntKind::Int);
402        let name = types.typedef(interner.intern("int32_t"), int);
403        let sugar_pointer = types.pointer(name);
404        let plain_pointer = types.pointer(int);
405        assert_ne!(sugar_pointer, plain_pointer);
406        assert_eq!(types.canonical(sugar_pointer), plain_pointer);
407
408        let sugar_array = types.array(name, ArrayLen::Fixed(3));
409        let plain_array = types.array(int, ArrayLen::Fixed(3));
410        assert_eq!(types.canonical(sugar_array), plain_array);
411    }
412
413    #[test]
414    fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
415        let mut interner = Interner::new();
416        let mut types = Types::new();
417        let int = types.int(IntKind::Int);
418        let mut current = int;
419        for i in 0..8 {
420            current = types.typedef(interner.intern(&format!("t{i}")), current);
421        }
422        assert_eq!(types.canonical(current), int);
423    }
424
425    #[test]
426    fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
427        let mut interner = Interner::new();
428        let mut types = Types::new();
429        let int = types.int(IntKind::Int);
430        let name = types.typedef(interner.intern("int32_t"), int);
431        let konst = types.qualified(name, Qualifiers::CONST);
432        assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
433        let want = types.qualified(int, Qualifiers::CONST);
434        assert_eq!(types.canonical(konst), want);
435    }
436
437    #[test]
438    fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
439        // `typedef int A[4]; const A x;` declares an array of `const int`, which is where the
440        // array rule and the sugar rule have to agree with each other.
441        let mut interner = Interner::new();
442        let mut types = Types::new();
443        let int = types.int(IntKind::Int);
444        let array = types.array(int, ArrayLen::Fixed(4));
445        let name = types.typedef(interner.intern("A"), array);
446        let konst = types.qualified(name, Qualifiers::CONST);
447        let konst_int = types.qualified(int, Qualifiers::CONST);
448        let want = types.array(konst_int, ArrayLen::Fixed(4));
449        assert_eq!(types.canonical(konst), want);
450    }
451
452    #[test]
453    fn a_function_type_is_deduplicated_by_its_signature() {
454        let mut types = Types::new();
455        let int = types.int(IntKind::Int);
456        let long = types.int(IntKind::Long);
457        let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
458            types.function(FunctionType { ret: int, params, variadic, prototyped: true })
459        };
460        let a = make(&mut types, vec![int, long], false);
461        let b = make(&mut types, vec![int, long], false);
462        assert_eq!(a, b);
463        assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
464        assert_ne!(a, make(&mut types, vec![long, int], false));
465    }
466
467    #[test]
468    fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
469        let mut interner = Interner::new();
470        let mut types = Types::new();
471        let int = types.int(IntKind::Int);
472        let name = types.typedef(interner.intern("int32_t"), int);
473        let sugar = types.function(FunctionType {
474            ret: name,
475            params: vec![name],
476            variadic: false,
477            prototyped: true,
478        });
479        let plain = types.function(FunctionType {
480            ret: int,
481            params: vec![int],
482            variadic: false,
483            prototyped: true,
484        });
485        assert_ne!(sugar, plain);
486        assert_eq!(types.canonical(sugar), plain);
487    }
488
489    #[test]
490    fn a_record_is_its_declaration_and_not_its_members() {
491        // Two structs written the same way in one translation unit are different types. The
492        // looser relation that does hold between them is compatibility, which is a separate
493        // question from identity and is answered elsewhere.
494        let mut interner = Interner::new();
495        let mut types = Types::new();
496        let tag = interner.intern("point");
497        let first = types.declare_record(RecordKind::Struct, Some(tag));
498        let second = types.declare_record(RecordKind::Struct, Some(tag));
499        assert_ne!(types.record(first), types.record(second));
500        assert_eq!(types.record(first), types.record(first));
501    }
502
503    #[test]
504    fn a_record_has_no_layout_until_it_has_been_completed() {
505        let mut types = Types::new();
506        let id = types.declare_record(RecordKind::Struct, None);
507        let ty = types.record(id);
508        assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
509        let long_long = types.int(IntKind::LongLong);
510        let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
511        types.complete_record(id, laid_out);
512        assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
513    }
514
515    #[test]
516    fn an_enum_takes_the_layout_of_its_underlying_type() {
517        let mut types = Types::new();
518        let id = types.declare_enum(None);
519        let ty = types.enumeration(id);
520        assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
521        let int = types.int(IntKind::Int);
522        types.complete_enum(id, int, false);
523        assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
524    }
525
526    #[test]
527    fn the_scalar_widths_come_from_the_target() {
528        let mut types = Types::new();
529        let linux = linux();
530        let windows = target("x86_64-pc-windows-msvc");
531        let darwin = target("aarch64-apple-darwin");
532
533        let long = types.int(IntKind::Long);
534        assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
535        assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
536
537        let ldouble = types.float(FloatKind::LongDouble);
538        assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
539        assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
540
541        let pointer = types.pointer(types.void());
542        assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
543
544        let boolean = types.boolean();
545        assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
546    }
547
548    #[test]
549    fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
550        // `_Complex long double` on SysV x86-64 is thirty two bytes aligned to sixteen, which
551        // is the case that catches an implementation that aligns the pair to its own size.
552        let mut types = Types::new();
553        let linux = linux();
554        let cfloat = types.complex(FloatKind::Float);
555        assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
556        let cdouble = types.complex(FloatKind::Double);
557        assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
558        let cldouble = types.complex(FloatKind::LongDouble);
559        assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
560        let darwin = target("aarch64-apple-darwin");
561        assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
562    }
563
564    #[test]
565    fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
566        // The whole reason `_Atomic` is a type here rather than a qualifier. A sixteen byte
567        // record is aligned to eight and the atomic version of it is aligned to sixteen.
568        let mut types = Types::new();
569        let linux = linux();
570        let long_long = types.int(IntKind::LongLong);
571        let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
572        let atomic = types.atomic(plain);
573        assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
574        assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
575
576        // An odd size cannot be accessed atomically in one go, so nothing is raised.
577        let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
578        let atomic_odd = types.atomic(odd);
579        assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
580
581        let int = types.int(IntKind::Int);
582        let atomic_int = types.atomic(int);
583        assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
584    }
585
586    #[test]
587    fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
588        // Measured with clang 18 on x86-64 Linux and clang on AArch64 Darwin. The two disagree
589        // above sixty four bits, which is why the granule is a target fact.
590        let mut types = Types::new();
591        let linux = linux();
592        let darwin = target("aarch64-apple-darwin");
593        let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
594        for (width, size, align) in cases {
595            let ty = types.bit_int(true, width);
596            assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
597            assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
598        }
599        for width in [65, 96, 128] {
600            let ty = types.bit_int(false, width);
601            assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
602            assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
603        }
604        let wide = types.bit_int(true, 129);
605        assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
606        assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
607    }
608
609    #[test]
610    fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
611        let mut types = Types::new();
612        let linux = linux();
613        let int = types.int(IntKind::Int);
614        let ty = types.array(int, ArrayLen::Fixed(10));
615        assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
616        let nested = types.array(ty, ArrayLen::Fixed(3));
617        assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
618    }
619
620    #[test]
621    fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
622        let mut types = Types::new();
623        let linux = linux();
624        let int = types.int(IntKind::Int);
625        for len in [ArrayLen::Unknown, ArrayLen::Star, ArrayLen::Variable(VlaId(0))] {
626            let ty = types.array(int, len);
627            assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
628        }
629        let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
630        assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
631    }
632
633    #[test]
634    fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
635        // The limit is `PTRDIFF_MAX` rather than wherever the multiplication happens to
636        // overflow, so an array of a byte may be every byte an object may have and one more
637        // than that is refused. gcc 16 gives the same two answers.
638        let mut types = Types::new();
639        let linux = linux();
640        let max = linux.max_object_size();
641        let ch = types.int(IntKind::Char);
642        let fits = types.array(ch, ArrayLen::Fixed(max));
643        assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
644        let over = types.array(ch, ArrayLen::Fixed(max + 1));
645        assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
646    }
647
648    #[test]
649    fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
650        // The shape `991014-1.c` in the gcc.c-torture execution suite asks about: a type
651        // nothing is ever an object of is still a type `sizeof` has to answer about. Counting
652        // the record in bits made the largest one an eighth of this, with the multiply by eight
653        // overflowing rather than any rule saying so.
654        let mut types = Types::new();
655        let linux = linux();
656        let max = linux.max_object_size();
657        let ch = types.int(IntKind::Char);
658        let int = types.int(IntKind::Int);
659        let short = types.int(IntKind::Short);
660
661        let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
662        let members = [member(huge), member(int), member(int), member(int), member(int)];
663        let laid_out = lay_out(&types, RecordKind::Struct, &members);
664        assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
665
666        let brim = types.array(ch, ArrayLen::Fixed(max));
667        let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
668        assert_eq!(laid_out.layout, Layout::new(max, 1));
669
670        let over = [member(brim), member(ch)];
671        let options = RecordOptions::default();
672        let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
673        assert_eq!(error, Err(RecordError::TooLarge));
674    }
675
676    #[test]
677    fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
678        // Eight times the largest object is more than a `u64` holds, so a bit-field at the end
679        // of a record that large has a bit offset no bit count can name. It is a byte offset
680        // and a bit within it here, which is what lets this be laid out at all, and gcc 16
681        // gives the same size for it.
682        let mut types = Types::new();
683        let linux = linux();
684        let ch = types.int(IntKind::Char);
685        let int = types.int(IntKind::Int);
686        let mut interner = Interner::new();
687        let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
688        let members = [member(buf), bits(&mut interner, "x", int, 1)];
689        let laid_out = lay_out(&types, RecordKind::Struct, &members);
690        assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
691        let last = laid_out.fields[1];
692        assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
693        assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
694    }
695
696    #[test]
697    fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
698        let mut types = Types::new();
699        let int = types.int(IntKind::Int);
700        let a = types.array(int, ArrayLen::Variable(VlaId(0)));
701        let b = types.array(int, ArrayLen::Variable(VlaId(1)));
702        assert_ne!(a, b);
703    }
704
705    #[test]
706    fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
707        // What GCC does with a `vector_size` that is not already one, checked against clang on
708        // AArch64 Darwin, which accepts the three element case that GCC rejects outright.
709        let mut types = Types::new();
710        let linux = linux();
711        let int = types.int(IntKind::Int);
712        let four = types.vector(int, 4);
713        assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
714        let three = types.vector(int, 3);
715        assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
716        let three_chars = types.vector(types.int(IntKind::Char), 3);
717        assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
718    }
719
720    #[test]
721    fn the_types_without_a_size_say_which_kind_of_without_they_are() {
722        // Kept apart because GNU C gives both of them a size of one and a different warning,
723        // and because a caller that cannot tell them apart cannot write either message.
724        let mut types = Types::new();
725        let linux = linux();
726        let void = types.void();
727        assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
728        let int = types.int(IntKind::Int);
729        let function = types.function(FunctionType {
730            ret: int,
731            params: Vec::new(),
732            variadic: false,
733            prototyped: true,
734        });
735        assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
736        let pointer_to_function = types.pointer(function);
737        assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
738    }
739
740    #[test]
741    fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
742        let types = Types::new();
743        let char_ = types.int(IntKind::Char);
744        let int = types.int(IntKind::Int);
745        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
746        assert_eq!(laid_out.layout, Layout::new(8, 4));
747        assert_eq!(offsets(&laid_out), [0, 32]);
748        assert_eq!(laid_out.fields[1].offset, 4);
749
750        // And the tail is padded, which is what makes an array of the thing work.
751        let long_long = types.int(IntKind::LongLong);
752        let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
753        assert_eq!(laid_out.layout, Layout::new(16, 8));
754    }
755
756    #[test]
757    fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
758        let mut types = Types::new();
759        let char_ = types.int(IntKind::Char);
760        let int = types.int(IntKind::Int);
761        let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
762        assert_eq!(laid_out.layout, Layout::new(4, 4));
763        assert_eq!(offsets(&laid_out), [0, 0]);
764
765        // Nine bytes and a short is ten, not nine and not sixteen: the size is rounded up to
766        // the alignment rather than to the largest member.
767        let nine = types.array(char_, ArrayLen::Fixed(9));
768        let short = types.int(IntKind::Short);
769        let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
770        assert_eq!(laid_out.layout, Layout::new(10, 2));
771    }
772
773    #[test]
774    fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
775        // Measured with gcc 13.3 on x86-64 Linux and clang on AArch64 Darwin, including where
776        // the bits landed, by setting each field to all ones and dumping the bytes.
777        let mut interner = Interner::new();
778        let types = Types::new();
779        let char_ = types.int(IntKind::Char);
780        let int = types.int(IntKind::Int);
781        let long_long = types.int(IntKind::LongLong);
782
783        let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
784        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
785        assert_eq!(laid_out.layout, Layout::new(4, 4));
786        assert_eq!(offsets(&laid_out), [0, 3]);
787
788        // Thirty bits do not fit in what is left of the first int, so they start a new one.
789        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
790        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
791        assert_eq!(laid_out.layout, Layout::new(8, 4));
792        assert_eq!(offsets(&laid_out), [0, 32]);
793
794        // Thirty three bits of a `long long` do fit in what is left of the first one, because
795        // the unit is eight bytes rather than four, so they stay where they are.
796        let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
797        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
798        assert_eq!(laid_out.layout, Layout::new(8, 8));
799        assert_eq!(offsets(&laid_out), [0, 8]);
800
801        // An ordinary member after a bit-field starts at the next byte it is allowed to.
802        let fields = [bits(&mut interner, "a", int, 3), member(char_)];
803        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
804        assert_eq!(offsets(&laid_out), [0, 8]);
805    }
806
807    #[test]
808    fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
809        let types = Types::new();
810        let char_ = types.int(IntKind::Char);
811        let int = types.int(IntKind::Int);
812        let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
813        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
814        // Five bytes aligned to one: the zero width field pushed the second `char` to offset
815        // four without giving the record the alignment of an `int`. Both compilers report that.
816        assert_eq!(laid_out.layout, Layout::new(5, 1));
817        assert_eq!(offsets(&laid_out), [0, 32, 32]);
818        assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
819    }
820
821    #[test]
822    fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
823        let mut interner = Interner::new();
824        let types = Types::new();
825        let char_ = types.int(IntKind::Char);
826        let int = types.int(IntKind::Int);
827
828        let unnamed = [member(char_), unnamed_bits(int, 20)];
829        let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
830        assert_eq!(unnamed.layout, Layout::new(4, 1));
831
832        let named = [member(char_), bits(&mut interner, "b", int, 20)];
833        let named = lay_out(&types, RecordKind::Struct, &named);
834        assert_eq!(named.layout, Layout::new(4, 4));
835        assert_eq!(offsets(&named), [0, 8], "the same place either way");
836
837        // The unit an unnamed field has to fit inside is still its own type's, so this one
838        // moves to bit thirty two and the record is eight bytes aligned to one.
839        let wider = [member(char_), unnamed_bits(int, 30)];
840        let wider = lay_out(&types, RecordKind::Struct, &wider);
841        assert_eq!(wider.layout, Layout::new(8, 1));
842        assert_eq!(offsets(&wider), [0, 32]);
843    }
844
845    #[test]
846    fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
847        let mut interner = Interner::new();
848        let types = Types::new();
849        let char_ = types.int(IntKind::Char);
850        let int = types.int(IntKind::Int);
851        let packed = RecordOptions { packed: true, ..RecordOptions::default() };
852
853        let fields = [member(char_), member(int)];
854        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
855            .expect("a packed struct of two complete members");
856        assert_eq!(laid_out.layout, Layout::new(5, 1));
857        assert_eq!(offsets(&laid_out), [0, 8]);
858
859        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
860        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
861            .expect("a packed struct with a bit-field");
862        assert_eq!(laid_out.layout, Layout::new(5, 1));
863        assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
864
865        // A zero width bit-field still rounds to its own type, packed or not, which is the
866        // whole reason a program writes one inside a packed structure.
867        let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
868        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
869            .expect("a packed struct with a zero width bit-field");
870        assert_eq!(laid_out.layout, Layout::new(5, 1));
871        assert_eq!(offsets(&laid_out), [0, 32, 32]);
872    }
873
874    #[test]
875    fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
876        let mut interner = Interner::new();
877        let types = Types::new();
878        let char_ = types.int(IntKind::Char);
879        let int = types.int(IntKind::Int);
880        let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
881
882        let fields = [member(char_), member(int)];
883        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
884            .expect("a packed struct of two complete members");
885        assert_eq!(laid_out.layout, Layout::new(6, 2));
886        assert_eq!(offsets(&laid_out), [0, 16]);
887
888        // Six bytes with the field at bit eight, not at bit sixteen. Once the alignment has
889        // been capped below the type's own there is no boundary to move to, so the field stays
890        // put. Measured, because moving it is at least as plausible a reading.
891        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
892        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
893            .expect("a packed struct with a bit-field");
894        assert_eq!(laid_out.layout, Layout::new(6, 2));
895        assert_eq!(offsets(&laid_out), [0, 8]);
896
897        // The same structure with the field unnamed is five bytes aligned to one, because the
898        // capped alignment reached it through the record and an unnamed field gives none back.
899        let fields = [member(char_), unnamed_bits(int, 30)];
900        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
901            .expect("a packed struct with an unnamed bit-field");
902        assert_eq!(laid_out.layout, Layout::new(5, 1));
903    }
904
905    #[test]
906    fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
907        let types = Types::new();
908        let char_ = types.int(IntKind::Char);
909        let int = types.int(IntKind::Int);
910
911        let aligned = FieldDecl { align: Some(16), ..member(int) };
912        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
913        assert_eq!(laid_out.layout, Layout::new(32, 16));
914        assert_eq!(offsets(&laid_out), [0, 128]);
915
916        // `packed, aligned(4)` together: the members pack and the record does not, which is
917        // the combination the attribute pair exists for.
918        let options = RecordOptions { packed: true, align: Some(4), pack: None };
919        let fields = [member(char_), member(int)];
920        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
921            .expect("a packed struct with an alignment asked for");
922        assert_eq!(laid_out.layout, Layout::new(8, 4));
923        assert_eq!(offsets(&laid_out), [0, 8]);
924    }
925
926    #[test]
927    fn a_flexible_array_member_costs_nothing_but_its_alignment() {
928        // What makes `malloc(sizeof(struct S) + n)` the idiom it is.
929        let mut types = Types::new();
930        let char_ = types.int(IntKind::Char);
931        let int = types.int(IntKind::Int);
932        let long_long = types.int(IntKind::LongLong);
933
934        let chars = types.array(char_, ArrayLen::Unknown);
935        let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
936        assert_eq!(laid_out.layout, Layout::new(4, 4));
937        assert_eq!(offsets(&laid_out), [0, 32]);
938
939        // The alignment still applies, so this is eight bytes of which one is the `char`.
940        let longs = types.array(long_long, ArrayLen::Unknown);
941        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
942        assert_eq!(laid_out.layout, Layout::new(8, 8));
943        assert_eq!(offsets(&laid_out), [0, 64]);
944
945        // Anywhere but last it is an incomplete member, and which member is part of the answer.
946        let fields = [member(chars), member(int)];
947        let error =
948            layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
949        assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
950    }
951
952    #[test]
953    fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
954        // The GNU empty structure, which C itself does not have and which real headers do.
955        let types = Types::new();
956        let laid_out = lay_out(&types, RecordKind::Struct, &[]);
957        assert_eq!(laid_out.layout, Layout::new(0, 1));
958    }
959
960    #[test]
961    fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
962        let types = Types::new();
963        let int = types.int(IntKind::Int);
964        let fields = [unnamed_bits(int, 33)];
965        let error =
966            layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
967        let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
968        assert_eq!(error, Err(want));
969    }
970
971    #[test]
972    fn a_record_reports_its_members_once_it_has_been_completed() {
973        let mut interner = Interner::new();
974        let mut types = Types::new();
975        let char_ = types.int(IntKind::Char);
976        let int = types.int(IntKind::Int);
977        let name = interner.intern("count");
978        let fields = [member(char_), FieldDecl::new(Some(name), int)];
979        let id = types.declare_record(RecordKind::Struct, None);
980        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
981        types.complete_record(id, laid_out);
982        let ty = types.record(id);
983        assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
984        let field = types.field(id, name).expect("the member that was declared");
985        assert_eq!(field.offset, 4);
986        assert!(!field.is_bit_field());
987        assert_eq!(types.field(id, interner.intern("missing")), None);
988    }
989
990    #[test]
991    fn a_nested_record_brings_its_own_alignment_with_it() {
992        let mut types = Types::new();
993        let char_ = types.int(IntKind::Char);
994        let int = types.int(IntKind::Int);
995        let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
996        let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
997        assert_eq!(laid_out.layout, Layout::new(8, 4));
998        assert_eq!(offsets(&laid_out), [0, 32]);
999
1000        // An anonymous member is an ordinary member with no name, so the same code lays it out
1001        // and the four bytes of padding after the `char` are there either way.
1002        let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1003        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1004        assert_eq!(laid_out.layout, Layout::new(12, 4));
1005        assert_eq!(offsets(&laid_out), [0, 32]);
1006    }
1007
1008    #[test]
1009    fn everything_narrower_than_an_int_promotes_to_one() {
1010        // Measured by naming the type of `+x` with `_Generic` in gcc 13.3 and clang 18. Every
1011        // one of these answers `int`, including the unsigned ones, because an `int` holds every
1012        // value a sixteen bit unsigned type has.
1013        let mut types = Types::new();
1014        let linux = linux();
1015        let int = types.int(IntKind::Int);
1016        let narrow =
1017            [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1018        for kind in narrow {
1019            let ty = types.int(kind);
1020            assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1021        }
1022        let boolean = types.boolean();
1023        assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1024
1025        // From `int` up, a type is its own promotion.
1026        for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1027            let ty = types.int(kind);
1028            assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1029        }
1030    }
1031
1032    #[test]
1033    fn a_bit_int_is_not_promoted_at_all() {
1034        // C23 6.3.1.1p2, and the point of the type. `_BitInt(8) + _BitInt(8)` stays eight bits
1035        // wide where `char + char` is an `int`, which is what makes the width mean something.
1036        let mut types = Types::new();
1037        let linux = linux();
1038        let small = types.bit_int(true, 8);
1039        assert_eq!(promote(&mut types, small, &linux), small);
1040        assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1041    }
1042
1043    #[test]
1044    fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1045        let mut types = Types::new();
1046        let linux = linux();
1047        let int = types.int(IntKind::Int);
1048        let uint = types.int(IntKind::UInt);
1049        let ullong = types.int(IntKind::ULongLong);
1050
1051        // Three bits of an unsigned field all fit in an `int`, so it is signed afterwards.
1052        assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1053        // Thirty two of them do not.
1054        assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1055        // Twenty bits of a signed field, which is an `int` either way.
1056        assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1057        // Forty bits keep the declared type. The C17 wording says `unsigned int` here, which
1058        // would silently drop eight bits; both compilers answer the declared type instead.
1059        assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), ullong);
1060    }
1061
1062    #[test]
1063    fn an_enumeration_promotes_through_what_it_is_represented_in() {
1064        let mut types = Types::new();
1065        let linux = linux();
1066        let int = types.int(IntKind::Int);
1067        let short = types.int(IntKind::Short);
1068        let uint = types.int(IntKind::UInt);
1069
1070        // `enum E : short` promotes the same way a `short` does, which is to `int`.
1071        let fixed = types.declare_enum(None);
1072        types.complete_enum(fixed, short, true);
1073        let fixed = types.enumeration(fixed);
1074        assert_eq!(promote(&mut types, fixed, &linux), int);
1075
1076        // An enumeration all of whose enumerators are non-negative is represented in
1077        // `unsigned int` by both compilers, and then it promotes to itself.
1078        let unsigned = types.declare_enum(None);
1079        types.complete_enum(unsigned, uint, false);
1080        let unsigned = types.enumeration(unsigned);
1081        assert_eq!(promote(&mut types, unsigned, &linux), uint);
1082
1083        // An enumeration nobody has decided on yet answers `int`, so that an expression using
1084        // one is still checkable while the diagnostic about it is being written.
1085        let undecided = types.declare_enum(None);
1086        let undecided = types.enumeration(undecided);
1087        assert_eq!(promote(&mut types, undecided, &linux), int);
1088    }
1089
1090    #[test]
1091    fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1092        // By the time a value is being promoted the lvalue conversion has already happened, so
1093        // `_Atomic const int` and `int` are the same operand.
1094        let mut types = Types::new();
1095        let linux = linux();
1096        let int = types.int(IntKind::Int);
1097        let konst = types.qualified(int, Qualifiers::CONST);
1098        let atomic = types.atomic(konst);
1099        assert_eq!(promote(&mut types, atomic, &linux), int);
1100        assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1101    }
1102
1103    #[test]
1104    fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1105        // Every row measured with `_Generic` in gcc 13.3 and clang 18 on x86-64 Linux.
1106        let mut types = Types::new();
1107        let linux = linux();
1108        let cases = [
1109            (IntKind::Int, IntKind::UInt, IntKind::UInt),
1110            (IntKind::Int, IntKind::Long, IntKind::Long),
1111            (IntKind::UInt, IntKind::Long, IntKind::Long),
1112            (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1113            (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1114            (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1115            (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1116            (IntKind::Char, IntKind::Char, IntKind::Int),
1117            (IntKind::UChar, IntKind::UShort, IntKind::Int),
1118        ];
1119        for (left, right, want) in cases {
1120            let left = types.int(left);
1121            let right = types.int(right);
1122            let want = types.int(want);
1123            assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1124            assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1125        }
1126    }
1127
1128    #[test]
1129    fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1130        // Measured on gcc 13.3 on x86-64 Linux and clang on AArch64 Darwin, both of which
1131        // report the same size, the same alignment, and an offset of sixteen for a member
1132        // after a `char`.
1133        let mut types = Types::new();
1134        let linux = linux();
1135        let signed = types.int(IntKind::Int128);
1136        let unsigned = types.int(IntKind::UInt128);
1137        for id in [signed, unsigned] {
1138            let laid_out = layout(&types, id, &linux).expect("a complete type");
1139            assert_eq!(laid_out.size, 16);
1140            assert_eq!(laid_out.align, 16);
1141        }
1142
1143        // `__int128 + unsigned long long` is `__int128`, because it wins on rank and is wide
1144        // enough to hold every value the other side had. Both compilers agree, and it is the
1145        // one pair that says the rank is above `long long` rather than beside it.
1146        let ull = types.int(IntKind::ULongLong);
1147        assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1148        // And it is its own promotion, the way every type at or above `int` is.
1149        assert_eq!(promote(&mut types, signed, &linux), signed);
1150    }
1151
1152    #[test]
1153    fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1154        // Same width, different types. The alignment is the visible difference on x86-64,
1155        // where a `_BitInt` is aligned to its sixty four bit granule and `__int128` is not.
1156        let mut types = Types::new();
1157        let linux = linux();
1158        let int128 = types.int(IntKind::Int128);
1159        let bit_int = types.bit_int(true, 128);
1160        assert_ne!(int128, bit_int);
1161        assert!(!compatible(&types, int128, bit_int));
1162        assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1163        assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1164    }
1165
1166    #[test]
1167    fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1168        // `unsigned long + long long` is `unsigned long long` on Linux: the `long long` wins on
1169        // rank and cannot hold every value of the `unsigned long`, so neither operand's own
1170        // type is the answer. This is the arm programs are surprised by.
1171        let mut types = Types::new();
1172        let linux = linux();
1173        let ulong = types.int(IntKind::ULong);
1174        let long_long = types.int(IntKind::LongLong);
1175        let want = types.int(IntKind::ULongLong);
1176        assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1177
1178        // The same pair on Windows, where `long` is thirty two bits, comes out as `long long`,
1179        // because there it does hold every value. A host-driven implementation gets one of
1180        // these two wrong.
1181        let windows = target("x86_64-pc-windows-msvc");
1182        assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1183    }
1184
1185    #[test]
1186    fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1187        // Measured with clang 18 on x86-64 Linux, which is the compiler that has `_BitInt`.
1188        let mut types = Types::new();
1189        let linux = linux();
1190        let b40 = types.bit_int(true, 40);
1191        let ub40 = types.bit_int(false, 40);
1192        let b8 = types.bit_int(true, 8);
1193        let b32 = types.bit_int(true, 32);
1194        let int = types.int(IntKind::Int);
1195        let uint = types.int(IntKind::UInt);
1196        let long = types.int(IntKind::Long);
1197        let char_ = types.int(IntKind::Char);
1198
1199        // Wider than an `int`, so it outranks one.
1200        assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1201        // Narrower than a `long`, so it loses to one.
1202        assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1203        // The same width as an `int`, and a standard type wins the tie.
1204        assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1205        assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1206        // The other side promotes first, so a `char` next to a narrow `_BitInt` is an `int`
1207        // and the `_BitInt` loses to it.
1208        assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1209        // Unsigned and higher ranked wins outright, and unsigned and lower ranked loses to a
1210        // signed type wide enough to hold it.
1211        assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1212        assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1213        // Two bit-precise types of the same width and different signedness.
1214        assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1215    }
1216
1217    #[test]
1218    fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1219        let mut types = Types::new();
1220        let linux = linux();
1221        let float = types.float(FloatKind::Float);
1222        let double = types.float(FloatKind::Double);
1223        let long_double = types.float(FloatKind::LongDouble);
1224        let ullong = types.int(IntKind::ULongLong);
1225        let int = types.int(IntKind::Int);
1226
1227        assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1228        assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1229        assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1230        // Sixty four bits of unsigned integer against a `float`, which is a `float` and loses
1231        // most of them. That is the rule rather than an oversight.
1232        assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1233    }
1234
1235    /// Insists that `a + b` and `b + a` are both `expected` on this target.
1236    ///
1237    /// Both ways round, because the operands of `+` are not ordered and an implementation that
1238    /// keeps the left one when it cannot decide would pass half of these and be wrong.
1239    fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1240        let mut types = Types::new();
1241        let left = types.float(a);
1242        let right = types.float(b);
1243        let want = types.float(expected);
1244        assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1245        assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1246    }
1247
1248    #[test]
1249    fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1250        // Every line here was read off gcc 16 with `_Generic` rather than off the standard, on
1251        // x86-64 Linux, where `long double` and `_Float64x` are both the x87 format and the
1252        // standard type is the one that comes out.
1253        let x86 = linux();
1254        combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1255        combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1256        combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1257        combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1258        combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1259        combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1260        combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1261        combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1262        combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1263        combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1264    }
1265
1266    #[test]
1267    fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1268        // The same reading against gcc 16 on aarch64-apple-darwin, where `long double` is a
1269        // `double` and loses to the `_Float64x` it beats on x86-64. The name says nothing about
1270        // which of the two is wider, which is why the ordering is worked out from the formats.
1271        let mac = target("aarch64-apple-darwin");
1272        combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1273        combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1274        combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1275        combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1276        combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1277        combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1278        combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1279        // `_Float16` is the narrowest type there is and does not promote on the way in, so it
1280        // survives an operation only when nothing wider is there.
1281        combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1282        combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1283        combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1284    }
1285
1286    #[test]
1287    fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1288        let mut types = Types::new();
1289        let linux = linux();
1290        let cfloat = types.complex(FloatKind::Float);
1291        let cdouble = types.complex(FloatKind::Double);
1292        let cldouble = types.complex(FloatKind::LongDouble);
1293        let double = types.float(FloatKind::Double);
1294        let long_double = types.float(FloatKind::LongDouble);
1295        let float = types.float(FloatKind::Float);
1296        let int = types.int(IntKind::Int);
1297
1298        assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1299        assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1300        assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1301        assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1302    }
1303
1304    #[test]
1305    fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1306        // The caller is the one holding the span, so this says no rather than guessing.
1307        let mut types = Types::new();
1308        let linux = linux();
1309        let int = types.int(IntKind::Int);
1310        let pointer = types.pointer(int);
1311        assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1312        assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1313        let void = types.void();
1314        assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1315        // And a type that is not arithmetic is still its own promotion, so a caller may promote
1316        // first and ask questions afterwards.
1317        assert_eq!(promote(&mut types, pointer, &linux), pointer);
1318    }
1319
1320    #[test]
1321    fn the_conversions_read_through_sugar() {
1322        let mut interner = Interner::new();
1323        let mut types = Types::new();
1324        let linux = linux();
1325        let char_ = types.int(IntKind::Char);
1326        let name = types.typedef(interner.intern("byte"), char_);
1327        let int = types.int(IntKind::Int);
1328        assert_eq!(promote(&mut types, name, &linux), int);
1329    }
1330
1331    /// A prototype returning `void`.
1332    fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1333        let ret = types.void();
1334        types.function(FunctionType { ret, params, variadic, prototyped: true })
1335    }
1336
1337    /// `void f()` as it means before C23: a declaration that says nothing about the parameters.
1338    fn old_style(types: &mut Types) -> TypeId {
1339        let ret = types.void();
1340        types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1341    }
1342
1343    /// A complete record with the given tag and members.
1344    fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1345        let id = types.declare_record(RecordKind::Struct, Some(tag));
1346        let laid_out = lay_out(types, RecordKind::Struct, fields);
1347        types.complete_record(id, laid_out);
1348        id
1349    }
1350
1351    #[test]
1352    fn a_type_is_compatible_with_itself_however_it_was_written() {
1353        let mut interner = Interner::new();
1354        let mut types = Types::new();
1355        let int = types.int(IntKind::Int);
1356        let name = types.typedef(interner.intern("int32_t"), int);
1357        assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1358        assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1359
1360        // The qualifiers have to match exactly, which is what keeps `const int *` and `int *`
1361        // apart as parameter types.
1362        let konst = types.qualified(int, Qualifiers::CONST);
1363        assert!(!compatible(&types, konst, int));
1364        let konst_pointer = types.pointer(konst);
1365        let pointer = types.pointer(int);
1366        assert!(!compatible(&types, konst_pointer, pointer));
1367        assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1368
1369        // And a different type is a different type. `char` is not `signed char` even on a target
1370        // where the two have the same range, which is why they are separate kinds here.
1371        let char_ = types.int(IntKind::Char);
1372        let schar = types.int(IntKind::SChar);
1373        assert!(!compatible(&types, char_, schar));
1374        // `_Atomic int` is not `int` either, since it is a type and not a qualifier.
1375        let atomic = types.atomic(int);
1376        assert!(!compatible(&types, atomic, int));
1377    }
1378
1379    #[test]
1380    fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1381        // gcc 13.3 and clang 18 both represent `enum E { A, B }` in `unsigned int`, and both
1382        // accept a redeclaration that writes the representation instead of the tag.
1383        let mut types = Types::new();
1384        let uint = types.int(IntKind::UInt);
1385        let int = types.int(IntKind::Int);
1386        let id = types.declare_enum(None);
1387        types.complete_enum(id, uint, false);
1388        let e = types.enumeration(id);
1389        assert!(compatible(&types, e, uint));
1390        assert!(compatible(&types, uint, e), "and the relation is symmetric");
1391        assert!(!compatible(&types, e, int));
1392
1393        // Two enumeration declarations are two types. Each is compatible with what it is
1394        // represented in, and that does not make them compatible with each other.
1395        let other = types.declare_enum(None);
1396        types.complete_enum(other, uint, false);
1397        let other = types.enumeration(other);
1398        assert!(!compatible(&types, e, other));
1399
1400        // One nobody has decided on yet is compatible with nothing but itself, because the
1401        // answer is not known rather than no.
1402        let undecided = types.declare_enum(None);
1403        let undecided = types.enumeration(undecided);
1404        assert!(!compatible(&types, undecided, uint));
1405        assert!(compatible(&types, undecided, undecided));
1406    }
1407
1408    #[test]
1409    fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1410        // `extern int a[]; int a[4];` is a complete array of four afterwards, which gcc reports
1411        // as a `sizeof` of sixteen. A compiler that keeps the first type has lost the size.
1412        let mut types = Types::new();
1413        let int = types.int(IntKind::Int);
1414        let unknown = types.array(int, ArrayLen::Unknown);
1415        let four = types.array(int, ArrayLen::Fixed(4));
1416        let five = types.array(int, ArrayLen::Fixed(5));
1417        assert!(compatible(&types, unknown, four));
1418        assert!(!compatible(&types, four, five));
1419        assert_eq!(composite(&mut types, unknown, four), Some(four));
1420        assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1421        assert_eq!(composite(&mut types, four, five), None);
1422
1423        // A variable length array is compatible with both, because its size is not something a
1424        // declaration can be checked against.
1425        let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1426        assert!(compatible(&types, vla, four));
1427        assert_eq!(composite(&mut types, vla, four), Some(four));
1428
1429        // The element types have to be compatible too, and the composite reaches into them.
1430        let long = types.int(IntKind::Long);
1431        let longs = types.array(long, ArrayLen::Fixed(4));
1432        assert!(!compatible(&types, four, longs));
1433    }
1434
1435    #[test]
1436    fn a_parameter_declared_as_an_array_is_a_pointer() {
1437        // `int fn(int p[3])` and `int fn(int *p)` are one declaration and one definition, which
1438        // both compilers accept. The adjustment is part of forming the parameter type, so two
1439        // functions written either way are not merely compatible but identical.
1440        let mut types = Types::new();
1441        let int = types.int(IntKind::Int);
1442        let three = types.array(int, ArrayLen::Fixed(3));
1443        let pointer = types.pointer(int);
1444        assert_eq!(adjust_parameter(&mut types, three), pointer);
1445
1446        // A function parameter becomes a pointer to the function the same way.
1447        let function = prototype(&mut types, vec![int], false);
1448        let function_pointer = types.pointer(function);
1449        assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1450
1451        // And the qualifiers on the outermost node go, so `void f(const int)` and `void f(int)`
1452        // declare the same function. The pointee of a `const int *` keeps its own.
1453        let konst = types.qualified(int, Qualifiers::CONST);
1454        assert_eq!(adjust_parameter(&mut types, konst), int);
1455        let to_konst = types.pointer(konst);
1456        assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1457    }
1458
1459    #[test]
1460    fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1461        // Measured with gcc 13.3 in C17 mode, which is the compiler that still has the old
1462        // meaning of `()`. It names the rule in its own diagnostic: an argument type that has a
1463        // default promotion cannot match an empty parameter name list declaration.
1464        let mut types = Types::new();
1465        let old = old_style(&mut types);
1466        let int = types.int(IntKind::Int);
1467        let long = types.int(IntKind::Long);
1468        let char_ = types.int(IntKind::Char);
1469        let float = types.float(FloatKind::Float);
1470        let double = types.float(FloatKind::Double);
1471
1472        let takes_int = prototype(&mut types, vec![int], false);
1473        assert!(compatible(&types, old, takes_int));
1474        assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1475        // The composite is the prototype, so the calls written before it can still be checked.
1476        assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1477
1478        let pointer = types.pointer(int);
1479        for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1480            let ty = prototype(&mut types, params, false);
1481            assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1482        }
1483
1484        // A `char` promotes to `int` and a `float` to `double`, so a call through the old style
1485        // declaration would have passed something else and the two conflict.
1486        for params in [vec![char_], vec![float], vec![int, char_]] {
1487            let ty = prototype(&mut types, params, false);
1488            assert!(!compatible(&types, old, ty));
1489            assert_eq!(composite(&mut types, old, ty), None);
1490        }
1491
1492        // An ellipsis conflicts too, which gcc also says in as many words.
1493        let variadic = prototype(&mut types, vec![int], true);
1494        assert!(!compatible(&types, old, variadic));
1495
1496        // An enumeration parameter comes through when what it is represented in does.
1497        let uint = types.int(IntKind::UInt);
1498        let id = types.declare_enum(None);
1499        types.complete_enum(id, uint, false);
1500        let e = types.enumeration(id);
1501        let takes_enum = prototype(&mut types, vec![e], false);
1502        assert!(compatible(&types, old, takes_enum));
1503
1504        // Two old style declarations agree about nothing and so cannot disagree.
1505        assert!(compatible(&types, old, old));
1506
1507        // The return type still has to match, which is the one part `()` does say.
1508        let returns_int = types.function(FunctionType {
1509            ret: int,
1510            params: Vec::new(),
1511            variadic: false,
1512            prototyped: false,
1513        });
1514        assert!(!compatible(&types, returns_int, takes_int));
1515    }
1516
1517    #[test]
1518    fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1519        // The dialect decides what `()` means and the parser records the decision, so the same
1520        // pair of declarations is a redeclaration in C17 and a conflict in C23. Both compilers
1521        // report exactly that.
1522        let mut types = Types::new();
1523        let int = types.int(IntKind::Int);
1524        let takes_int = prototype(&mut types, vec![int], false);
1525        let takes_nothing = prototype(&mut types, Vec::new(), false);
1526        let old = old_style(&mut types);
1527        assert!(!compatible(&types, takes_nothing, takes_int));
1528        assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1529    }
1530
1531    #[test]
1532    fn two_prototypes_have_to_agree_about_everything() {
1533        let mut types = Types::new();
1534        let int = types.int(IntKind::Int);
1535        let long = types.int(IntKind::Long);
1536        let base = prototype(&mut types, vec![int, int], false);
1537        for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1538            let other = prototype(&mut types, other, false);
1539            assert!(!compatible(&types, base, other));
1540        }
1541        let variadic = prototype(&mut types, vec![int, int], true);
1542        assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1543
1544        // The parameters are compared with the same rules as anything else, so an array size
1545        // inside a parameter's type is compared and an unknown one is not.
1546        let four = types.array(int, ArrayLen::Fixed(4));
1547        let unknown = types.array(int, ArrayLen::Unknown);
1548        let to_four = types.pointer(four);
1549        let to_unknown = types.pointer(unknown);
1550        let a = prototype(&mut types, vec![to_four], false);
1551        let b = prototype(&mut types, vec![to_unknown], false);
1552        assert!(compatible(&types, a, b));
1553        // And the composite takes the size, which is the whole reason it exists.
1554        assert_eq!(composite(&mut types, a, b), Some(a));
1555    }
1556
1557    #[test]
1558    fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1559        let mut types = Types::new();
1560        let int = types.int(IntKind::Int);
1561        let four = types.array(int, ArrayLen::Fixed(4));
1562        let unknown = types.array(int, ArrayLen::Unknown);
1563        let to_four = types.pointer(four);
1564        let to_unknown = types.pointer(unknown);
1565        assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1566
1567        // The pointer's own qualifiers survive, since a compatible pair has the same ones.
1568        let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1569        let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1570        assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1571    }
1572
1573    #[test]
1574    fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1575        // C23 6.2.7p1, which is what lets one header be included twice. clang 18 implements it
1576        // and gcc 13.3 still rejects the redefinition, so this is a divergence rather than a
1577        // reading; in the older dialects the redefinition never gets as far as being compared.
1578        let mut interner = Interner::new();
1579        let mut types = Types::new();
1580        let tag = interner.intern("point");
1581        let x = interner.intern("x");
1582        let y = interner.intern("y");
1583        let int = types.int(IntKind::Int);
1584        let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1585
1586        let first = tagged(&mut types, tag, &members);
1587        let second = tagged(&mut types, tag, &members);
1588        let first = types.record(first);
1589        let second = types.record(second);
1590        assert_ne!(first, second, "still two declarations and two types");
1591        assert!(compatible(&types, first, second));
1592
1593        // A different member name, a different member type, a different count, a different tag
1594        // and a different keyword are each enough to make them different types.
1595        let z = interner.intern("z");
1596        let long = types.int(IntKind::Long);
1597        let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1598        let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1599        for other in [&renamed[..], &retyped[..], &members[..1]] {
1600            let other = tagged(&mut types, tag, other);
1601            let other = types.record(other);
1602            assert!(!compatible(&types, first, other));
1603        }
1604        let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1605        let elsewhere = types.record(elsewhere);
1606        assert!(!compatible(&types, first, elsewhere));
1607
1608        // An anonymous record is compatible with nothing but itself: there is no name by which
1609        // a second declaration could be claiming to be the same type.
1610        let anonymous = record(&mut types, RecordKind::Struct, &members);
1611        let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1612        assert!(!compatible(&types, anonymous, also_anonymous));
1613
1614        // Nor is an incomplete declaration, which has no members to compare.
1615        let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1616        let incomplete = types.record(incomplete);
1617        assert!(!compatible(&types, first, incomplete));
1618        assert!(compatible(&types, incomplete, incomplete));
1619    }
1620
1621    #[test]
1622    fn a_self_referential_record_is_compared_without_going_round_forever() {
1623        // `struct node { int value; struct node *next; }` declared twice. Comparing the two
1624        // reaches the same pair again through the pointer, and the second time it is an
1625        // assumption rather than a question.
1626        let mut interner = Interner::new();
1627        let mut types = Types::new();
1628        let tag = interner.intern("node");
1629        let value = interner.intern("value");
1630        let next = interner.intern("next");
1631        let int = types.int(IntKind::Int);
1632
1633        let node = |types: &mut Types| {
1634            let id = types.declare_record(RecordKind::Struct, Some(tag));
1635            let ty = types.record(id);
1636            let pointer = types.pointer(ty);
1637            let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1638            let laid_out = lay_out(types, RecordKind::Struct, &members);
1639            types.complete_record(id, laid_out);
1640            ty
1641        };
1642        let first = node(&mut types);
1643        let second = node(&mut types);
1644        assert_ne!(first, second);
1645        assert!(compatible(&types, first, second));
1646
1647        // The guard is an assumption and not an answer, so a difference below the cycle is still
1648        // found: the same structure with the two members the other way round is a different one.
1649        let id = types.declare_record(RecordKind::Struct, Some(tag));
1650        let ty = types.record(id);
1651        let pointer = types.pointer(ty);
1652        let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1653        let laid_out = lay_out(&types, RecordKind::Struct, &members);
1654        types.complete_record(id, laid_out);
1655        assert!(!compatible(&types, first, ty));
1656    }
1657
1658    #[test]
1659    fn layout_reads_through_sugar() {
1660        let mut interner = Interner::new();
1661        let mut types = Types::new();
1662        let long = types.int(IntKind::Long);
1663        let name = types.typedef(interner.intern("word"), long);
1664        let array = types.array(name, ArrayLen::Fixed(4));
1665        assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1666    }
1667}