Skip to main content

rucc_types/
lib.rs

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