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