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.19.0")]
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        // Except that the Itanium rule on AArch64 is AAPCS64's, which says yes, so on Windows on
1174        // AArch64 gcc_struct gives four aligned to four, as llvm-mingw's clang does.
1175        let arm_mingw = target("aarch64-pc-windows-gnu");
1176        assert_eq!(on(&arm_mingw, &gcc, &unnamed).layout, Layout::new(4, 4));
1177        assert_eq!(on(&arm_mingw, &RecordOptions::default(), &unnamed).layout, Layout::new(8, 4));
1178
1179        // And so does what a zero width one does, with a bit-field before it and without one.
1180        let narrow = [
1181            bits(&mut interner, "a", char_, 1),
1182            unnamed_bits(int_, 0),
1183            bits(&mut interner, "b", char_, 1),
1184        ];
1185        let laid_out = on(&mingw, &gcc, &narrow);
1186        assert_eq!(laid_out.layout, Layout::new(5, 1));
1187        assert_eq!(offsets(&laid_out), [0, 32, 32]);
1188        assert_eq!(on(&linux(), &ms, &narrow).layout, Layout::new(8, 4));
1189        let alone = [member(char_), unnamed_bits(uint, 0)];
1190        assert_eq!(on(&mingw, &gcc, &alone).layout, Layout::new(4, 1));
1191        assert_eq!(on(&linux(), &ms, &alone).layout, Layout::new(1, 1));
1192    }
1193
1194    #[test]
1195    fn msvc_gives_a_unions_bit_field_storage_and_no_say_in_the_alignment() {
1196        let mut interner = Interner::new();
1197        let types = Types::new();
1198        let char_ = types.int(IntKind::Char);
1199        let uint = types.int(IntKind::UInt);
1200
1201        // Four bytes because the unit is an `unsigned`, aligned to one because the only member
1202        // that gets a say is the `char`. An alignment smaller than either member would have.
1203        let fields = [bits(&mut interner, "m0", uint, 3), member(char_)];
1204        assert_eq!(
1205            lay_out_on(&windows(), &types, RecordKind::Union, &fields).layout,
1206            Layout::new(4, 1)
1207        );
1208        assert_eq!(lay_out(&types, RecordKind::Union, &fields).layout, Layout::new(4, 4));
1209        // MinGW's gcc aligns it to four with the same bit-field rule otherwise, and clang aligns
1210        // it to one. gcc is the incumbent there, so its answer is the one taken.
1211        let mingw = target("x86_64-pc-windows-gnu");
1212        assert_eq!(
1213            lay_out_on(&mingw, &types, RecordKind::Union, &fields).layout,
1214            Layout::new(4, 4)
1215        );
1216    }
1217
1218    #[test]
1219    fn a_record_with_no_storage_in_it_is_four_bytes_under_msvc_and_nothing_anywhere_else() {
1220        let mut types = Types::new();
1221        let uint = types.int(IntKind::UInt);
1222        let mingw = target("x86_64-pc-windows-gnu");
1223
1224        // Three shapes that hold nothing, and the reference gives all three the same answer.
1225        let none: [FieldDecl; 0] = [];
1226        let zero_width = [unnamed_bits(uint, 0)];
1227        let flexible = [member(types.array(uint, ArrayLen::Unknown))];
1228        for fields in [&none[..], &zero_width[..], &flexible[..]] {
1229            let msvc = lay_out_on(&windows(), &types, RecordKind::Struct, fields);
1230            assert_eq!(msvc.layout.size, 4, "four bytes under MSVC");
1231            assert_eq!(lay_out_on(&mingw, &types, RecordKind::Struct, fields).layout.size, 0);
1232            assert_eq!(lay_out(&types, RecordKind::Struct, fields).layout.size, 0);
1233        }
1234
1235        // It is the environment that decides and not the operating system, so the two Windows
1236        // targets disagree with each other and mingw agrees with Linux. A rule keyed on the
1237        // operating system would have put both of them at four.
1238        assert_eq!(windows().empty_record_size, 4);
1239        assert_eq!(mingw.empty_record_size, 0);
1240    }
1241
1242    #[test]
1243    fn packed_drops_every_member_to_a_byte_and_bit_fields_to_the_next_free_bit() {
1244        let mut interner = Interner::new();
1245        let types = Types::new();
1246        let char_ = types.int(IntKind::Char);
1247        let int = types.int(IntKind::Int);
1248        let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1249
1250        let fields = [member(char_), member(int)];
1251        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1252            .expect("a packed struct of two complete members");
1253        assert_eq!(laid_out.layout, Layout::new(5, 1));
1254        assert_eq!(offsets(&laid_out), [0, 8]);
1255
1256        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1257        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1258            .expect("a packed struct with a bit-field");
1259        assert_eq!(laid_out.layout, Layout::new(5, 1));
1260        assert_eq!(offsets(&laid_out), [0, 8], "no boundary left to move to");
1261
1262        // A zero width bit-field still rounds to its own type, packed or not, which is the
1263        // whole reason a program writes one inside a packed structure.
1264        let fields = [member(char_), unnamed_bits(int, 0), member(char_)];
1265        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1266            .expect("a packed struct with a zero width bit-field");
1267        assert_eq!(laid_out.layout, Layout::new(5, 1));
1268        assert_eq!(offsets(&laid_out), [0, 32, 32]);
1269    }
1270
1271    #[test]
1272    fn pragma_pack_caps_alignment_and_leaves_a_bit_field_where_it_already_is() {
1273        let mut interner = Interner::new();
1274        let types = Types::new();
1275        let char_ = types.int(IntKind::Char);
1276        let int = types.int(IntKind::Int);
1277        let pack = RecordOptions { pack: Some(2), ..RecordOptions::default() };
1278
1279        let fields = [member(char_), member(int)];
1280        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1281            .expect("a packed struct of two complete members");
1282        assert_eq!(laid_out.layout, Layout::new(6, 2));
1283        assert_eq!(offsets(&laid_out), [0, 16]);
1284
1285        // Six bytes with the field at bit eight, not at bit sixteen. Once the alignment has
1286        // been capped below the type's own there is no boundary to move to, so the field stays
1287        // put. Measured, because moving it is at least as plausible a reading.
1288        let fields = [member(char_), bits(&mut interner, "b", int, 30)];
1289        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1290            .expect("a packed struct with a bit-field");
1291        assert_eq!(laid_out.layout, Layout::new(6, 2));
1292        assert_eq!(offsets(&laid_out), [0, 8]);
1293
1294        // The same structure with the field unnamed is five bytes aligned to one, because the
1295        // capped alignment reached it through the record and an unnamed field gives none back.
1296        let fields = [member(char_), unnamed_bits(int, 30)];
1297        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1298            .expect("a packed struct with an unnamed bit-field");
1299        assert_eq!(laid_out.layout, Layout::new(5, 1));
1300    }
1301
1302    #[test]
1303    fn an_alignment_the_program_asked_for_raises_the_member_and_the_record() {
1304        let types = Types::new();
1305        let char_ = types.int(IntKind::Char);
1306        let int = types.int(IntKind::Int);
1307
1308        let aligned = FieldDecl { align: Some(16), ..member(int) };
1309        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), aligned]);
1310        assert_eq!(laid_out.layout, Layout::new(32, 16));
1311        assert_eq!(offsets(&laid_out), [0, 128]);
1312
1313        // `packed, aligned(4)` together: the members pack and the record does not, which is
1314        // the combination the attribute pair exists for.
1315        let options = RecordOptions { packed: true, align: Some(4), ..RecordOptions::default() };
1316        let fields = [member(char_), member(int)];
1317        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
1318            .expect("a packed struct with an alignment asked for");
1319        assert_eq!(laid_out.layout, Layout::new(8, 4));
1320        assert_eq!(offsets(&laid_out), [0, 8]);
1321    }
1322
1323    #[test]
1324    fn an_alignment_asked_for_on_a_bit_field_moves_it_even_when_packed() {
1325        let mut interner = Interner::new();
1326        let types = Types::new();
1327        let char_ = types.int(IntKind::Char);
1328        let int = types.int(IntKind::Int);
1329        let long_long = types.int(IntKind::LongLong);
1330
1331        // Not packed: the field goes to the next sixteen byte boundary and takes the record
1332        // with it, where without the request it would have shared the first byte.
1333        let aligned = FieldDecl { align: Some(16), ..bits(&mut interner, "a", char_, 4) };
1334        let fields = [bits(&mut interner, "x", char_, 3), aligned];
1335        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1336        assert_eq!(laid_out.layout, Layout::new(32, 16));
1337        assert_eq!(offsets(&laid_out), [0, 128]);
1338
1339        // Packed, the request still wins over the next free bit.
1340        let packed = RecordOptions { packed: true, ..RecordOptions::default() };
1341        let aligned = FieldDecl { align: Some(4), ..bits(&mut interner, "a", int, 4) };
1342        let fields = [bits(&mut interner, "x", char_, 3), aligned];
1343        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1344            .expect("a packed struct with an aligned bit-field");
1345        assert_eq!(laid_out.layout, Layout::new(8, 4));
1346        assert_eq!(offsets(&laid_out), [0, 32]);
1347
1348        // `aligned(1)` asks for nothing an `int` did not have, and packed it still means the
1349        // next whole byte rather than the next bit.
1350        let aligned = FieldDecl { align: Some(1), ..bits(&mut interner, "a", int, 4) };
1351        let fields = [bits(&mut interner, "x", char_, 3), aligned];
1352        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &packed, &linux())
1353            .expect("a packed struct with a byte aligned bit-field");
1354        assert_eq!(laid_out.layout, Layout::new(2, 1));
1355        assert_eq!(offsets(&laid_out), [0, 8]);
1356
1357        // Under `#pragma pack(1)` an `aligned(16)` is capped to a byte and still moves the field
1358        // to one, which is the layout tcc's `95_bitfields` prints under gcc.
1359        let pack = RecordOptions { pack: Some(1), ..RecordOptions::default() };
1360        let fields = [
1361            bits(&mut interner, "x", int, 12),
1362            bits(&mut interner, "y", char_, 6),
1363            bits(&mut interner, "z", long_long, 63),
1364            FieldDecl { align: Some(16), ..bits(&mut interner, "a", char_, 4) },
1365            bits(&mut interner, "b", long_long, 2),
1366        ];
1367        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &pack, &linux())
1368            .expect("a struct under pragma pack with an aligned bit-field");
1369        assert_eq!(laid_out.layout, Layout::new(12, 1));
1370        assert_eq!(offsets(&laid_out), [0, 12, 18, 88, 92]);
1371    }
1372
1373    #[test]
1374    fn a_flexible_array_member_costs_nothing_but_its_alignment() {
1375        // What makes `malloc(sizeof(struct S) + n)` the idiom it is.
1376        let mut types = Types::new();
1377        let char_ = types.int(IntKind::Char);
1378        let int = types.int(IntKind::Int);
1379        let long_long = types.int(IntKind::LongLong);
1380
1381        let chars = types.array(char_, ArrayLen::Unknown);
1382        let laid_out = lay_out(&types, RecordKind::Struct, &[member(int), member(chars)]);
1383        assert_eq!(laid_out.layout, Layout::new(4, 4));
1384        assert_eq!(offsets(&laid_out), [0, 32]);
1385
1386        // The alignment still applies, so this is eight bytes of which one is the `char`.
1387        let longs = types.array(long_long, ArrayLen::Unknown);
1388        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(longs)]);
1389        assert_eq!(laid_out.layout, Layout::new(8, 8));
1390        assert_eq!(offsets(&laid_out), [0, 64]);
1391
1392        // Anywhere but last it is an incomplete member, and which member is part of the answer.
1393        let fields = [member(chars), member(int)];
1394        let error =
1395            layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1396        assert_eq!(error, Err(RecordError::Member { index: 0, error: LayoutError::Incomplete }));
1397    }
1398
1399    #[test]
1400    fn a_record_with_no_members_is_zero_bytes_aligned_to_one() {
1401        // The GNU empty structure, which C itself does not have and which real headers do.
1402        let types = Types::new();
1403        let laid_out = lay_out(&types, RecordKind::Struct, &[]);
1404        assert_eq!(laid_out.layout, Layout::new(0, 1));
1405    }
1406
1407    #[test]
1408    fn a_bit_field_wider_than_the_type_it_is_declared_with_is_refused() {
1409        let types = Types::new();
1410        let int = types.int(IntKind::Int);
1411        let fields = [unnamed_bits(int, 33)];
1412        let error =
1413            layout_record(&types, RecordKind::Struct, &fields, &RecordOptions::default(), &linux());
1414        let want = RecordError::BitFieldTooWide { index: 0, width: 33, capacity: 32 };
1415        assert_eq!(error, Err(want));
1416    }
1417
1418    #[test]
1419    fn a_record_reports_its_members_once_it_has_been_completed() {
1420        let mut interner = Interner::new();
1421        let mut types = Types::new();
1422        let char_ = types.int(IntKind::Char);
1423        let int = types.int(IntKind::Int);
1424        let name = interner.intern("count");
1425        let fields = [member(char_), FieldDecl::new(Some(name), int)];
1426        let id = types.declare_record(RecordKind::Struct, None);
1427        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
1428        types.complete_record(id, laid_out);
1429        let ty = types.record(id);
1430        assert_eq!(layout(&types, ty, &linux()).unwrap(), Layout::new(8, 4));
1431        let field = types.field(id, name).expect("the member that was declared");
1432        assert_eq!(field.offset, 4);
1433        assert!(!field.is_bit_field());
1434        assert_eq!(types.field(id, interner.intern("missing")), None);
1435    }
1436
1437    #[test]
1438    fn a_nested_record_brings_its_own_alignment_with_it() {
1439        let mut types = Types::new();
1440        let char_ = types.int(IntKind::Char);
1441        let int = types.int(IntKind::Int);
1442        let inner = record(&mut types, RecordKind::Struct, &[member(char_)]);
1443        let laid_out = lay_out(&types, RecordKind::Struct, &[member(inner), member(int)]);
1444        assert_eq!(laid_out.layout, Layout::new(8, 4));
1445        assert_eq!(offsets(&laid_out), [0, 32]);
1446
1447        // An anonymous member is an ordinary member with no name, so the same code lays it out
1448        // and the four bytes of padding after the `char` are there either way.
1449        let anonymous = record(&mut types, RecordKind::Struct, &[member(int), member(char_)]);
1450        let laid_out = lay_out(&types, RecordKind::Struct, &[member(char_), member(anonymous)]);
1451        assert_eq!(laid_out.layout, Layout::new(12, 4));
1452        assert_eq!(offsets(&laid_out), [0, 32]);
1453    }
1454
1455    #[test]
1456    fn everything_narrower_than_an_int_promotes_to_one() {
1457        // Measured by naming the type of `+x` with `_Generic` in gcc 13.3 and clang 18. Every
1458        // one of these answers `int`, including the unsigned ones, because an `int` holds every
1459        // value a sixteen bit unsigned type has.
1460        let mut types = Types::new();
1461        let linux = linux();
1462        let int = types.int(IntKind::Int);
1463        let narrow =
1464            [IntKind::Char, IntKind::SChar, IntKind::UChar, IntKind::Short, IntKind::UShort];
1465        for kind in narrow {
1466            let ty = types.int(kind);
1467            assert_eq!(promote(&mut types, ty, &linux), int, "{}", kind.as_str());
1468        }
1469        let boolean = types.boolean();
1470        assert_eq!(promote(&mut types, boolean, &linux), int, "C23 made bool a real type");
1471
1472        // From `int` up, a type is its own promotion.
1473        for kind in [IntKind::Int, IntKind::UInt, IntKind::Long, IntKind::ULongLong] {
1474            let ty = types.int(kind);
1475            assert_eq!(promote(&mut types, ty, &linux), ty, "{}", kind.as_str());
1476        }
1477    }
1478
1479    #[test]
1480    fn a_bit_int_is_not_promoted_at_all() {
1481        // C23 6.3.1.1p2, and the point of the type. `_BitInt(8) + _BitInt(8)` stays eight bits
1482        // wide where `char + char` is an `int`, which is what makes the width mean something.
1483        let mut types = Types::new();
1484        let linux = linux();
1485        let small = types.bit_int(true, 8);
1486        assert_eq!(promote(&mut types, small, &linux), small);
1487        assert_eq!(usual_arithmetic(&mut types, small, small, &linux), Some(small));
1488    }
1489
1490    #[test]
1491    fn a_bit_field_is_promoted_by_its_width_and_not_by_its_type() {
1492        let mut types = Types::new();
1493        let linux = linux();
1494        let int = types.int(IntKind::Int);
1495        let uint = types.int(IntKind::UInt);
1496        let ullong = types.int(IntKind::ULongLong);
1497
1498        // Three bits of an unsigned field all fit in an `int`, so it is signed afterwards.
1499        assert_eq!(promote_bit_field(&mut types, uint, 3, &linux), int);
1500        // Thirty two of them do not.
1501        assert_eq!(promote_bit_field(&mut types, uint, 32, &linux), uint);
1502        // Twenty bits of a signed field, which is an `int` either way.
1503        assert_eq!(promote_bit_field(&mut types, int, 20, &linux), int);
1504        // Forty bits are forty bits of value and nothing more. The C17 wording says `unsigned
1505        // int` here, which would silently drop eight of them, and C23 says the declared type,
1506        // which would silently add twenty four. Both compilers give the width instead, so
1507        // `x.b << 32` on such a field is zero rather than a value with a bit above the fortieth.
1508        let forty = types.bit_int(false, 40);
1509        assert_eq!(promote_bit_field(&mut types, ullong, 40, &linux), forty);
1510        // A field as wide as its type is that type, since there is no precision to lose.
1511        assert_eq!(promote_bit_field(&mut types, ullong, 64, &linux), ullong);
1512    }
1513
1514    #[test]
1515    fn an_enumeration_promotes_through_what_it_is_represented_in() {
1516        let mut types = Types::new();
1517        let linux = linux();
1518        let int = types.int(IntKind::Int);
1519        let short = types.int(IntKind::Short);
1520        let uint = types.int(IntKind::UInt);
1521
1522        // `enum E : short` promotes the same way a `short` does, which is to `int`.
1523        let fixed = types.declare_enum(None);
1524        types.complete_enum(fixed, short, true);
1525        let fixed = types.enumeration(fixed);
1526        assert_eq!(promote(&mut types, fixed, &linux), int);
1527
1528        // An enumeration all of whose enumerators are non-negative is represented in
1529        // `unsigned int` by both compilers, and then it promotes to itself.
1530        let unsigned = types.declare_enum(None);
1531        types.complete_enum(unsigned, uint, false);
1532        let unsigned = types.enumeration(unsigned);
1533        assert_eq!(promote(&mut types, unsigned, &linux), uint);
1534
1535        // An enumeration nobody has decided on yet answers `int`, so that an expression using
1536        // one is still checkable while the diagnostic about it is being written.
1537        let undecided = types.declare_enum(None);
1538        let undecided = types.enumeration(undecided);
1539        assert_eq!(promote(&mut types, undecided, &linux), int);
1540    }
1541
1542    #[test]
1543    fn the_qualifiers_and_the_atomic_come_off_before_anything_else() {
1544        // By the time a value is being promoted the lvalue conversion has already happened, so
1545        // `_Atomic const int` and `int` are the same operand.
1546        let mut types = Types::new();
1547        let linux = linux();
1548        let int = types.int(IntKind::Int);
1549        let konst = types.qualified(int, Qualifiers::CONST);
1550        let atomic = types.atomic(konst);
1551        assert_eq!(promote(&mut types, atomic, &linux), int);
1552        assert_eq!(usual_arithmetic(&mut types, atomic, konst, &linux), Some(int));
1553    }
1554
1555    #[test]
1556    fn the_usual_arithmetic_conversions_between_the_standard_integer_types() {
1557        // Every row measured with `_Generic` in gcc 13.3 and clang 18 on x86-64 Linux.
1558        let mut types = Types::new();
1559        let linux = linux();
1560        let cases = [
1561            (IntKind::Int, IntKind::UInt, IntKind::UInt),
1562            (IntKind::Int, IntKind::Long, IntKind::Long),
1563            (IntKind::UInt, IntKind::Long, IntKind::Long),
1564            (IntKind::UInt, IntKind::ULong, IntKind::ULong),
1565            (IntKind::Int, IntKind::LongLong, IntKind::LongLong),
1566            (IntKind::UInt, IntKind::LongLong, IntKind::LongLong),
1567            (IntKind::ULong, IntKind::LongLong, IntKind::ULongLong),
1568            (IntKind::Char, IntKind::Char, IntKind::Int),
1569            (IntKind::UChar, IntKind::UShort, IntKind::Int),
1570        ];
1571        for (left, right, want) in cases {
1572            let left = types.int(left);
1573            let right = types.int(right);
1574            let want = types.int(want);
1575            assert_eq!(usual_arithmetic(&mut types, left, right, &linux), Some(want));
1576            assert_eq!(usual_arithmetic(&mut types, right, left, &linux), Some(want), "either way");
1577        }
1578    }
1579
1580    #[test]
1581    fn int128_is_sixteen_bytes_aligned_to_sixteen_and_outranks_long_long() {
1582        // Measured on gcc 13.3 on x86-64 Linux and clang on AArch64 Darwin, both of which
1583        // report the same size, the same alignment, and an offset of sixteen for a member
1584        // after a `char`.
1585        let mut types = Types::new();
1586        let linux = linux();
1587        let signed = types.int(IntKind::Int128);
1588        let unsigned = types.int(IntKind::UInt128);
1589        for id in [signed, unsigned] {
1590            let laid_out = layout(&types, id, &linux).expect("a complete type");
1591            assert_eq!(laid_out.size, 16);
1592            assert_eq!(laid_out.align, 16);
1593        }
1594
1595        // `__int128 + unsigned long long` is `__int128`, because it wins on rank and is wide
1596        // enough to hold every value the other side had. Both compilers agree, and it is the
1597        // one pair that says the rank is above `long long` rather than beside it.
1598        let ull = types.int(IntKind::ULongLong);
1599        assert_eq!(usual_arithmetic(&mut types, signed, ull, &linux), Some(signed));
1600        // And it is its own promotion, the way every type at or above `int` is.
1601        assert_eq!(promote(&mut types, signed, &linux), signed);
1602    }
1603
1604    #[test]
1605    fn a_bit_int_of_a_hundred_and_twenty_eight_bits_is_not_int128() {
1606        // Same width, different types. The alignment is the visible difference on x86-64,
1607        // where a `_BitInt` is aligned to its sixty four bit granule and `__int128` is not.
1608        let mut types = Types::new();
1609        let linux = linux();
1610        let int128 = types.int(IntKind::Int128);
1611        let bit_int = types.bit_int(true, 128);
1612        assert_ne!(int128, bit_int);
1613        assert!(!compatible(&types, int128, bit_int));
1614        assert_eq!(layout(&types, bit_int, &linux).expect("complete").align, 8);
1615        assert_eq!(layout(&types, int128, &linux).expect("complete").align, 16);
1616    }
1617
1618    #[test]
1619    fn the_last_arm_takes_the_unsigned_type_of_the_wider_one() {
1620        // `unsigned long + long long` is `unsigned long long` on Linux: the `long long` wins on
1621        // rank and cannot hold every value of the `unsigned long`, so neither operand's own
1622        // type is the answer. This is the arm programs are surprised by.
1623        let mut types = Types::new();
1624        let linux = linux();
1625        let ulong = types.int(IntKind::ULong);
1626        let long_long = types.int(IntKind::LongLong);
1627        let want = types.int(IntKind::ULongLong);
1628        assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &linux), Some(want));
1629
1630        // The same pair on Windows, where `long` is thirty two bits, comes out as `long long`,
1631        // because there it does hold every value. A host-driven implementation gets one of
1632        // these two wrong.
1633        let windows = target("x86_64-pc-windows-msvc");
1634        assert_eq!(usual_arithmetic(&mut types, ulong, long_long, &windows), Some(long_long));
1635    }
1636
1637    #[test]
1638    fn a_bit_int_is_ranked_by_its_width_against_the_standard_types() {
1639        // Measured with clang 18 on x86-64 Linux, which is the compiler that has `_BitInt`.
1640        let mut types = Types::new();
1641        let linux = linux();
1642        let b40 = types.bit_int(true, 40);
1643        let ub40 = types.bit_int(false, 40);
1644        let b8 = types.bit_int(true, 8);
1645        let b32 = types.bit_int(true, 32);
1646        let int = types.int(IntKind::Int);
1647        let uint = types.int(IntKind::UInt);
1648        let long = types.int(IntKind::Long);
1649        let char_ = types.int(IntKind::Char);
1650
1651        // Wider than an `int`, so it outranks one.
1652        assert_eq!(usual_arithmetic(&mut types, b40, int, &linux), Some(b40));
1653        // Narrower than a `long`, so it loses to one.
1654        assert_eq!(usual_arithmetic(&mut types, b40, long, &linux), Some(long));
1655        // The same width as an `int`, and a standard type wins the tie.
1656        assert_eq!(usual_arithmetic(&mut types, b32, int, &linux), Some(int));
1657        assert_eq!(usual_arithmetic(&mut types, b32, uint, &linux), Some(uint));
1658        // The other side promotes first, so a `char` next to a narrow `_BitInt` is an `int`
1659        // and the `_BitInt` loses to it.
1660        assert_eq!(usual_arithmetic(&mut types, b8, char_, &linux), Some(int));
1661        // Unsigned and higher ranked wins outright, and unsigned and lower ranked loses to a
1662        // signed type wide enough to hold it.
1663        assert_eq!(usual_arithmetic(&mut types, ub40, int, &linux), Some(ub40));
1664        assert_eq!(usual_arithmetic(&mut types, ub40, long, &linux), Some(long));
1665        // Two bit-precise types of the same width and different signedness.
1666        assert_eq!(usual_arithmetic(&mut types, b40, ub40, &linux), Some(ub40));
1667    }
1668
1669    #[test]
1670    fn a_floating_operand_decides_the_answer_whatever_the_other_side_is() {
1671        let mut types = Types::new();
1672        let linux = linux();
1673        let float = types.float(FloatKind::Float);
1674        let double = types.float(FloatKind::Double);
1675        let long_double = types.float(FloatKind::LongDouble);
1676        let ullong = types.int(IntKind::ULongLong);
1677        let int = types.int(IntKind::Int);
1678
1679        assert_eq!(usual_arithmetic(&mut types, int, float, &linux), Some(float));
1680        assert_eq!(usual_arithmetic(&mut types, float, double, &linux), Some(double));
1681        assert_eq!(usual_arithmetic(&mut types, double, long_double, &linux), Some(long_double));
1682        // Sixty four bits of unsigned integer against a `float`, which is a `float` and loses
1683        // most of them. That is the rule rather than an oversight.
1684        assert_eq!(usual_arithmetic(&mut types, ullong, float, &linux), Some(float));
1685    }
1686
1687    #[test]
1688    fn a_mask_is_the_signed_integers_of_the_lane_width() {
1689        let mut types = Types::new();
1690        let linux = linux();
1691        let int = types.int(IntKind::Int);
1692        let float = types.float(FloatKind::Float);
1693        let short = types.int(IntKind::Short);
1694
1695        // A signed lane is already its own mask, so the answer is the vector it was given.
1696        let four_ints = types.vector(int, 4);
1697        assert_eq!(mask_of(&mut types, four_ints, &linux), Some(four_ints));
1698
1699        // An unsigned lane answers as the signed type of the same width, which is what GCC
1700        // gives a comparison of two `unsigned int` vectors.
1701        let uint = types.int(IntKind::UInt);
1702        let four_uints = types.vector(uint, 4);
1703        assert_eq!(mask_of(&mut types, four_uints, &linux), Some(four_ints));
1704
1705        // A float lane answers as an integer of the same width, since the mask is bits and not
1706        // a number and there is no float that is all ones.
1707        let four_floats = types.vector(float, 4);
1708        assert_eq!(mask_of(&mut types, four_floats, &linux), Some(four_ints));
1709
1710        // The width is the lane's own and not a word, so a `short` lane keeps its two bytes.
1711        let two_shorts = types.vector(short, 2);
1712        assert_eq!(mask_of(&mut types, two_shorts, &linux), Some(two_shorts));
1713
1714        // Not a vector, so there is no mask to give.
1715        assert_eq!(mask_of(&mut types, int, &linux), None);
1716    }
1717
1718    #[test]
1719    fn two_vectors_convert_between_each_other_when_the_bytes_line_up() {
1720        let mut types = Types::new();
1721        let linux = linux();
1722        let int = types.int(IntKind::Int);
1723        let uint = types.int(IntKind::UInt);
1724        let float = types.float(FloatKind::Float);
1725        let short = types.int(IntKind::Short);
1726
1727        let four_ints = types.vector(int, 4);
1728        let four_uints = types.vector(uint, 4);
1729        let four_floats = types.vector(float, 4);
1730        let eight_shorts = types.vector(short, 8);
1731        let two_ints = types.vector(int, 2);
1732
1733        // The case the whole thing exists for: a mask assigned to the unsigned vector it came
1734        // from, which GNU C converts and the standard rules would refuse.
1735        assert!(vectors_convertible(&types, four_uints, four_ints, &linux));
1736        // Both ways round, since assignment happens in both directions.
1737        assert!(vectors_convertible(&types, four_ints, four_uints, &linux));
1738        // The same sixteen bytes cut into eight lanes rather than four, which GCC also allows.
1739        assert!(vectors_convertible(&types, four_ints, eight_shorts, &linux));
1740        // Two floats of the same width, which is the other half of the rule.
1741        assert!(vectors_convertible(&types, four_floats, four_floats, &linux));
1742
1743        // An integer lane against a float lane, which GCC refuses even at the same size,
1744        // because reading one as the other is a cast and not a conversion.
1745        assert!(!vectors_convertible(&types, four_ints, four_floats, &linux));
1746        // Different sizes, so there is nothing to reinterpret.
1747        assert!(!vectors_convertible(&types, four_ints, two_ints, &linux));
1748        // A scalar is not a vector, whichever side it is on.
1749        assert!(!vectors_convertible(&types, four_ints, int, &linux));
1750        assert!(!vectors_convertible(&types, int, four_ints, &linux));
1751    }
1752
1753    /// Insists that `a + b` and `b + a` are both `expected` on this target.
1754    ///
1755    /// Both ways round, because the operands of `+` are not ordered and an implementation that
1756    /// keeps the left one when it cannot decide would pass half of these and be wrong.
1757    fn combines(target: &TargetInfo, a: FloatKind, b: FloatKind, expected: FloatKind) {
1758        let mut types = Types::new();
1759        let left = types.float(a);
1760        let right = types.float(b);
1761        let want = types.float(expected);
1762        assert_eq!(usual_arithmetic(&mut types, left, right, target), Some(want), "{a:?} + {b:?}");
1763        assert_eq!(usual_arithmetic(&mut types, right, left, target), Some(want), "{b:?} + {a:?}");
1764    }
1765
1766    #[test]
1767    fn two_floating_types_of_the_same_format_are_still_two_types_and_one_of_them_wins() {
1768        // Every line here was read off gcc 16 with `_Generic` rather than off the standard, on
1769        // x86-64 Linux, where `long double` and `_Float64x` are both the x87 format and the
1770        // standard type is the one that comes out.
1771        let x86 = linux();
1772        combines(&x86, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1773        combines(&x86, FloatKind::Float, FloatKind::Float32, FloatKind::Float32);
1774        combines(&x86, FloatKind::Double, FloatKind::Float32x, FloatKind::Double);
1775        combines(&x86, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::LongDouble);
1776        combines(&x86, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1777        combines(&x86, FloatKind::Float64x, FloatKind::Float128, FloatKind::Float128);
1778        combines(&x86, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1779        combines(&x86, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1780        combines(&x86, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1781        combines(&x86, FloatKind::LongDouble, FloatKind::Float64, FloatKind::LongDouble);
1782    }
1783
1784    #[test]
1785    fn the_widest_floating_type_is_a_question_about_the_target_and_not_about_the_names() {
1786        // The same reading against gcc 16 on aarch64-apple-darwin, where `long double` is a
1787        // `double` and loses to the `_Float64x` it beats on x86-64. The name says nothing about
1788        // which of the two is wider, which is why the ordering is worked out from the formats.
1789        let mac = target("aarch64-apple-darwin");
1790        combines(&mac, FloatKind::LongDouble, FloatKind::Float64x, FloatKind::Float64x);
1791        combines(&mac, FloatKind::Double, FloatKind::LongDouble, FloatKind::LongDouble);
1792        combines(&mac, FloatKind::Float128, FloatKind::LongDouble, FloatKind::Float128);
1793        combines(&mac, FloatKind::Float64x, FloatKind::Float64, FloatKind::Float64x);
1794        combines(&mac, FloatKind::Float32x, FloatKind::Float32, FloatKind::Float32x);
1795        combines(&mac, FloatKind::Float32x, FloatKind::Float64, FloatKind::Float64);
1796        combines(&mac, FloatKind::Double, FloatKind::Float64, FloatKind::Float64);
1797        // `_Float16` is the narrowest type there is and does not promote on the way in, so it
1798        // survives an operation only when nothing wider is there.
1799        combines(&mac, FloatKind::Float16, FloatKind::Float, FloatKind::Float);
1800        combines(&mac, FloatKind::Float16, FloatKind::Double, FloatKind::Double);
1801        combines(&mac, FloatKind::Float16, FloatKind::Float16, FloatKind::Float16);
1802    }
1803
1804    #[test]
1805    fn a_complex_operand_makes_the_answer_complex_after_the_real_types_have_combined() {
1806        let mut types = Types::new();
1807        let linux = linux();
1808        let cfloat = types.complex_float(FloatKind::Float);
1809        let cdouble = types.complex_float(FloatKind::Double);
1810        let cldouble = types.complex_float(FloatKind::LongDouble);
1811        let double = types.float(FloatKind::Double);
1812        let long_double = types.float(FloatKind::LongDouble);
1813        let float = types.float(FloatKind::Float);
1814        let int = types.int(IntKind::Int);
1815
1816        assert_eq!(usual_arithmetic(&mut types, cfloat, double, &linux), Some(cdouble));
1817        assert_eq!(usual_arithmetic(&mut types, cfloat, int, &linux), Some(cfloat));
1818        assert_eq!(usual_arithmetic(&mut types, cdouble, long_double, &linux), Some(cldouble));
1819        assert_eq!(usual_arithmetic(&mut types, cfloat, float, &linux), Some(cfloat));
1820    }
1821
1822    #[test]
1823    fn an_operand_that_is_not_arithmetic_has_no_common_type() {
1824        // The caller is the one holding the span, so this says no rather than guessing.
1825        let mut types = Types::new();
1826        let linux = linux();
1827        let int = types.int(IntKind::Int);
1828        let pointer = types.pointer(int);
1829        assert_eq!(usual_arithmetic(&mut types, pointer, int, &linux), None);
1830        assert_eq!(usual_arithmetic(&mut types, pointer, pointer, &linux), None);
1831        let void = types.void();
1832        assert_eq!(usual_arithmetic(&mut types, void, int, &linux), None);
1833        // And a type that is not arithmetic is still its own promotion, so a caller may promote
1834        // first and ask questions afterwards.
1835        assert_eq!(promote(&mut types, pointer, &linux), pointer);
1836    }
1837
1838    #[test]
1839    fn the_conversions_read_through_sugar() {
1840        let mut interner = Interner::new();
1841        let mut types = Types::new();
1842        let linux = linux();
1843        let char_ = types.int(IntKind::Char);
1844        let name = types.typedef(interner.intern("byte"), char_);
1845        let int = types.int(IntKind::Int);
1846        assert_eq!(promote(&mut types, name, &linux), int);
1847    }
1848
1849    /// A prototype returning `void`.
1850    fn prototype(types: &mut Types, params: Vec<TypeId>, variadic: bool) -> TypeId {
1851        let ret = types.void();
1852        types.function(FunctionType {
1853            ret,
1854            params,
1855            variadic,
1856            prototyped: true,
1857            convention: rucc_target::Convention::Target,
1858        })
1859    }
1860
1861    /// `void f()` as it means before C23: a declaration that says nothing about the parameters.
1862    fn old_style(types: &mut Types) -> TypeId {
1863        let ret = types.void();
1864        types.function(FunctionType {
1865            ret,
1866            params: Vec::new(),
1867            variadic: false,
1868            prototyped: false,
1869            convention: rucc_target::Convention::Target,
1870        })
1871    }
1872
1873    /// A complete record with the given tag and members.
1874    fn tagged(types: &mut Types, tag: Symbol, fields: &[FieldDecl]) -> RecordId {
1875        let id = types.declare_record(RecordKind::Struct, Some(tag));
1876        let laid_out = lay_out(types, RecordKind::Struct, fields);
1877        types.complete_record(id, laid_out);
1878        id
1879    }
1880
1881    #[test]
1882    fn a_type_is_compatible_with_itself_however_it_was_written() {
1883        let mut interner = Interner::new();
1884        let mut types = Types::new();
1885        let int = types.int(IntKind::Int);
1886        let name = types.typedef(interner.intern("int32_t"), int);
1887        assert!(compatible(&types, name, int), "the sugar is the same type underneath");
1888        assert_eq!(composite(&mut types, name, int), Some(name), "and it keeps its name");
1889
1890        // The qualifiers have to match exactly, which is what keeps `const int *` and `int *`
1891        // apart as parameter types.
1892        let konst = types.qualified(int, Qualifiers::CONST);
1893        assert!(!compatible(&types, konst, int));
1894        let konst_pointer = types.pointer(konst);
1895        let pointer = types.pointer(int);
1896        assert!(!compatible(&types, konst_pointer, pointer));
1897        assert_eq!(composite(&mut types, konst_pointer, pointer), None);
1898
1899        // And a different type is a different type. `char` is not `signed char` even on a target
1900        // where the two have the same range, which is why they are separate kinds here.
1901        let char_ = types.int(IntKind::Char);
1902        let schar = types.int(IntKind::SChar);
1903        assert!(!compatible(&types, char_, schar));
1904        // `_Atomic int` is not `int` either, since it is a type and not a qualifier.
1905        let atomic = types.atomic(int);
1906        assert!(!compatible(&types, atomic, int));
1907    }
1908
1909    #[test]
1910    fn an_enumeration_is_compatible_with_the_type_it_is_represented_in() {
1911        // gcc 13.3 and clang 18 both represent `enum E { A, B }` in `unsigned int`, and both
1912        // accept a redeclaration that writes the representation instead of the tag.
1913        let mut types = Types::new();
1914        let uint = types.int(IntKind::UInt);
1915        let int = types.int(IntKind::Int);
1916        let id = types.declare_enum(None);
1917        types.complete_enum(id, uint, false);
1918        let e = types.enumeration(id);
1919        assert!(compatible(&types, e, uint));
1920        assert!(compatible(&types, uint, e), "and the relation is symmetric");
1921        assert!(!compatible(&types, e, int));
1922
1923        // Two enumeration declarations are two types. Each is compatible with what it is
1924        // represented in, and that does not make them compatible with each other.
1925        let other = types.declare_enum(None);
1926        types.complete_enum(other, uint, false);
1927        let other = types.enumeration(other);
1928        assert!(!compatible(&types, e, other));
1929
1930        // One nobody has decided on yet is compatible with nothing but itself, because the
1931        // answer is not known rather than no.
1932        let undecided = types.declare_enum(None);
1933        let undecided = types.enumeration(undecided);
1934        assert!(!compatible(&types, undecided, uint));
1935        assert!(compatible(&types, undecided, undecided));
1936    }
1937
1938    #[test]
1939    fn an_array_without_a_size_is_compatible_with_one_that_has_it() {
1940        // `extern int a[]; int a[4];` is a complete array of four afterwards, which gcc reports
1941        // as a `sizeof` of sixteen. A compiler that keeps the first type has lost the size.
1942        let mut types = Types::new();
1943        let int = types.int(IntKind::Int);
1944        let unknown = types.array(int, ArrayLen::Unknown);
1945        let four = types.array(int, ArrayLen::Fixed(4));
1946        let five = types.array(int, ArrayLen::Fixed(5));
1947        assert!(compatible(&types, unknown, four));
1948        assert!(!compatible(&types, four, five));
1949        assert_eq!(composite(&mut types, unknown, four), Some(four));
1950        assert_eq!(composite(&mut types, four, unknown), Some(four), "either way round");
1951        assert_eq!(composite(&mut types, four, five), None);
1952
1953        // A variable length array is compatible with both, because its size is not something a
1954        // declaration can be checked against.
1955        let vla = types.array(int, ArrayLen::Variable(VlaId(0)));
1956        assert!(compatible(&types, vla, four));
1957        assert_eq!(composite(&mut types, vla, four), Some(four));
1958
1959        // The element types have to be compatible too, and the composite reaches into them.
1960        let long = types.int(IntKind::Long);
1961        let longs = types.array(long, ArrayLen::Fixed(4));
1962        assert!(!compatible(&types, four, longs));
1963    }
1964
1965    #[test]
1966    fn a_parameter_declared_as_an_array_is_a_pointer() {
1967        // `int fn(int p[3])` and `int fn(int *p)` are one declaration and one definition, which
1968        // both compilers accept. The adjustment is part of forming the parameter type, so two
1969        // functions written either way are not merely compatible but identical.
1970        let mut types = Types::new();
1971        let int = types.int(IntKind::Int);
1972        let three = types.array(int, ArrayLen::Fixed(3));
1973        let pointer = types.pointer(int);
1974        assert_eq!(adjust_parameter(&mut types, three), pointer);
1975
1976        // A function parameter becomes a pointer to the function the same way.
1977        let function = prototype(&mut types, vec![int], false);
1978        let function_pointer = types.pointer(function);
1979        assert_eq!(adjust_parameter(&mut types, function), function_pointer);
1980
1981        // And the qualifiers on the outermost node go, so `void f(const int)` and `void f(int)`
1982        // declare the same function. The pointee of a `const int *` keeps its own.
1983        let konst = types.qualified(int, Qualifiers::CONST);
1984        assert_eq!(adjust_parameter(&mut types, konst), int);
1985        let to_konst = types.pointer(konst);
1986        assert_eq!(adjust_parameter(&mut types, to_konst), to_konst);
1987    }
1988
1989    #[test]
1990    fn an_old_style_declaration_is_compatible_with_the_prototypes_a_call_could_not_tell_from_it() {
1991        // Measured with gcc 13.3 in C17 mode, which is the compiler that still has the old
1992        // meaning of `()`. It names the rule in its own diagnostic: an argument type that has a
1993        // default promotion cannot match an empty parameter name list declaration.
1994        let mut types = Types::new();
1995        let old = old_style(&mut types);
1996        let int = types.int(IntKind::Int);
1997        let long = types.int(IntKind::Long);
1998        let char_ = types.int(IntKind::Char);
1999        let float = types.float(FloatKind::Float);
2000        let double = types.float(FloatKind::Double);
2001
2002        let takes_int = prototype(&mut types, vec![int], false);
2003        assert!(compatible(&types, old, takes_int));
2004        assert!(compatible(&types, takes_int, old), "and the relation is symmetric");
2005        // The composite is the prototype, so the calls written before it can still be checked.
2006        assert_eq!(composite(&mut types, old, takes_int), Some(takes_int));
2007
2008        let pointer = types.pointer(int);
2009        for params in [vec![long], vec![double], vec![pointer], vec![int, long]] {
2010            let ty = prototype(&mut types, params, false);
2011            assert!(compatible(&types, old, ty), "nothing here is touched by a promotion");
2012        }
2013
2014        // A `char` promotes to `int` and a `float` to `double`, so a call through the old style
2015        // declaration would have passed something else and the two conflict.
2016        for params in [vec![char_], vec![float], vec![int, char_]] {
2017            let ty = prototype(&mut types, params, false);
2018            assert!(!compatible(&types, old, ty));
2019            assert_eq!(composite(&mut types, old, ty), None);
2020        }
2021
2022        // An ellipsis conflicts too, which gcc also says in as many words.
2023        let variadic = prototype(&mut types, vec![int], true);
2024        assert!(!compatible(&types, old, variadic));
2025
2026        // An enumeration parameter comes through when what it is represented in does.
2027        let uint = types.int(IntKind::UInt);
2028        let id = types.declare_enum(None);
2029        types.complete_enum(id, uint, false);
2030        let e = types.enumeration(id);
2031        let takes_enum = prototype(&mut types, vec![e], false);
2032        assert!(compatible(&types, old, takes_enum));
2033
2034        // Two old style declarations agree about nothing and so cannot disagree.
2035        assert!(compatible(&types, old, old));
2036
2037        // The return type still has to match, which is the one part `()` does say.
2038        let returns_int = types.function(FunctionType {
2039            ret: int,
2040            params: Vec::new(),
2041            variadic: false,
2042            prototyped: false,
2043            convention: rucc_target::Convention::Target,
2044        });
2045        assert!(!compatible(&types, returns_int, takes_int));
2046    }
2047
2048    /// gcc's rule: a function of one convention and a function of the other are never
2049    /// compatible, however alike the rest of the two types is, and the composite of two that do
2050    /// agree keeps the convention.
2051    #[test]
2052    fn two_conventions_are_two_incompatible_types() {
2053        let mut types = Types::new();
2054        let int = types.int(IntKind::Int);
2055        let signature = FunctionType {
2056            ret: int,
2057            params: vec![int],
2058            variadic: false,
2059            prototyped: true,
2060            convention: rucc_target::Convention::Ms,
2061        };
2062        let native = types.function(FunctionType {
2063            convention: rucc_target::Convention::Target,
2064            ..signature.clone()
2065        });
2066        let ms = types.function(signature);
2067        let old_ms = types.function(FunctionType {
2068            ret: int,
2069            params: Vec::new(),
2070            variadic: false,
2071            prototyped: false,
2072            convention: rucc_target::Convention::Ms,
2073        });
2074        assert!(!compatible(&types, native, ms));
2075        let (to_native, to_ms) = (types.pointer(native), types.pointer(ms));
2076        assert!(!compatible(&types, to_native, to_ms));
2077        assert!(compatible(&types, ms, old_ms));
2078        let merged = composite(&mut types, old_ms, ms).expect("the two agree");
2079        let TypeKind::Function(id) = types.kind(merged) else { panic!("a function") };
2080        assert_eq!(types.signature(id).convention, rucc_target::Convention::Ms);
2081        assert!(types.signature(id).prototyped);
2082    }
2083
2084    #[test]
2085    fn from_c23_an_empty_parameter_list_is_a_prototype_and_conflicts_where_it_used_to_merge() {
2086        // The dialect decides what `()` means and the parser records the decision, so the same
2087        // pair of declarations is a redeclaration in C17 and a conflict in C23. Both compilers
2088        // report exactly that.
2089        let mut types = Types::new();
2090        let int = types.int(IntKind::Int);
2091        let takes_int = prototype(&mut types, vec![int], false);
2092        let takes_nothing = prototype(&mut types, Vec::new(), false);
2093        let old = old_style(&mut types);
2094        assert!(!compatible(&types, takes_nothing, takes_int));
2095        assert!(compatible(&types, old, takes_int), "the C17 reading of the same source");
2096    }
2097
2098    #[test]
2099    fn two_prototypes_have_to_agree_about_everything() {
2100        let mut types = Types::new();
2101        let int = types.int(IntKind::Int);
2102        let long = types.int(IntKind::Long);
2103        let base = prototype(&mut types, vec![int, int], false);
2104        for other in [vec![int], vec![int, long], vec![int, int, int], Vec::new()] {
2105            let other = prototype(&mut types, other, false);
2106            assert!(!compatible(&types, base, other));
2107        }
2108        let variadic = prototype(&mut types, vec![int, int], true);
2109        assert!(!compatible(&types, base, variadic), "`...` is part of the type");
2110
2111        // The parameters are compared with the same rules as anything else, so an array size
2112        // inside a parameter's type is compared and an unknown one is not.
2113        let four = types.array(int, ArrayLen::Fixed(4));
2114        let unknown = types.array(int, ArrayLen::Unknown);
2115        let to_four = types.pointer(four);
2116        let to_unknown = types.pointer(unknown);
2117        let a = prototype(&mut types, vec![to_four], false);
2118        let b = prototype(&mut types, vec![to_unknown], false);
2119        assert!(compatible(&types, a, b));
2120        // And the composite takes the size, which is the whole reason it exists.
2121        assert_eq!(composite(&mut types, a, b), Some(a));
2122    }
2123
2124    #[test]
2125    fn a_pointer_composite_reaches_through_to_what_is_pointed_at() {
2126        let mut types = Types::new();
2127        let int = types.int(IntKind::Int);
2128        let four = types.array(int, ArrayLen::Fixed(4));
2129        let unknown = types.array(int, ArrayLen::Unknown);
2130        let to_four = types.pointer(four);
2131        let to_unknown = types.pointer(unknown);
2132        assert_eq!(composite(&mut types, to_unknown, to_four), Some(to_four));
2133
2134        // The pointer's own qualifiers survive, since a compatible pair has the same ones.
2135        let konst_to_unknown = types.qualified(to_unknown, Qualifiers::CONST);
2136        let konst_to_four = types.qualified(to_four, Qualifiers::CONST);
2137        assert_eq!(composite(&mut types, konst_to_unknown, konst_to_four), Some(konst_to_four));
2138    }
2139
2140    #[test]
2141    fn two_record_declarations_with_the_same_tag_and_the_same_members_are_compatible() {
2142        // C23 6.2.7p1, which is what lets one header be included twice. clang 18 implements it
2143        // and gcc 13.3 still rejects the redefinition, so this is a divergence rather than a
2144        // reading; in the older dialects the redefinition never gets as far as being compared.
2145        let mut interner = Interner::new();
2146        let mut types = Types::new();
2147        let tag = interner.intern("point");
2148        let x = interner.intern("x");
2149        let y = interner.intern("y");
2150        let int = types.int(IntKind::Int);
2151        let members = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), int)];
2152
2153        let first = tagged(&mut types, tag, &members);
2154        let second = tagged(&mut types, tag, &members);
2155        let first = types.record(first);
2156        let second = types.record(second);
2157        assert_ne!(first, second, "still two declarations and two types");
2158        assert!(compatible(&types, first, second));
2159
2160        // A different member name, a different member type, a different count, a different tag
2161        // and a different keyword are each enough to make them different types.
2162        let z = interner.intern("z");
2163        let long = types.int(IntKind::Long);
2164        let renamed = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(z), int)];
2165        let retyped = [FieldDecl::new(Some(x), int), FieldDecl::new(Some(y), long)];
2166        for other in [&renamed[..], &retyped[..], &members[..1]] {
2167            let other = tagged(&mut types, tag, other);
2168            let other = types.record(other);
2169            assert!(!compatible(&types, first, other));
2170        }
2171        let elsewhere = tagged(&mut types, interner.intern("pair"), &members);
2172        let elsewhere = types.record(elsewhere);
2173        assert!(!compatible(&types, first, elsewhere));
2174
2175        // An anonymous record is compatible with nothing but itself: there is no name by which
2176        // a second declaration could be claiming to be the same type.
2177        let anonymous = record(&mut types, RecordKind::Struct, &members);
2178        let also_anonymous = record(&mut types, RecordKind::Struct, &members);
2179        assert!(!compatible(&types, anonymous, also_anonymous));
2180
2181        // Nor is an incomplete declaration, which has no members to compare.
2182        let incomplete = types.declare_record(RecordKind::Struct, Some(tag));
2183        let incomplete = types.record(incomplete);
2184        assert!(!compatible(&types, first, incomplete));
2185        assert!(compatible(&types, incomplete, incomplete));
2186    }
2187
2188    #[test]
2189    fn a_self_referential_record_is_compared_without_going_round_forever() {
2190        // `struct node { int value; struct node *next; }` declared twice. Comparing the two
2191        // reaches the same pair again through the pointer, and the second time it is an
2192        // assumption rather than a question.
2193        let mut interner = Interner::new();
2194        let mut types = Types::new();
2195        let tag = interner.intern("node");
2196        let value = interner.intern("value");
2197        let next = interner.intern("next");
2198        let int = types.int(IntKind::Int);
2199
2200        let node = |types: &mut Types| {
2201            let id = types.declare_record(RecordKind::Struct, Some(tag));
2202            let ty = types.record(id);
2203            let pointer = types.pointer(ty);
2204            let members = [FieldDecl::new(Some(value), int), FieldDecl::new(Some(next), pointer)];
2205            let laid_out = lay_out(types, RecordKind::Struct, &members);
2206            types.complete_record(id, laid_out);
2207            ty
2208        };
2209        let first = node(&mut types);
2210        let second = node(&mut types);
2211        assert_ne!(first, second);
2212        assert!(compatible(&types, first, second));
2213
2214        // The guard is an assumption and not an answer, so a difference below the cycle is still
2215        // found: the same structure with the two members the other way round is a different one.
2216        let id = types.declare_record(RecordKind::Struct, Some(tag));
2217        let ty = types.record(id);
2218        let pointer = types.pointer(ty);
2219        let members = [FieldDecl::new(Some(next), pointer), FieldDecl::new(Some(value), int)];
2220        let laid_out = lay_out(&types, RecordKind::Struct, &members);
2221        types.complete_record(id, laid_out);
2222        assert!(!compatible(&types, first, ty));
2223    }
2224
2225    #[test]
2226    fn layout_reads_through_sugar() {
2227        let mut interner = Interner::new();
2228        let mut types = Types::new();
2229        let long = types.int(IntKind::Long);
2230        let name = types.typedef(interner.intern("word"), long);
2231        let array = types.array(name, ArrayLen::Fixed(4));
2232        assert_eq!(layout(&types, array, &linux()).unwrap(), Layout::new(32, 8));
2233    }
2234
2235    /// A recipe worked out, with `sizes` standing for how large each member turned out to be.
2236    ///
2237    /// The lowering does this with instructions and this does it with numbers, which is what
2238    /// makes a recipe testable here: the tree is the whole answer, and what a member is as long
2239    /// as is the only thing either side has to be told.
2240    fn work_out(recipe: &Extent, sizes: &[u64]) -> u64 {
2241        match recipe {
2242            Extent::Bytes(count) => *count,
2243            Extent::Member(index) => sizes[*index as usize],
2244            Extent::Sum(parts) => parts.iter().map(|part| work_out(part, sizes)).sum(),
2245            Extent::RoundUp(inner, to) => work_out(inner, sizes).next_multiple_of(*to),
2246            Extent::Max(parts) => parts.iter().map(|part| work_out(part, sizes)).max().unwrap_or(0),
2247        }
2248    }
2249
2250    /// An array of `int` whose length the program computes.
2251    fn measured(types: &mut Types, which: u32) -> TypeId {
2252        let int = types.int(IntKind::Int);
2253        types.array(int, ArrayLen::Variable(VlaId(which)))
2254    }
2255
2256    #[test]
2257    fn a_member_of_no_fixed_size_leaves_the_size_and_what_follows_it_to_the_program() {
2258        let mut types = Types::new();
2259        let int = types.int(IntKind::Int);
2260        let rows = measured(&mut types, 0);
2261        let laid_out = lay_out(&types, RecordKind::Struct, &[member(rows), member(int)]);
2262
2263        // Nothing is known here but the alignment, which never varies: it is decided by the
2264        // members rather than by where they land.
2265        assert_eq!(laid_out.layout, Layout::new(0, 4));
2266        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2267        // The member in front of the variable one sits where its number says, and the one after
2268        // it does not. There is no rounding in between, because an array of `int` ends on a four
2269        // byte boundary however long it is.
2270        assert_eq!(variable.offsets[0], None);
2271        let after = variable.offsets[1].as_ref().expect("an offset the program works out");
2272        for count in 0..6u64 {
2273            let sizes = [4 * count, 4];
2274            assert_eq!(work_out(after, &sizes), 4 * count);
2275            assert_eq!(work_out(&variable.size, &sizes), 4 * count + 4);
2276        }
2277        assert_eq!(laid_out.fields[1].align, 4);
2278    }
2279
2280    #[test]
2281    fn a_member_after_one_of_no_fixed_size_is_rounded_up_where_its_alignment_asks_for_it() {
2282        let mut types = Types::new();
2283        let char_ty = types.int(IntKind::Char);
2284        let rows = measured(&mut types, 0);
2285        let double = types.float(FloatKind::Double);
2286        let fields = [member(char_ty), member(rows), member(double)];
2287        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2288
2289        assert_eq!(laid_out.layout, Layout::new(0, 8));
2290        assert_eq!(offsets(&laid_out)[..2], [0, 32]);
2291        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2292        assert_eq!(variable.offsets[..2], [None, None]);
2293        let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2294        for count in 0..6u64 {
2295            let sizes = [1, 4 * count, 8];
2296            let at = (4 + 4 * count).next_multiple_of(8);
2297            assert_eq!(work_out(after, &sizes), at);
2298            assert_eq!(work_out(&variable.size, &sizes), at + 8);
2299        }
2300    }
2301
2302    #[test]
2303    fn a_union_with_a_member_of_no_fixed_size_is_as_long_as_the_longest_of_them() {
2304        let mut types = Types::new();
2305        let rows = measured(&mut types, 0);
2306        let double = types.float(FloatKind::Double);
2307        let laid_out = lay_out(&types, RecordKind::Union, &[member(rows), member(double)]);
2308
2309        assert_eq!(laid_out.layout, Layout::new(0, 8));
2310        let variable = laid_out.variable.expect("a union with a member of no fixed size");
2311        // Every member of a union starts where the union does, so none of them has an offset the
2312        // program has to work out.
2313        assert!(variable.offsets.iter().all(Option::is_none));
2314        for count in 0..6u64 {
2315            let sizes = [4 * count, 8];
2316            let want = (4 * count).max(8).next_multiple_of(8);
2317            assert_eq!(work_out(&variable.size, &sizes), want);
2318        }
2319    }
2320
2321    #[test]
2322    fn packed_takes_the_rounding_out_of_a_record_the_program_measures() {
2323        let mut types = Types::new();
2324        let char_ty = types.int(IntKind::Char);
2325        let int = types.int(IntKind::Int);
2326        let rows = measured(&mut types, 0);
2327        let fields = [member(char_ty), member(rows), member(int)];
2328        let options = RecordOptions { packed: true, ..RecordOptions::default() };
2329        let laid_out = layout_record(&types, RecordKind::Struct, &fields, &options, &linux())
2330            .expect("a packed record with a member of no fixed size");
2331
2332        assert_eq!(laid_out.layout, Layout::new(0, 1));
2333        assert_eq!(laid_out.fields[2].align, 1);
2334        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2335        let after = variable.offsets[2].as_ref().expect("an offset the program works out");
2336        for count in 0..6u64 {
2337            let sizes = [1, 4 * count, 4];
2338            assert_eq!(work_out(after, &sizes), 1 + 4 * count);
2339            assert_eq!(work_out(&variable.size, &sizes), 1 + 4 * count + 4);
2340        }
2341    }
2342
2343    #[test]
2344    fn bit_fields_after_a_member_of_no_fixed_size_are_placed_one_after_another() {
2345        let mut interner = Interner::new();
2346        let mut types = Types::new();
2347        let int = types.int(IntKind::Int);
2348        let char_ty = types.int(IntKind::Char);
2349        let rows = measured(&mut types, 0);
2350        let fields = [
2351            member(rows),
2352            bits(&mut interner, "b", int, 3),
2353            bits(&mut interner, "c", int, 30),
2354            member(char_ty),
2355        ];
2356        let laid_out = lay_out(&types, RecordKind::Struct, &fields);
2357
2358        // `c` would straddle its `int` if the offset were a number, and gcc 16 puts it at bit
2359        // three all the same, because it only asks that question of an offset it knows. So the
2360        // `char` is five bytes past the array and the record is `4 * n + 8` long.
2361        assert_eq!((laid_out.fields[2].offset, laid_out.fields[2].bit), (0, 3));
2362        let variable = laid_out.variable.expect("a record with a member of no fixed size");
2363        let after = variable.offsets[3].as_ref().expect("an offset the program works out");
2364        for count in 0..6u64 {
2365            let sizes = [4 * count, 4, 4, 1];
2366            assert_eq!(work_out(after, &sizes), 4 * count + 5);
2367            assert_eq!(work_out(&variable.size, &sizes), 4 * count + 8);
2368        }
2369    }
2370
2371    #[test]
2372    fn a_zero_width_bit_field_that_needs_more_alignment_than_is_known_is_turned_down() {
2373        let mut types = Types::new();
2374        let int = types.int(IntKind::Int);
2375        let char_ty = types.int(IntKind::Char);
2376        let letters = types.array(char_ty, ArrayLen::Variable(VlaId(0)));
2377        let fields = [member(letters), unnamed_bits(int, 0)];
2378        let options = RecordOptions::default();
2379        let failed = layout_record(&types, RecordKind::Struct, &fields, &options, &linux());
2380
2381        // A `char` array may end on any byte, so which four byte boundary `int : 0` rounds to is a
2382        // question about an address the program has not worked out yet. The layout says so
2383        // rather than putting the member somewhere plausible.
2384        assert_eq!(failed, Err(RecordError::VariableBitField { index: 1 }));
2385    }
2386}