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