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 3, 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.11.9")]
82
83mod classify;
84mod compat;
85mod convert;
86mod granule;
87mod kind;
88mod layout;
89mod print;
90mod record;
91mod types;
92
93pub use crate::classify::{
94    element, is_aggregate, is_arithmetic, is_array, is_atomic, is_complete, is_complex,
95    is_floating, is_function, is_integer, is_modifiable, is_object, is_pointer, is_real,
96    is_real_floating, is_record, is_scalar, is_vector, is_void, lanes, pointee, pointee_as_written,
97    real_part,
98};
99pub use crate::compat::{adjust_parameter, compatible, composite};
100pub use crate::convert::{
101    mask_of, promote, promote_bit_field, usual_arithmetic, vectors_convertible,
102};
103pub use crate::granule::{GRANULE, Keying, Tally, measure, measure_all, report as granule_report};
104pub use crate::kind::{
105    ArrayLen, EnumId, FloatKind, FunctionId, FunctionType, IntKind, Qualifiers, RecordId,
106    RecordKind, Type, TypeKind, VlaId,
107};
108pub use crate::layout::{
109    IntegerInfo, Layout, LayoutError, align, float_format, float_width, int_width, integer_info,
110    layout,
111};
112pub use crate::print::{declare, spell};
113pub use crate::record::{
114    Extent, Field, FieldDecl, RecordError, RecordLayout, RecordOptions, VariableLayout,
115    layout_record,
116};
117pub use crate::types::{Alias, EnumInfo, Enumerator, RecordInfo, Spelled, TypeId, Types};
118
119/// The milestone in `spec/17-milestones.md` that fills this crate in.
120pub const MILESTONE: &str = "M2";
121
122#[cfg(test)]
123mod tests {
124    use std::num::NonZeroU32;
125
126    use rucc_base::{Interner, Symbol};
127    use rucc_target::{TargetInfo, Triple};
128
129    use super::*;
130
131    fn target(triple: &str) -> TargetInfo {
132        TargetInfo::new(triple.parse::<Triple>().expect("a triple the compiler supports"))
133    }
134
135    fn linux() -> TargetInfo {
136        target("x86_64-unknown-linux-gnu")
137    }
138
139    /// The one target in the table that runs Microsoft's bit-field rule. So does
140    /// `x86_64-pc-windows-gnu`, and the tests below say so where it matters, because a rule keyed
141    /// on the environment rather than on the operating system would pass every one of them.
142    fn windows() -> TargetInfo {
143        target("x86_64-pc-windows-msvc")
144    }
145
146    /// AAPCS64 proper, where an unnamed bit-field raises the record's alignment. Apple's AArch64
147    /// dropped that, so `aarch64-apple-darwin` answers the way x86-64 does and is the pair to
148    /// this one wherever the difference is being measured.
149    fn aapcs() -> TargetInfo {
150        target("aarch64-unknown-linux-gnu")
151    }
152
153    /// Lays out a record with no attributes on it, on x86-64 Linux.
154    fn lay_out(types: &Types, kind: RecordKind, fields: &[FieldDecl]) -> RecordLayout {
155        lay_out_on(&linux(), types, kind, fields)
156    }
157
158    /// Lays out a record with no attributes on it, on a named target.
159    fn lay_out_on(
160        target: &TargetInfo,
161        types: &Types,
162        kind: RecordKind,
163        fields: &[FieldDecl],
164    ) -> RecordLayout {
165        layout_record(types, kind, fields, &RecordOptions::default(), target)
166            .expect("a record every member of which has a layout")
167    }
168
169    /// The offsets of the members, in bits, which is what a measurement of a real compiler
170    /// gives back once its byte offsets and its bit dumps are put together.
171    fn offsets(laid_out: &RecordLayout) -> Vec<u128> {
172        laid_out.fields.iter().map(Field::bit_offset).collect()
173    }
174
175    /// A complete record type built out of the given members.
176    fn record(types: &mut Types, kind: RecordKind, fields: &[FieldDecl]) -> TypeId {
177        let id = types.declare_record(kind, None);
178        let laid_out = lay_out(types, kind, fields);
179        types.complete_record(id, laid_out);
180        types.record(id)
181    }
182
183    /// An ordinary member of the given type, unnamed, which is all most of these tests need.
184    fn member(ty: TypeId) -> FieldDecl {
185        FieldDecl::new(None, ty)
186    }
187
188    /// A named bit-field, which is what a measurement of a real compiler has to use to be able
189    /// to read the field back.
190    fn bits(interner: &mut Interner, name: &str, ty: TypeId, width: u32) -> FieldDecl {
191        FieldDecl::bit_field(Some(interner.intern(name)), ty, width)
192    }
193
194    /// An unnamed bit-field, which occupies bits and raises nothing.
195    fn unnamed_bits(ty: TypeId, width: u32) -> FieldDecl {
196        FieldDecl::bit_field(None, ty, width)
197    }
198
199    #[test]
200    fn milestone_is_recorded() {
201        assert!(MILESTONE.starts_with('M'));
202    }
203
204    #[test]
205    fn an_integer_type_answers_with_the_width_of_its_value_and_not_of_its_object() {
206        let mut interner = Interner::new();
207        let mut types = Types::new();
208        let target = linux();
209
210        // A `bool` is one byte and holds one bit, and a `_BitInt(37)` is eight bytes and holds
211        // thirty seven. Folding a constant in the size rather than the width gets both wrong.
212        let boolean = types.boolean();
213        let bits = types.bit_int(true, 37);
214        // Through the sugar, the qualifiers and `_Atomic`, none of which is part of a value.
215        let short = types.int(IntKind::Short);
216        let alias = types.typedef(interner.intern("word"), short);
217        let unsigned_char = types.int(IntKind::UChar);
218        let atomic = types.atomic(unsigned_char);
219
220        let shape = |ty| integer_info(&types, ty, &target).expect("an integer type");
221        assert_eq!(shape(boolean), IntegerInfo::new(false, 1));
222        assert_eq!(shape(bits), IntegerInfo::new(true, 37));
223        assert_eq!(shape(types.int(IntKind::Int)), IntegerInfo::new(true, 32));
224        assert_eq!(shape(types.int(IntKind::ULong)), IntegerInfo::new(false, 64));
225        assert_eq!(shape(alias), IntegerInfo::new(true, 16));
226        assert_eq!(shape(atomic), IntegerInfo::new(false, 8));
227
228        assert_eq!(integer_info(&types, types.float(FloatKind::Double), &target), None);
229    }
230
231    #[test]
232    fn an_enumeration_answers_with_the_type_the_enumerators_are_kept_in() {
233        let mut interner = Interner::new();
234        let mut types = Types::new();
235        let target = linux();
236
237        // An enumeration that has not been completed has no underlying type yet, and the answer
238        // is that there is no answer rather than a guess at `int` that a later `: long` unsays.
239        let colour = types.declare_enum(Some(interner.intern("colour")));
240        let ty = types.enumeration(colour);
241        assert_eq!(integer_info(&types, ty, &target), None);
242
243        let underlying = types.int(IntKind::ULong);
244        types.complete_enum(colour, underlying, true);
245        assert_eq!(integer_info(&types, ty, &target), Some(IntegerInfo::new(false, 64)));
246    }
247
248    #[test]
249    fn a_value_stored_in_an_integer_type_keeps_the_bits_the_type_has_room_for() {
250        let char_type = IntegerInfo::new(true, 8);
251        assert_eq!(char_type.wrap(300), 44);
252        assert!(!char_type.holds(300));
253        assert!(char_type.holds(-128));
254
255        assert_eq!(IntegerInfo::new(false, 32).wrap(-1), 4_294_967_295);
256        assert_eq!(IntegerInfo::new(false, 8).wrap(-1), 255);
257
258        // Every pattern is a value of a hundred and twenty eight bit type, of either signedness,
259        // which is what stops the folding from inventing an overflow at the widest type there is.
260        assert!(IntegerInfo::new(false, 128).holds(i128::MIN));
261        assert!(IntegerInfo::new(true, 128).holds(i128::MIN));
262        assert_eq!(IntegerInfo::new(true, 128).wrap(i128::MAX), i128::MAX);
263    }
264
265    #[test]
266    fn a_long_double_has_a_format_the_size_does_not_give_away() {
267        let target = linux();
268        // Sixteen bytes on SysV x86-64 and eighty bits of x87 inside them. A compiler that
269        // picked the format by the size would fold every one of those constants too finely.
270        assert_eq!(float_width(FloatKind::LongDouble, &target), 128);
271        assert_eq!(
272            float_format(FloatKind::LongDouble, &target),
273            rucc_base::float::Format::X87Extended
274        );
275        assert_eq!(float_format(FloatKind::Float, &target), rucc_base::float::Format::Single);
276    }
277
278    #[test]
279    fn an_interchange_type_names_a_format_and_an_extended_one_names_the_target() {
280        use rucc_base::float::Format;
281
282        // The four `_FloatN` types are the same format everywhere, which is the point of them,
283        // so a program that wants binary128 can say so and get it or get told it cannot.
284        for target in [&linux(), &target("aarch64-apple-darwin")] {
285            assert_eq!(float_format(FloatKind::Float16, target), Format::Half);
286            assert_eq!(float_format(FloatKind::Float32, target), Format::Single);
287            assert_eq!(float_format(FloatKind::Float64, target), Format::Double);
288            assert_eq!(float_format(FloatKind::Float128, target), Format::Quad);
289            assert_eq!(float_width(FloatKind::Float16, target), 16);
290            assert_eq!(float_width(FloatKind::Float32, target), 32);
291            assert_eq!(float_width(FloatKind::Float64, target), 64);
292            assert_eq!(float_width(FloatKind::Float128, target), 128);
293            // `_Float32x` is `double` on every target this compiles for.
294            assert_eq!(float_format(FloatKind::Float32x, target), Format::Double);
295        }
296
297        // `_Float64x` is the one that moves, and it moves with the processor rather than with
298        // the operating system, so it stays eighty bits of x87 on x86-64 where `long double`
299        // is the same thing and is quad on Apple where `long double` is only a `double`.
300        let x86 = linux();
301        assert_eq!(float_format(FloatKind::Float64x, &x86), Format::X87Extended);
302        assert_eq!(float_format(FloatKind::LongDouble, &x86), Format::X87Extended);
303        let mac = target("aarch64-apple-darwin");
304        assert_eq!(float_format(FloatKind::Float64x, &mac), Format::Quad);
305        assert_eq!(float_format(FloatKind::LongDouble, &mac), Format::Double);
306        // Sixteen bytes either way, because the x87 eighty bits are stored padded, which is
307        // the same reason `long double` is sixteen bytes on x86-64 and not ten.
308        assert_eq!(float_width(FloatKind::Float64x, &x86), 128);
309        assert_eq!(float_width(FloatKind::Float64x, &mac), 128);
310    }
311
312    #[test]
313    fn every_floating_type_is_as_wide_as_the_format_it_is_stored_in() {
314        let types = Types::new();
315        let sizes = |target: &TargetInfo| -> Vec<(u64, u64)> {
316            FloatKind::ALL
317                .iter()
318                .map(|&kind| {
319                    let found = layout(&types, types.float(kind), target).expect("a complete type");
320                    (found.size, found.align)
321                })
322                .collect()
323        };
324        // Read off gcc 16 with `sizeof` and `_Alignof`, in the order of `FloatKind::ALL`. The
325        // two targets differ in one place, which is `long double`, and the eighty bit x87 value
326        // that `long double` and `_Float64x` hold on x86-64 takes sixteen bytes to store.
327        assert_eq!(
328            sizes(&linux()),
329            [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16), (16, 16)]
330        );
331        assert_eq!(
332            sizes(&target("aarch64-apple-darwin")),
333            [(2, 2), (4, 4), (4, 4), (8, 8), (8, 8), (8, 8), (8, 8), (16, 16), (16, 16)]
334        );
335    }
336
337    #[test]
338    fn every_floating_type_has_a_slot_of_its_own_and_a_name_of_its_own() {
339        // Nine types and nine ids, which is what makes `_Float64` and `double` two types that
340        // `_Generic` can tell apart rather than one type with two spellings.
341        let types = Types::new();
342        let mut seen = Vec::new();
343        for kind in FloatKind::ALL {
344            seen.push(types.float(kind));
345        }
346        let mut sorted = seen.clone();
347        sorted.sort_unstable();
348        sorted.dedup();
349        assert_eq!(sorted.len(), seen.len(), "two floating types share an id");
350
351        let names: Vec<&str> = FloatKind::ALL.iter().map(|kind| kind.as_str()).collect();
352        assert_eq!(
353            names,
354            [
355                "_Float16",
356                "float",
357                "_Float32",
358                "double",
359                "_Float32x",
360                "_Float64",
361                "long double",
362                "_Float64x",
363                "_Float128",
364            ]
365        );
366    }
367
368    #[test]
369    fn the_same_type_asked_for_twice_is_the_same_id() {
370        let mut types = Types::new();
371        let a = types.pointer(types.int(IntKind::Int));
372        let b = types.pointer(types.int(IntKind::Int));
373        assert_eq!(a, b, "interning is what makes type identity an integer comparison");
374        let c = types.pointer(types.int(IntKind::Long));
375        assert_ne!(a, c);
376    }
377
378    #[test]
379    fn a_qualifier_makes_a_different_type_with_the_same_shape() {
380        let mut types = Types::new();
381        let int = types.int(IntKind::Int);
382        let konst = types.qualified(int, Qualifiers::CONST);
383        assert_ne!(int, konst);
384        assert_eq!(types.kind(konst), types.kind(int));
385        assert!(types.quals(konst).has(Qualifiers::CONST));
386        assert_eq!(types.unqualified(konst), int);
387    }
388
389    #[test]
390    fn qualifiers_accumulate_and_do_not_depend_on_the_order_they_were_written() {
391        let mut types = Types::new();
392        let int = types.int(IntKind::Int);
393        let a = types.qualified(int, Qualifiers::CONST);
394        let a = types.qualified(a, Qualifiers::VOLATILE);
395        let b = types.qualified(int, Qualifiers::VOLATILE);
396        let b = types.qualified(b, Qualifiers::CONST);
397        assert_eq!(a, b, "`const volatile int` and `volatile const int` are one type");
398    }
399
400    #[test]
401    fn qualifying_an_array_qualifies_its_element() {
402        // 6.7.3p10, and not a shortcut. An array type has no qualifiers of its own, so if this
403        // put the `const` on the array then `const` on an array parameter would mean nothing.
404        let mut types = Types::new();
405        let int = types.int(IntKind::Int);
406        let array = types.array(int, ArrayLen::Fixed(4));
407        let konst = types.qualified(array, Qualifiers::CONST);
408        assert!(types.quals(konst).is_none(), "the array itself is unqualified");
409        let TypeKind::Array { elem, len } = types.kind(konst) else {
410            panic!("still an array");
411        };
412        assert_eq!(len, ArrayLen::Fixed(4));
413        assert!(types.quals(elem).has(Qualifiers::CONST));
414    }
415
416    #[test]
417    fn a_typedef_is_a_different_type_that_means_the_same_thing() {
418        let mut interner = Interner::new();
419        let mut types = Types::new();
420        let int = types.int(IntKind::Int);
421        let name = types.typedef(interner.intern("int32_t"), int);
422        assert_ne!(name, int, "the sugar survives, so a diagnostic can print it");
423        assert_eq!(types.canonical(name), int, "and no rule ever sees it");
424        assert!(types.is_sugar(name));
425        assert!(!types.is_sugar(int));
426    }
427
428    /// The names are a list beside the table and change nothing about what a type is.
429    ///
430    /// Two names for one type are one type, which is the whole reason they are kept here rather
431    /// than interned: the list grows and the identifiers do not, so the equality of two type
432    /// identifiers still means the two are the same type.
433    #[test]
434    fn a_typedef_name_is_recorded_without_making_a_type_of_its_own() {
435        let mut interner = Interner::new();
436        let mut types = Types::new();
437        let int = types.int(IntKind::Int);
438        types.alias(interner.intern("int32_t"), int);
439        types.alias(interner.intern("word"), int);
440        types.alias(interner.intern("int32_t"), int);
441        let names: Vec<_> =
442            types.aliases().iter().map(|had| interner.resolve(had.name).to_owned()).collect();
443        assert_eq!(names, ["int32_t", "word"], "the same name twice is one entry");
444        assert!(types.aliases().iter().all(|had| had.of == int));
445        assert_eq!(types.int(IntKind::Int), int, "and the type is the type it was");
446    }
447
448    #[test]
449    fn sugar_below_the_outermost_node_is_resolved_too() {
450        // The bug this is here for: canonicalising only the top node leaves `int32_t *` and
451        // `int *` as different types, and then every rule stated on pointers stops firing.
452        let mut interner = Interner::new();
453        let mut types = Types::new();
454        let int = types.int(IntKind::Int);
455        let name = types.typedef(interner.intern("int32_t"), int);
456        let sugar_pointer = types.pointer(name);
457        let plain_pointer = types.pointer(int);
458        assert_ne!(sugar_pointer, plain_pointer);
459        assert_eq!(types.canonical(sugar_pointer), plain_pointer);
460
461        let sugar_array = types.array(name, ArrayLen::Fixed(3));
462        let plain_array = types.array(int, ArrayLen::Fixed(3));
463        assert_eq!(types.canonical(sugar_array), plain_array);
464    }
465
466    #[test]
467    fn a_typedef_of_a_typedef_canonicalises_all_the_way_down() {
468        let mut interner = Interner::new();
469        let mut types = Types::new();
470        let int = types.int(IntKind::Int);
471        let mut current = int;
472        for i in 0..8 {
473            current = types.typedef(interner.intern(&format!("t{i}")), current);
474        }
475        assert_eq!(types.canonical(current), int);
476    }
477
478    #[test]
479    fn a_typedef_that_asked_for_an_alignment_says_what_it_is_and_not_what_it_is_at_least() {
480        // `__attribute__((aligned(n)))` in this one position replaces the alignment rather than
481        // raising it, which is what lets `typedef int L __attribute__((aligned(2)))` really be an
482        // `int` at a multiple of two. The size is left where it was, which is gcc's answer and the
483        // reason an array of an over aligned typedef is refused rather than padded.
484        let mut interner = Interner::new();
485        let mut types = Types::new();
486        let target = linux();
487        let int = types.int(IntKind::Int);
488        let low = types.aligned_typedef(interner.intern("L"), int, NonZeroU32::new(2).unwrap());
489        let high = types.aligned_typedef(interner.intern("H"), int, NonZeroU32::new(16).unwrap());
490
491        assert_eq!(layout(&types, low, &target), Ok(Layout::new(4, 2)));
492        assert_eq!(layout(&types, high, &target), Ok(Layout::new(4, 16)));
493        // And the type behind them is what it always was, since the alignment belongs to the name
494        // and not to the `int`.
495        assert_eq!(layout(&types, int, &target), Ok(Layout::new(4, 4)));
496
497        // Two names for one type that asked for different alignments are two types, which is why
498        // the alignment is part of what the table interns them by.
499        assert_ne!(low, high);
500
501        // The nearest one wins, because the outer typedef is the one a declaration was written
502        // with, and one that asked for nothing keeps whatever the one below it asked for.
503        let outer = types.aligned_typedef(interner.intern("M"), low, NonZeroU32::new(8).unwrap());
504        assert_eq!(types.align_override(outer), NonZeroU32::new(8));
505        let plain = types.typedef(interner.intern("N"), low);
506        assert_eq!(types.align_override(plain), NonZeroU32::new(2));
507        // Below the sugar there is nothing to find, since only a typedef can carry one of these.
508        assert_eq!(types.align_override(int), None);
509    }
510
511    #[test]
512    fn a_qualified_typedef_keeps_the_name_and_canonicalises_to_the_qualified_type() {
513        let mut interner = Interner::new();
514        let mut types = Types::new();
515        let int = types.int(IntKind::Int);
516        let name = types.typedef(interner.intern("int32_t"), int);
517        let konst = types.qualified(name, Qualifiers::CONST);
518        assert!(matches!(types.kind(konst), TypeKind::Typedef { .. }), "still prints as int32_t");
519        let want = types.qualified(int, Qualifiers::CONST);
520        assert_eq!(types.canonical(konst), want);
521    }
522
523    #[test]
524    fn a_typedef_of_an_array_pushes_a_qualifier_to_the_element_when_it_canonicalises() {
525        // `typedef int A[4]; const A x;` declares an array of `const int`, which is where the
526        // array rule and the sugar rule have to agree with each other.
527        let mut interner = Interner::new();
528        let mut types = Types::new();
529        let int = types.int(IntKind::Int);
530        let array = types.array(int, ArrayLen::Fixed(4));
531        let name = types.typedef(interner.intern("A"), array);
532        let konst = types.qualified(name, Qualifiers::CONST);
533        let konst_int = types.qualified(int, Qualifiers::CONST);
534        let want = types.array(konst_int, ArrayLen::Fixed(4));
535        assert_eq!(types.canonical(konst), want);
536    }
537
538    #[test]
539    fn a_function_type_is_deduplicated_by_its_signature() {
540        let mut types = Types::new();
541        let int = types.int(IntKind::Int);
542        let long = types.int(IntKind::Long);
543        let make = |types: &mut Types, params: Vec<TypeId>, variadic| {
544            types.function(FunctionType { ret: int, params, variadic, prototyped: true })
545        };
546        let a = make(&mut types, vec![int, long], false);
547        let b = make(&mut types, vec![int, long], false);
548        assert_eq!(a, b);
549        assert_ne!(a, make(&mut types, vec![int, long], true), "`...` is part of the type");
550        assert_ne!(a, make(&mut types, vec![long, int], false));
551    }
552
553    #[test]
554    fn a_function_type_written_with_a_typedef_canonicalises_through_its_signature() {
555        let mut interner = Interner::new();
556        let mut types = Types::new();
557        let int = types.int(IntKind::Int);
558        let name = types.typedef(interner.intern("int32_t"), int);
559        let sugar = types.function(FunctionType {
560            ret: name,
561            params: vec![name],
562            variadic: false,
563            prototyped: true,
564        });
565        let plain = types.function(FunctionType {
566            ret: int,
567            params: vec![int],
568            variadic: false,
569            prototyped: true,
570        });
571        assert_ne!(sugar, plain);
572        assert_eq!(types.canonical(sugar), plain);
573    }
574
575    #[test]
576    fn a_record_is_its_declaration_and_not_its_members() {
577        // Two structs written the same way in one translation unit are different types. The
578        // looser relation that does hold between them is compatibility, which is a separate
579        // question from identity and is answered elsewhere.
580        let mut interner = Interner::new();
581        let mut types = Types::new();
582        let tag = interner.intern("point");
583        let first = types.declare_record(RecordKind::Struct, Some(tag));
584        let second = types.declare_record(RecordKind::Struct, Some(tag));
585        assert_ne!(types.record(first), types.record(second));
586        assert_eq!(types.record(first), types.record(first));
587    }
588
589    #[test]
590    fn a_record_has_no_layout_until_it_has_been_completed() {
591        let mut types = Types::new();
592        let id = types.declare_record(RecordKind::Struct, None);
593        let ty = types.record(id);
594        assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
595        let long_long = types.int(IntKind::LongLong);
596        let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long); 2]);
597        types.complete_record(id, laid_out);
598        assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(16, 8));
599    }
600
601    #[test]
602    fn an_enum_takes_the_layout_of_its_underlying_type() {
603        let mut types = Types::new();
604        let id = types.declare_enum(None);
605        let ty = types.enumeration(id);
606        assert_eq!(layout(&types, ty, &linux()), Err(LayoutError::Incomplete));
607        let int = types.int(IntKind::Int);
608        types.complete_enum(id, int, false);
609        assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(4, 4));
610    }
611
612    #[test]
613    fn the_scalar_widths_come_from_the_target() {
614        let mut types = Types::new();
615        let linux = linux();
616        let windows = target("x86_64-pc-windows-msvc");
617        let darwin = target("aarch64-apple-darwin");
618
619        let long = types.int(IntKind::Long);
620        assert_eq!(layout(&types, long, &linux).unwrap(), Layout::new(8, 8));
621        assert_eq!(layout(&types, long, &windows).unwrap(), Layout::new(4, 4), "LLP64");
622
623        let ldouble = types.float(FloatKind::LongDouble);
624        assert_eq!(layout(&types, ldouble, &linux).unwrap(), Layout::new(16, 16));
625        assert_eq!(layout(&types, ldouble, &darwin).unwrap(), Layout::new(8, 8));
626
627        let pointer = types.pointer(types.void());
628        assert_eq!(layout(&types, pointer, &linux).unwrap(), Layout::new(8, 8));
629
630        let boolean = types.boolean();
631        assert_eq!(layout(&types, boolean, &linux).unwrap(), Layout::new(1, 1));
632    }
633
634    #[test]
635    fn a_complex_type_is_two_of_its_component_with_the_components_alignment() {
636        // `_Complex long double` on SysV x86-64 is thirty two bytes aligned to sixteen, which
637        // is the case that catches an implementation that aligns the pair to its own size.
638        let mut types = Types::new();
639        let linux = linux();
640        let cfloat = types.complex_float(FloatKind::Float);
641        assert_eq!(layout(&types, cfloat, &linux).unwrap(), Layout::new(8, 4));
642        let cdouble = types.complex_float(FloatKind::Double);
643        assert_eq!(layout(&types, cdouble, &linux).unwrap(), Layout::new(16, 8));
644        let cldouble = types.complex_float(FloatKind::LongDouble);
645        assert_eq!(layout(&types, cldouble, &linux).unwrap(), Layout::new(32, 16));
646        let darwin = target("aarch64-apple-darwin");
647        assert_eq!(layout(&types, cldouble, &darwin).unwrap(), Layout::new(16, 8));
648    }
649
650    #[test]
651    fn an_atomic_type_can_be_more_aligned_than_the_type_it_wraps() {
652        // The whole reason `_Atomic` is a type here rather than a qualifier. A sixteen byte
653        // record is aligned to eight and the atomic version of it is aligned to sixteen.
654        let mut types = Types::new();
655        let linux = linux();
656        let long_long = types.int(IntKind::LongLong);
657        let plain = record(&mut types, RecordKind::Struct, &[member(long_long); 2]);
658        let atomic = types.atomic(plain);
659        assert_eq!(layout(&types, plain, &linux).unwrap(), Layout::new(16, 8));
660        assert_eq!(layout(&types, atomic, &linux).unwrap(), Layout::new(16, 16));
661
662        // An odd size cannot be accessed atomically in one go, so nothing is raised.
663        let odd = record(&mut types, RecordKind::Struct, &[member(long_long); 3]);
664        let atomic_odd = types.atomic(odd);
665        assert_eq!(layout(&types, atomic_odd, &linux).unwrap(), Layout::new(24, 8));
666
667        let int = types.int(IntKind::Int);
668        let atomic_int = types.atomic(int);
669        assert_eq!(layout(&types, atomic_int, &linux).unwrap(), Layout::new(4, 4));
670    }
671
672    #[test]
673    fn a_bit_int_is_laid_out_like_a_standard_integer_until_it_outgrows_one() {
674        // Measured with clang 18 on x86-64 Linux and clang on AArch64 Darwin. The two disagree
675        // above sixty four bits, which is why the granule is a target fact.
676        let mut types = Types::new();
677        let linux = linux();
678        let darwin = target("aarch64-apple-darwin");
679        let cases = [(7, 1, 1), (8, 1, 1), (9, 2, 2), (17, 4, 4), (33, 8, 8), (64, 8, 8)];
680        for (width, size, align) in cases {
681            let ty = types.bit_int(true, width);
682            assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(size, align), "{width}");
683            assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(size, align), "{width}");
684        }
685        for width in [65, 96, 128] {
686            let ty = types.bit_int(false, width);
687            assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(16, 8), "{width}");
688            assert_eq!(layout(&types, ty, &darwin).unwrap(), Layout::new(16, 16), "{width}");
689        }
690        let wide = types.bit_int(true, 129);
691        assert_eq!(layout(&types, wide, &linux).unwrap(), Layout::new(24, 8));
692        assert_eq!(layout(&types, wide, &darwin).unwrap(), Layout::new(32, 16));
693    }
694
695    #[test]
696    fn an_array_is_its_element_repeated_and_keeps_its_elements_alignment() {
697        let mut types = Types::new();
698        let linux = linux();
699        let int = types.int(IntKind::Int);
700        let ty = types.array(int, ArrayLen::Fixed(10));
701        assert_eq!(layout(&types, ty, &linux).unwrap(), Layout::new(40, 4));
702        let nested = types.array(ty, ArrayLen::Fixed(3));
703        assert_eq!(layout(&types, nested, &linux).unwrap(), Layout::new(120, 4));
704    }
705
706    #[test]
707    fn an_array_without_a_size_is_incomplete_and_an_impossible_one_says_so() {
708        let mut types = Types::new();
709        let linux = linux();
710        let int = types.int(IntKind::Int);
711        for len in [ArrayLen::Unknown, ArrayLen::Star] {
712            let ty = types.array(int, len);
713            assert_eq!(layout(&types, ty, &linux), Err(LayoutError::Incomplete));
714        }
715        // An array whose length the program computes is a different answer from an incomplete
716        // one, because it is not a mistake: there is a size and this is not the place that
717        // knows it. A caller that only wants a number treats the two the same and a caller
718        // building the arithmetic asks for the members instead.
719        let measured = types.array(int, ArrayLen::Variable(VlaId(0)));
720        assert_eq!(layout(&types, measured, &linux), Err(LayoutError::Variable));
721        assert_eq!(align(&types, measured, &linux), Ok(4));
722        let huge = types.array(int, ArrayLen::Fixed(u64::MAX));
723        assert_eq!(layout(&types, huge, &linux), Err(LayoutError::TooLarge));
724    }
725
726    #[test]
727    fn the_largest_array_is_the_largest_object_and_not_the_largest_number() {
728        // The limit is `PTRDIFF_MAX` rather than wherever the multiplication happens to
729        // overflow, so an array of a byte may be every byte an object may have and one more
730        // than that is refused. gcc 16 gives the same two answers.
731        let mut types = Types::new();
732        let linux = linux();
733        let max = linux.max_object_size();
734        let ch = types.int(IntKind::Char);
735        let fits = types.array(ch, ArrayLen::Fixed(max));
736        assert_eq!(layout(&types, fits, &linux), Ok(Layout::new(max, 1)));
737        let over = types.array(ch, ArrayLen::Fixed(max + 1));
738        assert_eq!(layout(&types, over, &linux), Err(LayoutError::TooLarge));
739    }
740
741    #[test]
742    fn a_record_may_be_as_large_as_an_object_may_be_and_no_larger() {
743        // The shape `991014-1.c` in the gcc.c-torture execution suite asks about: a type
744        // nothing is ever an object of is still a type `sizeof` has to answer about. Counting
745        // the record in bits made the largest one an eighth of this, with the multiply by eight
746        // overflowing rather than any rule saying so.
747        let mut types = Types::new();
748        let linux = linux();
749        let max = linux.max_object_size();
750        let ch = types.int(IntKind::Char);
751        let int = types.int(IntKind::Int);
752        let short = types.int(IntKind::Short);
753
754        let huge = types.array(short, ArrayLen::Fixed((1 << 62) - 256));
755        let members = [member(huge), member(int), member(int), member(int), member(int)];
756        let laid_out = lay_out(&types, RecordKind::Struct, &members);
757        assert_eq!(laid_out.layout, Layout::new((1 << 63) - 496, 4));
758
759        let brim = types.array(ch, ArrayLen::Fixed(max));
760        let laid_out = lay_out(&types, RecordKind::Struct, &[member(brim)]);
761        assert_eq!(laid_out.layout, Layout::new(max, 1));
762
763        let over = [member(brim), member(ch)];
764        let options = RecordOptions::default();
765        let error = layout_record(&types, RecordKind::Struct, &over, &options, &linux);
766        assert_eq!(error, Err(RecordError::TooLarge));
767    }
768
769    #[test]
770    fn a_bit_field_past_where_a_bit_count_fits_is_still_placed() {
771        // Eight times the largest object is more than a `u64` holds, so a bit-field at the end
772        // of a record that large has a bit offset no bit count can name. It is a byte offset
773        // and a bit within it here, which is what lets this be laid out at all, and gcc 16
774        // gives the same size for it.
775        let mut types = Types::new();
776        let linux = linux();
777        let ch = types.int(IntKind::Char);
778        let int = types.int(IntKind::Int);
779        let mut interner = Interner::new();
780        let buf = types.array(ch, ArrayLen::Fixed(linux.max_object_size() - 7));
781        let members = [member(buf), bits(&mut interner, "x", int, 1)];
782        let laid_out = lay_out(&types, RecordKind::Struct, &members);
783        assert_eq!(laid_out.layout, Layout::new(9_223_372_036_854_775_804, 4));
784        let last = laid_out.fields[1];
785        assert_eq!((last.offset, last.bit), (9_223_372_036_854_775_800, 0));
786        assert_eq!(last.bit_offset(), 73_786_976_294_838_206_400);
787    }
788
789    #[test]
790    fn two_variable_length_arrays_of_the_same_element_are_still_different_types() {
791        let mut types = Types::new();
792        let int = types.int(IntKind::Int);
793        let a = types.array(int, ArrayLen::Variable(VlaId(0)));
794        let b = types.array(int, ArrayLen::Variable(VlaId(1)));
795        assert_ne!(a, b);
796    }
797
798    #[test]
799    fn a_vector_is_rounded_up_to_a_power_of_two_and_aligned_to_the_whole_thing() {
800        // What GCC does with a `vector_size` that is not already one, checked against clang on
801        // AArch64 Darwin, which accepts the three element case that GCC rejects outright.
802        let mut types = Types::new();
803        let linux = linux();
804        let int = types.int(IntKind::Int);
805        let four = types.vector(int, 4);
806        assert_eq!(layout(&types, four, &linux).unwrap(), Layout::new(16, 16));
807        let three = types.vector(int, 3);
808        assert_eq!(layout(&types, three, &linux).unwrap(), Layout::new(16, 16));
809        let three_chars = types.vector(types.int(IntKind::Char), 3);
810        assert_eq!(layout(&types, three_chars, &linux).unwrap(), Layout::new(4, 4));
811    }
812
813    #[test]
814    fn the_types_without_a_size_say_which_kind_of_without_they_are() {
815        // Kept apart because GNU C gives both of them a size of one and a different warning,
816        // and because a caller that cannot tell them apart cannot write either message.
817        let mut types = Types::new();
818        let linux = linux();
819        let void = types.void();
820        assert_eq!(layout(&types, void, &linux), Err(LayoutError::Incomplete));
821        let int = types.int(IntKind::Int);
822        let function = types.function(FunctionType {
823            ret: int,
824            params: Vec::new(),
825            variadic: false,
826            prototyped: true,
827        });
828        assert_eq!(layout(&types, function, &linux), Err(LayoutError::Function));
829        let pointer_to_function = types.pointer(function);
830        assert_eq!(layout(&types, pointer_to_function, &linux).unwrap(), Layout::new(8, 8));
831    }
832
833    #[test]
834    fn a_struct_puts_each_member_at_the_next_offset_it_is_allowed_to_start_at() {
835        let types = Types::new();
836        let char_ = types.int(IntKind::Char);
837        let int = types.int(IntKind::Int);
838        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(int)]);
839        assert_eq!(laid_out.layout, Layout::new(8, 4));
840        assert_eq!(offsets(&laid_out), [0, 32]);
841        assert_eq!(laid_out.fields[1].offset, 4);
842
843        // And the tail is padded, which is what makes an array of the thing work.
844        let long_long = types.int(IntKind::LongLong);
845        let laid_out = lay_out(&types, RecordKind::Struct, &[member(long_long), member(char_)]);
846        assert_eq!(laid_out.layout, Layout::new(16, 8));
847    }
848
849    #[test]
850    fn a_union_starts_every_member_at_zero_and_is_as_large_as_the_largest() {
851        let mut types = Types::new();
852        let char_ = types.int(IntKind::Char);
853        let int = types.int(IntKind::Int);
854        let laid_out = lay_out(&types, RecordKind::Union, &[member(char_), member(int)]);
855        assert_eq!(laid_out.layout, Layout::new(4, 4));
856        assert_eq!(offsets(&laid_out), [0, 0]);
857
858        // Nine bytes and a short is ten, not nine and not sixteen: the size is rounded up to
859        // the alignment rather than to the largest member.
860        let nine = types.array(char_, ArrayLen::Fixed(9));
861        let short = types.int(IntKind::Short);
862        let laid_out = lay_out(&types, RecordKind::Union, &[member(nine), member(short)]);
863        assert_eq!(laid_out.layout, Layout::new(10, 2));
864    }
865
866    #[test]
867    fn bit_fields_share_a_unit_until_one_of_them_would_span_two() {
868        // Measured with gcc 13.3 on x86-64 Linux and clang on AArch64 Darwin, including where
869        // the bits landed, by setting each field to all ones and dumping the bytes.
870        let mut interner = Interner::new();
871        let types = Types::new();
872        let char_ = types.int(IntKind::Char);
873        let int = types.int(IntKind::Int);
874        let long_long = types.int(IntKind::LongLong);
875
876        let fields = [bits(&mut interner, "a", int, 3), bits(&mut interner, "b", int, 5)];
877        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
878        assert_eq!(laid_out.layout, Layout::new(4, 4));
879        assert_eq!(offsets(&laid_out), [0, 3]);
880
881        // Thirty bits do not fit in what is left of the first int, so they start a new one.
882        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
883        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
884        assert_eq!(laid_out.layout, Layout::new(8, 4));
885        assert_eq!(offsets(&laid_out), [0, 32]);
886
887        // Thirty three bits of a `long long` do fit in what is left of the first one, because
888        // the unit is eight bytes rather than four, so they stay where they are.
889        let fields = [member(char_), bits(&mut interner, "b", long_long, 33)];
890        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
891        assert_eq!(laid_out.layout, Layout::new(8, 8));
892        assert_eq!(offsets(&laid_out), [0, 8]);
893
894        // An ordinary member after a bit-field starts at the next byte it is allowed to.
895        let fields = [bits(&mut interner, "a", int, 3), member(char_)];
896        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
897        assert_eq!(offsets(&laid_out), [0, 8]);
898    }
899
900    #[test]
901    fn a_zero_width_bit_field_moves_the_next_member_on_and_nothing_else() {
902        let types = Types::new();
903        let char_ = types.int(IntKind::Char);
904        let int = types.int(IntKind::Int);
905        let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
906        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
907        // Five bytes aligned to one: the zero width field pushed the second `char` to offset
908        // four without giving the record the alignment of an `int`. Both compilers report that.
909        assert_eq!(laid_out.layout, Layout::new(5, 1));
910        assert_eq!(offsets(&laid_out), [0, 32, 32]);
911        assert_eq!(laid_out.fields.len(), 3, "one field per declaration, so indices line up");
912
913        // With nothing after it the padding is still the record's, which is the half of the rule
914        // the case above hides: the second `char` ends further along than the zero width field
915        // does, so whether the field moved the size or only the next member never showed.
916        let trailing = [member(char_), unnamed_bits(int, 0)];
917        assert_eq!(lay_out(&types, RecordKind::Struct, &trailing).layout, Layout::new(4, 1));
918
919        // And a record that is nothing but the zero width field has nothing to pad, so it is the
920        // empty structure with the alignment of whatever the field's type was.
921        let only = [unnamed_bits(int, 0)];
922        assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
923    }
924
925    #[test]
926    fn an_unnamed_bit_field_does_not_raise_the_records_alignment_but_a_named_one_does() {
927        let mut interner = Interner::new();
928        let types = Types::new();
929        let char_ = types.int(IntKind::Char);
930        let int = types.int(IntKind::Int);
931
932        let unnamed = [member(char_), unnamed_bits(int, 20)];
933        let unnamed = lay_out(&types, RecordKind::Struct, &unnamed);
934        assert_eq!(unnamed.layout, Layout::new(4, 1));
935
936        let named = [member(char_), bits(&mut interner, "b", int, 20)];
937        let named = lay_out(&types, RecordKind::Struct, &named);
938        assert_eq!(named.layout, Layout::new(4, 4));
939        assert_eq!(offsets(&named), [0, 8], "the same place either way");
940
941        // The unit an unnamed field has to fit inside is still its own type's, so this one
942        // moves to bit thirty two and the record is eight bytes aligned to one.
943        let wider = [member(char_), unnamed_bits(int, 30)];
944        let wider = lay_out(&types, RecordKind::Struct, &wider);
945        assert_eq!(wider.layout, Layout::new(8, 1));
946        assert_eq!(offsets(&wider), [0, 32]);
947    }
948
949    #[test]
950    fn aapcs64_lets_an_unnamed_bit_field_raise_the_records_alignment() {
951        let types = Types::new();
952        let char_ = types.int(IntKind::Char);
953        let uint = types.int(IntKind::UInt);
954
955        // The same structure as the test above, on the one ABI in the table that disagrees.
956        let fields = [member(char_), unnamed_bits(uint, 20)];
957        let arm = lay_out_on(&aapcs(), &types, RecordKind::Struct, &fields);
958        assert_eq!(arm.layout, Layout::new(4, 4));
959
960        // The zero width member is the case a program actually writes, and it is where the rule
961        // is visible with nothing else in the record at all.
962        let only = [unnamed_bits(uint, 0)];
963        assert_eq!(
964            lay_out_on(&aapcs(), &types, RecordKind::Struct, &only).layout,
965            Layout::new(0, 4)
966        );
967        assert_eq!(lay_out(&types, RecordKind::Struct, &only).layout, Layout::new(0, 1));
968
969        // And it changes a size rather than only an alignment, because the record is rounded up
970        // to the alignment it ends with. Five bytes on x86-64 and eight here.
971        let pushed = [member(char_), unnamed_bits(uint, 0), member(char_)];
972        let pushed = lay_out_on(&aapcs(), &types, RecordKind::Struct, &pushed);
973        assert_eq!(pushed.layout, Layout::new(8, 4));
974        assert_eq!(offsets(&pushed), [0, 32, 32]);
975    }
976
977    #[test]
978    fn windows_allocates_a_bit_field_into_a_unit_of_its_declared_type() {
979        let mut interner = Interner::new();
980        let types = Types::new();
981        let char_ = types.int(IntKind::Char);
982        let uint = types.int(IntKind::UInt);
983        let ushort = types.int(IntKind::UShort);
984        let longlong = types.int(IntKind::LongLong);
985
986        // An ordinary member closes the unit, and the unit costs its whole four bytes, so the
987        // `char` is at offset four rather than at offset one.
988        let then_member = [bits(&mut interner, "m0", uint, 3), member(char_)];
989        let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &then_member);
990        assert_eq!(ms.layout, Layout::new(8, 4));
991        assert_eq!(offsets(&ms), [0, 32]);
992        let itanium = lay_out(&types, RecordKind::Struct, &then_member);
993        assert_eq!(itanium.layout, Layout::new(4, 4));
994        assert_eq!(offsets(&itanium), [0, 8]);
995
996        // A declared type of a different size closes it too, although five bits were free.
997        let narrower = [bits(&mut interner, "m0", uint, 3), bits(&mut interner, "m1", ushort, 5)];
998        let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &narrower);
999        assert_eq!(ms.layout, Layout::new(8, 4));
1000        assert_eq!(offsets(&ms), [0, 32]);
1001        assert_eq!(lay_out(&types, RecordKind::Struct, &narrower).layout, Layout::new(4, 4));
1002
1003        // And the unit is opened at its own alignment, so a `long long` bit-field after a `char`
1004        // starts at offset eight where the Itanium rule leaves it at bit eight.
1005        let wide = [member(char_), bits(&mut interner, "b", longlong, 33)];
1006        let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &wide);
1007        assert_eq!(ms.layout, Layout::new(16, 8));
1008        assert_eq!(offsets(&ms), [0, 64]);
1009        let itanium = lay_out(&types, RecordKind::Struct, &wide);
1010        assert_eq!(itanium.layout, Layout::new(8, 8));
1011        assert_eq!(offsets(&itanium), [0, 8]);
1012    }
1013
1014    #[test]
1015    fn microsofts_zero_width_bit_field_closes_a_unit_and_does_nothing_without_one() {
1016        let mut interner = Interner::new();
1017        let types = Types::new();
1018        let char_ = types.int(IntKind::Char);
1019        let uint = types.int(IntKind::UInt);
1020
1021        // Nothing before it is a bit-field, so there is no run to end and the member is free.
1022        let alone = [member(char_), unnamed_bits(uint, 0)];
1023        assert_eq!(
1024            lay_out_on(&windows(), &types, RecordKind::Struct, &alone).layout,
1025            Layout::new(1, 1)
1026        );
1027        assert_eq!(lay_out(&types, RecordKind::Struct, &alone).layout, Layout::new(4, 1));
1028
1029        // With a unit open it ends it, and the member after starts a unit of its own.
1030        let between = [
1031            bits(&mut interner, "m0", uint, 3),
1032            unnamed_bits(uint, 0),
1033            bits(&mut interner, "m1", uint, 5),
1034            member(char_),
1035        ];
1036        let ms = lay_out_on(&windows(), &types, RecordKind::Struct, &between);
1037        assert_eq!(ms.layout, Layout::new(12, 4));
1038        assert_eq!(offsets(&ms), [0, 32, 32, 64]);
1039        let itanium = lay_out(&types, RecordKind::Struct, &between);
1040        assert_eq!(itanium.layout, Layout::new(8, 4));
1041        assert_eq!(offsets(&itanium), [0, 32, 32, 40]);
1042    }
1043
1044    #[test]
1045    fn msvc_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1046        let mut interner = Interner::new();
1047        let types = Types::new();
1048        let char_ = types.int(IntKind::Char);
1049        let uint = types.int(IntKind::UInt);
1050
1051        // Four bytes because the unit is an `unsigned`, aligned to one because the only member
1052        // that gets a say is the `char`. An alignment smaller than either member would have.
1053        let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1054        assert_eq!(
1055            lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1056            Layout::new(4, 1)
1057        );
1058        assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1059        // MinGW's gcc aligns it to four with the same bit-field rule otherwise, and clang aligns
1060        // it to one. gcc is the incumbent there, so its answer is the one taken.
1061        let mingw = target("x86_64-pc-windows-gnu");
1062        assert_eq!(
1063            lay_out_on(&mingw, &types, RecordKind::Union, &fields).layout,
1064            Layout::new(4, 4)
1065        );
1066    }
1067
1068    #[test]
1069    fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1070        let mut types = Types::new();
1071        let uint = types.int(IntKind::UInt);
1072        let mingw = target("x86_64-pc-windows-gnu");
1073
1074        // Three shapes that hold nothing, and the reference gives all three the same answer.
1075        let none: [FieldDecl; 0] = [];
1076        let zero_width = [unnamed_bits(uint, 0)];
1077        let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1078        for fields in [&none[..], &zero_width[..], &flexible[..]] {
1079            let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1080            assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1081            assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1082            assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1083        }
1084
1085        // It is the environment that decides and not the operating system, so the two Windows
1086        // targets disagree with each other and mingw agrees with Linux. A rule keyed on the
1087        // operating system would have put both of them at four.
1088        assert_eq!(windows().empty_record_size, 4);
1089        assert_eq!(mingw.empty_record_size, 0);
1090    }
1091
1092    #[test]
1093    fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
1094        let mut interner = Interner::new();
1095        let types = Types::new();
1096        let char_ = types.int(IntKind::Char);
1097        let int = types.int(IntKind::Int);
1098        let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1099
1100        let fields = [member(char_), member(int)];
1101        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1102            .expect("a packed struct of two complete members");
1103        assert_eq!(laid_out.layout, Layout::new(5, 1));
1104        assert_eq!(offsets(&laid_out), [0, 8]);
1105
1106        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1107        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1108            .expect("a packed struct with a bit-field");
1109        assert_eq!(laid_out.layout, Layout::new(5, 1));
1110        assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1111
1112        // A zero width bit-field still rounds to its own type, packed or not, which is the
1113        // whole reason a program writes one inside a packed structure.
1114        let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1115        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1116            .expect("a packed struct with a zero width bit-field");
1117        assert_eq!(laid_out.layout, Layout::new(5, 1));
1118        assert_eq!(offsets(&laid_out), [0, 32, 32]);
1119    }
1120
1121    #[test]
1122    fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1123        let mut interner = Interner::new();
1124        let types = Types::new();
1125        let char_ = types.int(IntKind::Char);
1126        let int = types.int(IntKind::Int);
1127        let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1128
1129        let fields = [member(char_), member(int)];
1130        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1131            .expect("a packed struct of two complete members");
1132        assert_eq!(laid_out.layout, Layout::new(6, 2));
1133        assert_eq!(offsets(&laid_out), [0, 16]);
1134
1135        // Six bytes with the field at bit eight, not at bit sixteen. Once the alignment has
1136        // been capped below the type's own there is no boundary to move to, so the field stays
1137        // put. Measured, because moving it is at least as plausible a reading.
1138        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1139        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1140            .expect("a packed struct with a bit-field");
1141        assert_eq!(laid_out.layout, Layout::new(6, 2));
1142        assert_eq!(offsets(&laid_out), [0, 8]);
1143
1144        // The same structure with the field unnamed is five bytes aligned to one, because the
1145        // capped alignment reached it through the record and an unnamed field gives none back.
1146        let fields = [member(char_), unnamed_bits(int, 30)];
1147        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1148            .expect("a packed struct with an unnamed bit-field");
1149        assert_eq!(laid_out.layout, Layout::new(5, 1));
1150    }
1151
1152    #[test]
1153    fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1154        let types = Types::new();
1155        let char_ = types.int(IntKind::Char);
1156        let int = types.int(IntKind::Int);
1157
1158        let aligned = FieldDecl { align: Some(16), ..member(int) };
1159        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1160        assert_eq!(laid_out.layout, Layout::new(32, 16));
1161        assert_eq!(offsets(&laid_out), [0, 128]);
1162
1163        // `packed, aligned(4)` together: the members pack and the record does not, which is
1164        // the combination the attribute pair exists for.
1165        let options = RecordOptions { packed: true, align: Some(4), pack: None };
1166        let fields = [member(char_), member(int)];
1167        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1168            .expect("a packed struct with an alignment asked for");
1169        assert_eq!(laid_out.layout, Layout::new(8, 4));
1170        assert_eq!(offsets(&laid_out), [0, 8]);
1171    }
1172
1173    #[test]
1174    fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1175        // What makes `malloc(sizeof(struct S) + n)` the idiom it is.
1176        let mut types = Types::new();
1177        let char_ = types.int(IntKind::Char);
1178        let int = types.int(IntKind::Int);
1179        let long_long = types.int(IntKind::LongLong);
1180
1181        let chars = types.array(char_, ArrayLen::Unknown);
1182        let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1183        assert_eq!(laid_out.layout, Layout::new(4, 4));
1184        assert_eq!(offsets(&laid_out), [0, 32]);
1185
1186        // The alignment still applies, so this is eight bytes of which one is the `char`.
1187        let longs = types.array(long_long, ArrayLen::Unknown);
1188        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1189        assert_eq!(laid_out.layout, Layout::new(8, 8));
1190        assert_eq!(offsets(&laid_out), [0, 64]);
1191
1192        // Anywhere but last it is an incomplete member, and which member is part of the answer.
1193        let fields = [member(chars), member(int)];
1194        let error =
1195            layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1196        assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1197    }
1198
1199    #[test]
1200    fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1201        // The GNU empty structure, which C itself does not have and which real headers do.
1202        let types = Types::new();
1203        let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1204        assert_eq!(laid_out.layout, Layout::new(0, 1));
1205    }
1206
1207    #[test]
1208    fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1209        let types = Types::new();
1210        let int = types.int(IntKind::Int);
1211        let fields = [unnamed_bits(int, 33)];
1212        let error =
1213            layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1214        let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1215        assert_eq!(error, Err(want));
1216    }
1217
1218    #[test]
1219    fn a_record_reports_its_members_once_it_has_been_completed() {
1220        let mut interner = Interner::new();
1221        let mut types = Types::new();
1222        let char_ = types.int(IntKind::Char);
1223        let int = types.int(IntKind::Int);
1224        let name = interner.intern("count");
1225        let fields = [member(char_), FieldDecl::new(Some(name), int)];
1226        let id = types.declare_record(RecordKind::Struct, None);
1227        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1228        types.complete_record(id, laid_out);
1229        let ty = types.record(id);
1230        assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1231        let field = types.field(id, name).expect("the member that was declared");
1232        assert_eq!(field.offset, 4);
1233        assert!(!field.is_bit_field());
1234        assert_eq!(types.field(id, interner.intern("missing")), None);
1235    }
1236
1237    #[test]
1238    fn a_nested_record_brings_its_own_alignment_with_it() {
1239        let mut types = Types::new();
1240        let char_ = types.int(IntKind::Char);
1241        let int = types.int(IntKind::Int);
1242        let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1243        let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1244        assert_eq!(laid_out.layout, Layout::new(8, 4));
1245        assert_eq!(offsets(&laid_out), [0, 32]);
1246
1247        // An anonymous member is an ordinary member with no name, so the same code lays it out
1248        // and the four bytes of padding after the `char` are there either way.
1249        let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1250        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1251        assert_eq!(laid_out.layout, Layout::new(12, 4));
1252        assert_eq!(offsets(&laid_out), [0, 32]);
1253    }
1254
1255    #[test]
1256    fn everything_narrower_than_an_int_promotes_to_one() {
1257        // Measured by naming the type of `+x` with `_Generic` in gcc 13.3 and clang 18. Every
1258        // one of these answers `int`, including the unsigned ones, because an `int` holds every
1259        // value a sixteen bit unsigned type has.
1260        let mut types = Types::new();
1261        let linux = linux();
1262        let int = types.int(IntKind::Int);
1263        let narrow =
1264            [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1265        for kind in narrow {
1266            let ty = types.int(kind);
1267            assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1268        }
1269        let boolean = types.boolean();
1270        assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1271
1272        // From `int` up, a type is its own promotion.
1273        for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1274            let ty = types.int(kind);
1275            assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1276        }
1277    }
1278
1279    #[test]
1280    fn a_bit_int_is_not_promoted_at_all() {
1281        // C23 6.3.1.1p2, and the point of the type. `_BitInt(8) + _BitInt(8)` stays eight bits
1282        // wide where `char + char` is an `int`, which is what makes the width mean something.
1283        let mut types = Types::new();
1284        let linux = linux();
1285        let small = types.bit_int(true, 8);
1286        assert_eq!(promote(&mut types, small, &linux), small);
1287        assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1288    }
1289
1290    #[test]
1291    fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1292        let mut types = Types::new();
1293        let linux = linux();
1294        let int = types.int(IntKind::Int);
1295        let uint = types.int(IntKind::UInt);
1296        let ullong = types.int(IntKind::ULongLong);
1297
1298        // Three bits of an unsigned field all fit in an `int`, so it is signed afterwards.
1299        assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1300        // Thirty two of them do not.
1301        assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1302        // Twenty bits of a signed field, which is an `int` either way.
1303        assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1304        // Forty bits are forty bits of value and nothing more. The C17 wording says `unsigned
1305        // int` here, which would silently drop eight of them, and C23 says the declared type,
1306        // which would silently add twenty four. Both compilers give the width instead, so
1307        // `x.b << 32` on such a field is zero rather than a value with a bit above the fortieth.
1308        let forty = types.bit_int(false, 40);
1309        assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1310        // A field as wide as its type is that type, since there is no precision to lose.
1311        assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1312    }
1313
1314    #[test]
1315    fn an_enumeration_promotes_through_what_it_is_represented_in() {
1316        let mut types = Types::new();
1317        let linux = linux();
1318        let int = types.int(IntKind::Int);
1319        let short = types.int(IntKind::Short);
1320        let uint = types.int(IntKind::UInt);
1321
1322        // `enum E : short` promotes the same way a `short` does, which is to `int`.
1323        let fixed = types.declare_enum(None);
1324        types.complete_enum(fixed, short, true);
1325        let fixed = types.enumeration(fixed);
1326        assert_eq!(promote(&mut types, fixed, &linux), int);
1327
1328        // An enumeration all of whose enumerators are non-negative is represented in
1329        // `unsigned int` by both compilers, and then it promotes to itself.
1330        let unsigned = types.declare_enum(None);
1331        types.complete_enum(unsigned, uint, false);
1332        let unsigned = types.enumeration(unsigned);
1333        assert_eq!(promote(&mut types, unsigned, &linux), uint);
1334
1335        // An enumeration nobody has decided on yet answers `int`, so that an expression using
1336        // one is still checkable while the diagnostic about it is being written.
1337        let undecided = types.declare_enum(None);
1338        let undecided = types.enumeration(undecided);
1339        assert_eq!(promote(&mut types, undecided, &linux), int);
1340    }
1341
1342    #[test]
1343    fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1344        // By the time a value is being promoted the lvalue conversion has already happened, so
1345        // `_Atomic const int` and `int` are the same operand.
1346        let mut types = Types::new();
1347        let linux = linux();
1348        let int = types.int(IntKind::Int);
1349        let konst = types.qualified(int, Qualifiers::CONST);
1350        let atomic = types.atomic(konst);
1351        assert_eq!(promote(&mut types, atomic, &linux), int);
1352        assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1353    }
1354
1355    #[test]
1356    fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1357        // Every row measured with `_Generic` in gcc 13.3 and clang 18 on x86-64 Linux.
1358        let mut types = Types::new();
1359        let linux = linux();
1360        let cases = [
1361            (IntKind::Int, IntKind::UInt, IntKind::UInt),
1362            (IntKind::Int, IntKind::Long, IntKind::Long),
1363            (IntKind::UInt, IntKind::Long, IntKind::Long),
1364            (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1365            (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1366            (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1367            (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1368            (IntKind::Char, IntKind::Char, IntKind::Int),
1369            (IntKind::UChar, IntKind::UShort, IntKind::Int),
1370        ];
1371        for (left, right, want) in cases {
1372            let left = types.int(left);
1373            let right = types.int(right);
1374            let want = types.int(want);
1375            assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1376            assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1377        }
1378    }
1379
1380    #[test]
1381    fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1382        // Measured on gcc 13.3 on x86-64 Linux and clang on AArch64 Darwin, both of which
1383        // report the same size, the same alignment, and an offset of sixteen for a member
1384        // after a `char`.
1385        let mut types = Types::new();
1386        let linux = linux();
1387        let signed = types.int(IntKind::Int128);
1388        let unsigned = types.int(IntKind::UInt128);
1389        for id in [signed, unsigned] {
1390            let laid_out = layout(&types, id, &linux).expect("a complete type");
1391            assert_eq!(laid_out.size, 16);
1392            assert_eq!(laid_out.align, 16);
1393        }
1394
1395        // `__int128 + unsigned long long` is `__int128`, because it wins on rank and is wide
1396        // enough to hold every value the other side had. Both compilers agree, and it is the
1397        // one pair that says the rank is above `long long` rather than beside it.
1398        let ull = types.int(IntKind::ULongLong);
1399        assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1400        // And it is its own promotion, the way every type at or above `int` is.
1401        assert_eq!(promote(&mut types, signed, &linux), signed);
1402    }
1403
1404    #[test]
1405    fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1406        // Same width, different types. The alignment is the visible difference on x86-64,
1407        // where a `_BitInt` is aligned to its sixty four bit granule and `__int128` is not.
1408        let mut types = Types::new();
1409        let linux = linux();
1410        let int128 = types.int(IntKind::Int128);
1411        let bit_int = types.bit_int(true, 128);
1412        assert_ne!(int128, bit_int);
1413        assert!(!compatible(&types, int128, bit_int));
1414        assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1415        assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1416    }
1417
1418    #[test]
1419    fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1420        // `unsigned long + long long` is `unsigned long long` on Linux: the `long long` wins on
1421        // rank and cannot hold every value of the `unsigned long`, so neither operand's own
1422        // type is the answer. This is the arm programs are surprised by.
1423        let mut types = Types::new();
1424        let linux = linux();
1425        let ulong = types.int(IntKind::ULong);
1426        let long_long = types.int(IntKind::LongLong);
1427        let want = types.int(IntKind::ULongLong);
1428        assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1429
1430        // The same pair on Windows, where `long` is thirty two bits, comes out as `long long`,
1431        // because there it does hold every value. A host-driven implementation gets one of
1432        // these two wrong.
1433        let windows = target("x86_64-pc-windows-msvc");
1434        assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1435    }
1436
1437    #[test]
1438    fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1439        // Measured with clang 18 on x86-64 Linux, which is the compiler that has `_BitInt`.
1440        let mut types = Types::new();
1441        let linux = linux();
1442        let b40 = types.bit_int(true, 40);
1443        let ub40 = types.bit_int(false, 40);
1444        let b8 = types.bit_int(true, 8);
1445        let b32 = types.bit_int(true, 32);
1446        let int = types.int(IntKind::Int);
1447        let uint = types.int(IntKind::UInt);
1448        let long = types.int(IntKind::Long);
1449        let char_ = types.int(IntKind::Char);
1450
1451        // Wider than an `int`, so it outranks one.
1452        assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1453        // Narrower than a `long`, so it loses to one.
1454        assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1455        // The same width as an `int`, and a standard type wins the tie.
1456        assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1457        assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1458        // The other side promotes first, so a `char` next to a narrow `_BitInt` is an `int`
1459        // and the `_BitInt` loses to it.
1460        assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1461        // Unsigned and higher ranked wins outright, and unsigned and lower ranked loses to a
1462        // signed type wide enough to hold it.
1463        assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1464        assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1465        // Two bit-precise types of the same width and different signedness.
1466        assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1467    }
1468
1469    #[test]
1470    fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1471        let mut types = Types::new();
1472        let linux = linux();
1473        let float = types.float(FloatKind::Float);
1474        let double = types.float(FloatKind::Double);
1475        let long_double = types.float(FloatKind::LongDouble);
1476        let ullong = types.int(IntKind::ULongLong);
1477        let int = types.int(IntKind::Int);
1478
1479        assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1480        assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1481        assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1482        // Sixty four bits of unsigned integer against a `float`, which is a `float` and loses
1483        // most of them. That is the rule rather than an oversight.
1484        assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1485    }
1486
1487    #[test]
1488    fn a_mask_is_the_signed_integers_of_the_lane_width() {
1489        let mut types = Types::new();
1490        let linux = linux();
1491        let int = types.int(IntKind::Int);
1492        let float = types.float(FloatKind::Float);
1493        let short = types.int(IntKind::Short);
1494
1495        // A signed lane is already its own mask, so the answer is the vector it was given.
1496        let four_ints = types.vector(int, 4);
1497        assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1498
1499        // An unsigned lane answers as the signed type of the same width, which is what GCC
1500        // gives a comparison of two `unsigned int` vectors.
1501        let uint = types.int(IntKind::UInt);
1502        let four_uints = types.vector(uint, 4);
1503        assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1504
1505        // A float lane answers as an integer of the same width, since the mask is bits and not
1506        // a number and there is no float that is all ones.
1507        let four_floats = types.vector(float, 4);
1508        assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1509
1510        // The width is the lane's own and not a word, so a `short` lane keeps its two bytes.
1511        let two_shorts = types.vector(short, 2);
1512        assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1513
1514        // Not a vector, so there is no mask to give.
1515        assert_eq!(mask_of(&mut types, int, &linux), None);
1516    }
1517
1518    #[test]
1519    fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1520        let mut types = Types::new();
1521        let linux = linux();
1522        let int = types.int(IntKind::Int);
1523        let uint = types.int(IntKind::UInt);
1524        let float = types.float(FloatKind::Float);
1525        let short = types.int(IntKind::Short);
1526
1527        let four_ints = types.vector(int, 4);
1528        let four_uints = types.vector(uint, 4);
1529        let four_floats = types.vector(float, 4);
1530        let eight_shorts = types.vector(short, 8);
1531        let two_ints = types.vector(int, 2);
1532
1533        // The case the whole thing exists for: a mask assigned to the unsigned vector it came
1534        // from, which GNU C converts and the standard rules would refuse.
1535        assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1536        // Both ways round, since assignment happens in both directions.
1537        assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1538        // The same sixteen bytes cut into eight lanes rather than four, which GCC also allows.
1539        assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1540        // Two floats of the same width, which is the other half of the rule.
1541        assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1542
1543        // An integer lane against a float lane, which GCC refuses even at the same size,
1544        // because reading one as the other is a cast and not a conversion.
1545        assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1546        // Different sizes, so there is nothing to reinterpret.
1547        assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1548        // A scalar is not a vector, whichever side it is on.
1549        assert!(!vectors_convertible(&types, four_ints, int, &linux));
1550        assert!(!vectors_convertible(&types, int, four_ints, &linux));
1551    }
1552
1553    /// Insists that `a + b` and `b + a` are both `expected` on this target.
1554    ///
1555    /// Both ways round, because the operands of `+` are not ordered and an implementation that
1556    /// keeps the left one when it cannot decide would pass half of these and be wrong.
1557    fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1558        let mut types = Types::new();
1559        let left = types.float(a);
1560        let right = types.float(b);
1561        let want = types.float(expected);
1562        assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1563        assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1564    }
1565
1566    #[test]
1567    fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1568        // Every line here was read off gcc 16 with `_Generic` rather than off the standard, on
1569        // x86-64 Linux, where `long double` and `_Float64x` are both the x87 format and the
1570        // standard type is the one that comes out.
1571        let x86 = linux();
1572        combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1573        combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1574        combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1575        combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1576        combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1577        combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1578        combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1579        combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1580        combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1581        combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1582    }
1583
1584    #[test]
1585    fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1586        // The same reading against gcc 16 on aarch64-apple-darwin, where `long double` is a
1587        // `double` and loses to the `_Float64x` it beats on x86-64. The name says nothing about
1588        // which of the two is wider, which is why the ordering is worked out from the formats.
1589        let mac = target("aarch64-apple-darwin");
1590        combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1591        combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1592        combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1593        combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1594        combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1595        combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1596        combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1597        // `_Float16` is the narrowest type there is and does not promote on the way in, so it
1598        // survives an operation only when nothing wider is there.
1599        combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1600        combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1601        combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1602    }
1603
1604    #[test]
1605    fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1606        let mut types = Types::new();
1607        let linux = linux();
1608        let cfloat = types.complex_float(FloatKind::Float);
1609        let cdouble = types.complex_float(FloatKind::Double);
1610        let cldouble = types.complex_float(FloatKind::LongDouble);
1611        let double = types.float(FloatKind::Double);
1612        let long_double = types.float(FloatKind::LongDouble);
1613        let float = types.float(FloatKind::Float);
1614        let int = types.int(IntKind::Int);
1615
1616        assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1617        assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1618        assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1619        assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1620    }
1621
1622    #[test]
1623    fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1624        // The caller is the one holding the span, so this says no rather than guessing.
1625        let mut types = Types::new();
1626        let linux = linux();
1627        let int = types.int(IntKind::Int);
1628        let pointer = types.pointer(int);
1629        assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1630        assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1631        let void = types.void();
1632        assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1633        // And a type that is not arithmetic is still its own promotion, so a caller may promote
1634        // first and ask questions afterwards.
1635        assert_eq!(promote(&mut types, pointer, &linux), pointer);
1636    }
1637
1638    #[test]
1639    fn the_conversions_read_through_sugar() {
1640        let mut interner = Interner::new();
1641        let mut types = Types::new();
1642        let linux = linux();
1643        let char_ = types.int(IntKind::Char);
1644        let name = types.typedef(interner.intern("byte"), char_);
1645        let int = types.int(IntKind::Int);
1646        assert_eq!(promote(&mut types, name, &linux), int);
1647    }
1648
1649    /// A prototype returning `void`.
1650    fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1651        let ret = types.void();
1652        types.function(FunctionType { ret, params, variadic, prototyped: true })
1653    }
1654
1655    /// `void f()` as it means before C23: a declaration that says nothing about the parameters.
1656    fn old_style(types: &mut Types) -> TypeId {
1657        let ret = types.void();
1658        types.function(FunctionType { ret, params: Vec::new(), variadic: false, prototyped: false })
1659    }
1660
1661    /// A complete record with the given tag and members.
1662    fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1663        let id = types.declare_record(RecordKind::Struct, Some(tag));
1664        let laid_out = lay_out(types, RecordKind::Struct, fields);
1665        types.complete_record(id, laid_out);
1666        id
1667    }
1668
1669    #[test]
1670    fn a_type_is_compatible_with_itself_however_it_was_written() {
1671        let mut interner = Interner::new();
1672        let mut types = Types::new();
1673        let int = types.int(IntKind::Int);
1674        let name = types.typedef(interner.intern("int32_t"), int);
1675        assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1676        assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1677
1678        // The qualifiers have to match exactly, which is what keeps `const int *` and `int *`
1679        // apart as parameter types.
1680        let konst = types.qualified(int, Qualifiers::CONST);
1681        assert!(!compatible(&types, konst, int));
1682        let konst_pointer = types.pointer(konst);
1683        let pointer = types.pointer(int);
1684        assert!(!compatible(&types, konst_pointer, pointer));
1685        assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1686
1687        // And a different type is a different type. `char` is not `signed char` even on a target
1688        // where the two have the same range, which is why they are separate kinds here.
1689        let char_ = types.int(IntKind::Char);
1690        let schar = types.int(IntKind::SChar);
1691        assert!(!compatible(&types, char_, schar));
1692        // `_Atomic int` is not `int` either, since it is a type and not a qualifier.
1693        let atomic = types.atomic(int);
1694        assert!(!compatible(&types, atomic, int));
1695    }
1696
1697    #[test]
1698    fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1699        // gcc 13.3 and clang 18 both represent `enum E { A, B }` in `unsigned int`, and both
1700        // accept a redeclaration that writes the representation instead of the tag.
1701        let mut types = Types::new();
1702        let uint = types.int(IntKind::UInt);
1703        let int = types.int(IntKind::Int);
1704        let id = types.declare_enum(None);
1705        types.complete_enum(id, uint, false);
1706        let e = types.enumeration(id);
1707        assert!(compatible(&types, e, uint));
1708        assert!(compatible(&types, uint, e), "and the relation is symmetric");
1709        assert!(!compatible(&types, e, int));
1710
1711        // Two enumeration declarations are two types. Each is compatible with what it is
1712        // represented in, and that does not make them compatible with each other.
1713        let other = types.declare_enum(None);
1714        types.complete_enum(other, uint, false);
1715        let other = types.enumeration(other);
1716        assert!(!compatible(&types, e, other));
1717
1718        // One nobody has decided on yet is compatible with nothing but itself, because the
1719        // answer is not known rather than no.
1720        let undecided = types.declare_enum(None);
1721        let undecided = types.enumeration(undecided);
1722        assert!(!compatible(&types, undecided, uint));
1723        assert!(compatible(&types, undecided, undecided));
1724    }
1725
1726    #[test]
1727    fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1728        // `extern int a[]; int a[4];` is a complete array of four afterwards, which gcc reports
1729        // as a `sizeof` of sixteen. A compiler that keeps the first type has lost the size.
1730        let mut types = Types::new();
1731        let int = types.int(IntKind::Int);
1732        let unknown = types.array(int, ArrayLen::Unknown);
1733        let four = types.array(int, ArrayLen::Fixed(4));
1734        let five = types.array(int, ArrayLen::Fixed(5));
1735        assert!(compatible(&types, unknown, four));
1736        assert!(!compatible(&types, four, five));
1737        assert_eq!(composite(&mut types, unknown, four), Some(four));
1738        assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1739        assert_eq!(composite(&mut types, four, five), None);
1740
1741        // A variable length array is compatible with both, because its size is not something a
1742        // declaration can be checked against.
1743        let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1744        assert!(compatible(&types, vla, four));
1745        assert_eq!(composite(&mut types, vla, four), Some(four));
1746
1747        // The element types have to be compatible too, and the composite reaches into them.
1748        let long = types.int(IntKind::Long);
1749        let longs = types.array(long, ArrayLen::Fixed(4));
1750        assert!(!compatible(&types, four, longs));
1751    }
1752
1753    #[test]
1754    fn a_parameter_declared_as_an_array_is_a_pointer() {
1755        // `int fn(int p[3])` and `int fn(int *p)` are one declaration and one definition, which
1756        // both compilers accept. The adjustment is part of forming the parameter type, so two
1757        // functions written either way are not merely compatible but identical.
1758        let mut types = Types::new();
1759        let int = types.int(IntKind::Int);
1760        let three = types.array(int, ArrayLen::Fixed(3));
1761        let pointer = types.pointer(int);
1762        assert_eq!(adjust_parameter(&mut types, three), pointer);
1763
1764        // A function parameter becomes a pointer to the function the same way.
1765        let function = prototype(&mut types, vec![int], false);
1766        let function_pointer = types.pointer(function);
1767        assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1768
1769        // And the qualifiers on the outermost node go, so `void f(const int)` and `void f(int)`
1770        // declare the same function. The pointee of a `const int *` keeps its own.
1771        let konst = types.qualified(int, Qualifiers::CONST);
1772        assert_eq!(adjust_parameter(&mut types, konst), int);
1773        let to_konst = types.pointer(konst);
1774        assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1775    }
1776
1777    #[test]
1778    fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1779        // Measured with gcc 13.3 in C17 mode, which is the compiler that still has the old
1780        // meaning of `()`. It names the rule in its own diagnostic: an argument type that has a
1781        // default promotion cannot match an empty parameter name list declaration.
1782        let mut types = Types::new();
1783        let old = old_style(&mut types);
1784        let int = types.int(IntKind::Int);
1785        let long = types.int(IntKind::Long);
1786        let char_ = types.int(IntKind::Char);
1787        let float = types.float(FloatKind::Float);
1788        let double = types.float(FloatKind::Double);
1789
1790        let takes_int = prototype(&mut types, vec![int], false);
1791        assert!(compatible(&types, old, takes_int));
1792        assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
1793        // The composite is the prototype, so the calls written before it can still be checked.
1794        assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
1795
1796        let pointer = types.pointer(int);
1797        for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
1798            let ty = prototype(&mut types, params, false);
1799            assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
1800        }
1801
1802        // A `char` promotes to `int` and a `float` to `double`, so a call through the old style
1803        // declaration would have passed something else and the two conflict.
1804        for params in [vec![char_], vec![float], vec![int, char_]] {
1805            let ty = prototype(&mut types, params, false);
1806            assert!(!compatible(&types, old, ty));
1807            assert_eq!(composite(&mut types, old, ty), None);
1808        }
1809
1810        // An ellipsis conflicts too, which gcc also says in as many words.
1811        let variadic = prototype(&mut types, vec![int], true);
1812        assert!(!compatible(&types, old, variadic));
1813
1814        // An enumeration parameter comes through when what it is represented in does.
1815        let uint = types.int(IntKind::UInt);
1816        let id = types.declare_enum(None);
1817        types.complete_enum(id, uint, false);
1818        let e = types.enumeration(id);
1819        let takes_enum = prototype(&mut types, vec![e], false);
1820        assert!(compatible(&types, old, takes_enum));
1821
1822        // Two old style declarations agree about nothing and so cannot disagree.
1823        assert!(compatible(&types, old, old));
1824
1825        // The return type still has to match, which is the one part `()` does say.
1826        let returns_int = types.function(FunctionType {
1827            ret: int,
1828            params: Vec::new(),
1829            variadic: false,
1830            prototyped: false,
1831        });
1832        assert!(!compatible(&types, returns_int, takes_int));
1833    }
1834
1835    #[test]
1836    fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
1837        // The dialect decides what `()` means and the parser records the decision, so the same
1838        // pair of declarations is a redeclaration in C17 and a conflict in C23. Both compilers
1839        // report exactly that.
1840        let mut types = Types::new();
1841        let int = types.int(IntKind::Int);
1842        let takes_int = prototype(&mut types, vec![int], false);
1843        let takes_nothing = prototype(&mut types, Vec::new(), false);
1844        let old = old_style(&mut types);
1845        assert!(!compatible(&types, takes_nothing, takes_int));
1846        assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
1847    }
1848
1849    #[test]
1850    fn two_prototypes_have_to_agree_about_everything() {
1851        let mut types = Types::new();
1852        let int = types.int(IntKind::Int);
1853        let long = types.int(IntKind::Long);
1854        let base = prototype(&mut types, vec![int, int], false);
1855        for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
1856            let other = prototype(&mut types, other, false);
1857            assert!(!compatible(&types, base, other));
1858        }
1859        let variadic = prototype(&mut types, vec![int, int], true);
1860        assert!(!compatible(&types, base, variadic), "`...` is part of the type");
1861
1862        // The parameters are compared with the same rules as anything else, so an array size
1863        // inside a parameter's type is compared and an unknown one is not.
1864        let four = types.array(int, ArrayLen::Fixed(4));
1865        let unknown = types.array(int, ArrayLen::Unknown);
1866        let to_four = types.pointer(four);
1867        let to_unknown = types.pointer(unknown);
1868        let a = prototype(&mut types, vec![to_four], false);
1869        let b = prototype(&mut types, vec![to_unknown], false);
1870        assert!(compatible(&types, a, b));
1871        // And the composite takes the size, which is the whole reason it exists.
1872        assert_eq!(composite(&mut types, a, b), Some(a));
1873    }
1874
1875    #[test]
1876    fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
1877        let mut types = Types::new();
1878        let int = types.int(IntKind::Int);
1879        let four = types.array(int, ArrayLen::Fixed(4));
1880        let unknown = types.array(int, ArrayLen::Unknown);
1881        let to_four = types.pointer(four);
1882        let to_unknown = types.pointer(unknown);
1883        assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
1884
1885        // The pointer's own qualifiers survive, since a compatible pair has the same ones.
1886        let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
1887        let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
1888        assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
1889    }
1890
1891    #[test]
1892    fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
1893        // C23 6.2.7p1, which is what lets one header be included twice. clang 18 implements it
1894        // and gcc 13.3 still rejects the redefinition, so this is a divergence rather than a
1895        // reading; in the older dialects the redefinition never gets as far as being compared.
1896        let mut interner = Interner::new();
1897        let mut types = Types::new();
1898        let tag = interner.intern("point");
1899        let x = interner.intern("x");
1900        let y = interner.intern("y");
1901        let int = types.int(IntKind::Int);
1902        let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
1903
1904        let first = tagged(&mut types, tag, &members);
1905        let second = tagged(&mut types, tag, &members);
1906        let first = types.record(first);
1907        let second = types.record(second);
1908        assert_ne!(first, second, "still two declarations and two types");
1909        assert!(compatible(&types, first, second));
1910
1911        // A different member name, a different member type, a different count, a different tag
1912        // and a different keyword are each enough to make them different types.
1913        let z = interner.intern("z");
1914        let long = types.int(IntKind::Long);
1915        let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
1916        let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
1917        for other in [&renamed[..], &retyped[..], &members[..1]] {
1918            let other = tagged(&mut types, tag, other);
1919            let other = types.record(other);
1920            assert!(!compatible(&types, first, other));
1921        }
1922        let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
1923        let elsewhere = types.record(elsewhere);
1924        assert!(!compatible(&types, first, elsewhere));
1925
1926        // An anonymous record is compatible with nothing but itself: there is no name by which
1927        // a second declaration could be claiming to be the same type.
1928        let anonymous = record(&mut types, RecordKind::Struct, &members);
1929        let also_anonymous = record(&mut types, RecordKind::Struct, &members);
1930        assert!(!compatible(&types, anonymous, also_anonymous));
1931
1932        // Nor is an incomplete declaration, which has no members to compare.
1933        let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
1934        let incomplete = types.record(incomplete);
1935        assert!(!compatible(&types, first, incomplete));
1936        assert!(compatible(&types, incomplete, incomplete));
1937    }
1938
1939    #[test]
1940    fn a_self_referential_record_is_compared_without_going_round_forever() {
1941        // `struct node { int value; struct node *next; }` declared twice. Comparing the two
1942        // reaches the same pair again through the pointer, and the second time it is an
1943        // assumption rather than a question.
1944        let mut interner = Interner::new();
1945        let mut types = Types::new();
1946        let tag = interner.intern("node");
1947        let value = interner.intern("value");
1948        let next = interner.intern("next");
1949        let int = types.int(IntKind::Int);
1950
1951        let node = |types: &mut Types| {
1952            let id = types.declare_record(RecordKind::Struct, Some(tag));
1953            let ty = types.record(id);
1954            let pointer = types.pointer(ty);
1955            let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
1956            let laid_out = lay_out(types, RecordKind::Struct, &members);
1957            types.complete_record(id, laid_out);
1958            ty
1959        };
1960        let first = node(&mut types);
1961        let second = node(&mut types);
1962        assert_ne!(first, second);
1963        assert!(compatible(&types, first, second));
1964
1965        // The guard is an assumption and not an answer, so a difference below the cycle is still
1966        // found: the same structure with the two members the other way round is a different one.
1967        let id = types.declare_record(RecordKind::Struct, Some(tag));
1968        let ty = types.record(id);
1969        let pointer = types.pointer(ty);
1970        let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
1971        let laid_out = lay_out(&types, RecordKind::Struct, &members);
1972        types.complete_record(id, laid_out);
1973        assert!(!compatible(&types, first, ty));
1974    }
1975
1976    #[test]
1977    fn layout_reads_through_sugar() {
1978        let mut interner = Interner::new();
1979        let mut types = Types::new();
1980        let long = types.int(IntKind::Long);
1981        let name = types.typedef(interner.intern("word"), long);
1982        let array = types.array(name, ArrayLen::Fixed(4));
1983        assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
1984    }
1985
1986    /// A recipe worked out, with `sizes` standing for how large each member turned out to be.
1987    ///
1988    /// The lowering does this with instructions and this does it with numbers, which is what
1989    /// makes a recipe testable here: the tree is the whole answer, and what a member is as long
1990    /// as is the only thing either side has to be told.
1991    fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
1992        match recipe {
1993            Extent::Bytes(count) => *count,
1994            Extent::Member(index) => sizes[*index as usize],
1995            Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
1996            Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
1997            Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
1998        }
1999    }
2000
2001    /// An array of `int` whose length the program computes.
2002    fn measured(types: &mut Types, which: u32) -> TypeId {
2003        let int = types.int(IntKind::Int);
2004        types.array(int, ArrayLen::Variable(VlaId(which)))
2005    }
2006
2007    #[test]
2008    fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2009        let mut types = Types::new();
2010        let int = types.int(IntKind::Int);
2011        let rows = measured(&mut types, 0);
2012        let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2013
2014        // Nothing is known here but the alignment, which never varies: it is decided by the
2015        // members rather than by where they land.
2016        assert_eq!(laid_out.layout, Layout::new(0, 4));
2017        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2018        // The member in front of the variable one sits where its number says, and the one after
2019        // it does not. There is no rounding in between, because an array of `int` ends on a four
2020        // byte boundary however long it is.
2021        assert_eq!(variable.offsets[0], None);
2022        let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2023        for count in 0..6u64 {
2024            let sizes = [4 * count, 4];
2025            assert_eq!(work_out(after, &sizes), 4 * count);
2026            assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2027        }
2028        assert_eq!(laid_out.fields[1].align, 4);
2029    }
2030
2031    #[test]
2032    fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2033        let mut types = Types::new();
2034        let char_ty = types.int(IntKind::Char);
2035        let rows = measured(&mut types, 0);
2036        let double = types.float(FloatKind::Double);
2037        let fields = [member(char_ty), member(rows), member(double)];
2038        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2039
2040        assert_eq!(laid_out.layout, Layout::new(0, 8));
2041        assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2042        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2043        assert_eq!(variable.offsets[..2], [None, None]);
2044        let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2045        for count in 0..6u64 {
2046            let sizes = [1, 4 * count, 8];
2047            let at = (4 + 4 * count).next_multiple_of(8);
2048            assert_eq!(work_out(after, &sizes), at);
2049            assert_eq!(work_out(&variable.size, &sizes), at + 8);
2050        }
2051    }
2052
2053    #[test]
2054    fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2055        let mut types = Types::new();
2056        let rows = measured(&mut types, 0);
2057        let double = types.float(FloatKind::Double);
2058        let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2059
2060        assert_eq!(laid_out.layout, Layout::new(0, 8));
2061        let variable = laid_out.variable.expect("a union with a member of no fixed size");
2062        // Every member of a union starts where the union does, so none of them has an offset the
2063        // program has to work out.
2064        assert!(variable.offsets.iter().all(Option::is_none));
2065        for count in 0..6u64 {
2066            let sizes = [4 * count, 8];
2067            let want = (4 * count).max(8).next_multiple_of(8);
2068            assert_eq!(work_out(&variable.size, &sizes), want);
2069        }
2070    }
2071
2072    #[test]
2073    fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2074        let mut types = Types::new();
2075        let char_ty = types.int(IntKind::Char);
2076        let int = types.int(IntKind::Int);
2077        let rows = measured(&mut types, 0);
2078        let fields = [member(char_ty), member(rows), member(int)];
2079        let options = RecordOptions { packed: true, ..RecordOptions::default() };
2080        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2081            .expect("a packed record with a member of no fixed size");
2082
2083        assert_eq!(laid_out.layout, Layout::new(0, 1));
2084        assert_eq!(laid_out.fields[2].align, 1);
2085        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2086        let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2087        for count in 0..6u64 {
2088            let sizes = [1, 4 * count, 4];
2089            assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2090            assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2091        }
2092    }
2093
2094    #[test]
2095    fn bit_fields_after_a_member_of_no_fixed_size_are_placed_one_after_another() {
2096        let mut interner = Interner::new();
2097        let mut types = Types::new();
2098        let int = types.int(IntKind::Int);
2099        let char_ty = types.int(IntKind::Char);
2100        let rows = measured(&mut types, 0);
2101        let fields = [
2102            member(rows),
2103            bits(&mut interner, "b", int, 3),
2104            bits(&mut interner, "c", int, 30),
2105            member(char_ty),
2106        ];
2107        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2108
2109        // `c` would straddle its `int` if the offset were a number, and gcc 16 puts it at bit
2110        // three all the same, because it only asks that question of an offset it knows. So the
2111        // `char` is five bytes past the array and the record is `4 * n + 8` long.
2112        assert_eq!((laid_out.fields[2].offset, laid_out.fields[2].bit), (0, 3));
2113        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2114        let after = variable.offsets[3].as_ref().expect("an offset the program works out");
2115        for count in 0..6u64 {
2116            let sizes = [4 * count, 4, 4, 1];
2117            assert_eq!(work_out(after, &sizes), 4 * count + 5);
2118            assert_eq!(work_out(&variable.size, &sizes), 4 * count + 8);
2119        }
2120    }
2121
2122    #[test]
2123    fn a_zero_width_bit_field_that_needs_more_alignment_than_is_known_is_turned_down() {
2124        let mut types = Types::new();
2125        let int = types.int(IntKind::Int);
2126        let char_ty = types.int(IntKind::Char);
2127        let letters = types.array(char_ty, ArrayLen::Variable(VlaId(0)));
2128        let fields = [member(letters), unnamed_bits(int, 0)];
2129        let options = RecordOptions::default();
2130        let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2131
2132        // A `char` array may end on any byte, so which four byte boundary `int : 0` rounds to is a
2133        // question about an address the program has not worked out yet. The layout says so
2134        // rather than putting the member somewhere plausible.
2135        assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2136    }
2137}