From db6bfda107d1603cdfdf9629825177f0aafdf297 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 27 Apr 2026 16:26:47 +0100 Subject: [PATCH 1/5] Add union tests --- tests/unit/union_addrof_external.c | 49 +++++++++++++++ tests/unit/union_basic.c | 18 ++++++ tests/unit/union_cross_arm_cast.c | 46 ++++++++++++++ tests/unit/union_field_alignment.c | 23 +++++++ tests/unit/union_flex_array_member.c | 35 +++++++++++ tests/unit/union_memset_memcpy.c | 55 ++++++++++++++++ tests/unit/union_nested.c | 45 ++++++++++++++ tests/unit/union_pointer_pun_address.c | 26 ++++++++ tests/unit/union_pointer_pun_writethrough.c | 17 +++++ tests/unit/union_struct_dual_use.c | 35 +++++++++++ tests/unit/union_tagged_many_arms.c | 52 ++++++++++++++++ tests/unit/union_tagged_simple.c | 35 +++++++++++ tests/unit/union_tagged_struct_arms.c | 69 +++++++++++++++++++++ tests/unit/union_void_ptr_sized_deref.c | 59 ++++++++++++++++++ 14 files changed, 564 insertions(+) create mode 100644 tests/unit/union_addrof_external.c create mode 100644 tests/unit/union_basic.c create mode 100644 tests/unit/union_cross_arm_cast.c create mode 100644 tests/unit/union_field_alignment.c create mode 100644 tests/unit/union_flex_array_member.c create mode 100644 tests/unit/union_memset_memcpy.c create mode 100644 tests/unit/union_nested.c create mode 100644 tests/unit/union_pointer_pun_address.c create mode 100644 tests/unit/union_pointer_pun_writethrough.c create mode 100644 tests/unit/union_struct_dual_use.c create mode 100644 tests/unit/union_tagged_many_arms.c create mode 100644 tests/unit/union_tagged_simple.c create mode 100644 tests/unit/union_tagged_struct_arms.c create mode 100644 tests/unit/union_void_ptr_sized_deref.c diff --git a/tests/unit/union_addrof_external.c b/tests/unit/union_addrof_external.c new file mode 100644 index 00000000..fff91224 --- /dev/null +++ b/tests/unit/union_addrof_external.c @@ -0,0 +1,49 @@ +// translation-fail +#include +#include +#include +#include + +struct header { + uint16_t tag; + uint16_t port; + uint32_t addr; + char pad[8]; +}; + +struct Storage { + union { + struct header h; + char raw[128]; + } buffer; +}; + +static void external_writer(void *out, size_t cap) { + unsigned char src[16] = {0}; + src[0] = 2; + src[1] = 0; + src[2] = 0x00; + src[3] = 0x50; + src[4] = 0x7F; + src[5] = 0x00; + src[6] = 0x00; + src[7] = 0x01; + size_t n = sizeof(src) < cap ? sizeof(src) : cap; + memcpy(out, src, n); +} + +int main(void) { + struct Storage s; + memset(&s, 0, sizeof(s)); + + external_writer((void *)&s.buffer, sizeof(s.buffer)); + + assert(s.buffer.h.tag == 2); + assert(((unsigned char *)&s.buffer.h.port)[0] == 0x00); + assert(((unsigned char *)&s.buffer.h.port)[1] == 0x50); + + assert(s.buffer.raw[0] == 2); + assert((unsigned char)s.buffer.raw[3] == 0x50); + + return 0; +} diff --git a/tests/unit/union_basic.c b/tests/unit/union_basic.c new file mode 100644 index 00000000..5d26a336 --- /dev/null +++ b/tests/unit/union_basic.c @@ -0,0 +1,18 @@ +#include + +union basic { + int i; + float f; +}; + +int main(void) { + union basic u; + + u.i = 42; + assert(u.i == 42); + + u.f = 3.14f; + assert(u.f == 3.14f); + + return 0; +} diff --git a/tests/unit/union_cross_arm_cast.c b/tests/unit/union_cross_arm_cast.c new file mode 100644 index 00000000..ec3f5f8c --- /dev/null +++ b/tests/unit/union_cross_arm_cast.c @@ -0,0 +1,46 @@ +// translation-fail +#include +#include +#include +#include + +struct header_a { + uint16_t tag; + char data[14]; +}; + +struct header_b { + uint16_t tag; + uint16_t port; + uint32_t flags; + uint8_t body[16]; + uint32_t extra; +}; + +struct Storage { + unsigned int len; + union { + struct header_a a; + struct header_b b; + char raw[64]; + } u; +}; + +int main(void) { + struct Storage s; + memset(&s, 0, sizeof(s)); + + s.u.a.tag = 10; + s.len = sizeof(struct header_b); + + ((struct header_b *)(void *)&s.u.a)->extra = 0xDEADBEEF; + + assert(s.u.b.extra == 0xDEADBEEF); + assert(s.u.b.tag == 10); + + s.u.b.port = 0x1F90; + assert(((unsigned char *)&s.u.raw)[2] == 0x90); + assert(((unsigned char *)&s.u.raw)[3] == 0x1F); + + return 0; +} diff --git a/tests/unit/union_field_alignment.c b/tests/unit/union_field_alignment.c new file mode 100644 index 00000000..ca03bd29 --- /dev/null +++ b/tests/unit/union_field_alignment.c @@ -0,0 +1,23 @@ +// translation-fail +#include +#include +#include + +struct chunk { + struct chunk *next; + union { + uint8_t data[1]; + void *dummy; + } x; +}; + +int main(void) { + struct chunk c; + c.next = 0; + c.x.data[0] = 0xAB; + + assert(c.x.data[0] == 0xAB); + assert(sizeof(c.x) >= sizeof(void *)); + assert(((uintptr_t)&c.x % _Alignof(void *)) == 0); + return 0; +} diff --git a/tests/unit/union_flex_array_member.c b/tests/unit/union_flex_array_member.c new file mode 100644 index 00000000..ff3bfffa --- /dev/null +++ b/tests/unit/union_flex_array_member.c @@ -0,0 +1,35 @@ +// translation-fail +#include +#include +#include +#include +#include + +struct chunk { + size_t dlen; + union { + uint8_t data[1]; + void *dummy; + } x; +}; + +int main(void) { + size_t chunk_size = 32; + struct chunk *c = (struct chunk *)malloc(sizeof(struct chunk) + chunk_size); + c->dlen = chunk_size; + + for (size_t i = 0; i < chunk_size; i++) { + c->x.data[i] = (uint8_t)(i & 0xFF); + } + for (size_t i = 0; i < chunk_size; i++) { + assert(c->x.data[i] == (uint8_t)(i & 0xFF)); + } + + uint8_t *p = &c->x.data[10]; + assert(*p == 10); + *p = 0xAA; + assert(c->x.data[10] == 0xAA); + + free(c); + return 0; +} diff --git a/tests/unit/union_memset_memcpy.c b/tests/unit/union_memset_memcpy.c new file mode 100644 index 00000000..644ec67b --- /dev/null +++ b/tests/unit/union_memset_memcpy.c @@ -0,0 +1,55 @@ +// translation-fail +#include +#include +#include +#include + +struct header_a { + uint16_t tag; + char data[14]; +}; + +struct header_b { + uint16_t tag; + uint16_t port; + uint32_t addr; + char zero[8]; +}; + +struct Storage { + union { + struct header_a a; + struct header_b b; + char raw[256]; + } buffer; +}; + +int main(void) { + struct Storage s; + + memset(&s, 0, sizeof(s)); + assert(s.buffer.a.tag == 0); + assert(s.buffer.b.port == 0); + assert(s.buffer.raw[0] == 0); + assert(s.buffer.raw[255] == 0); + + unsigned char wire[16] = {0}; + wire[0] = 2; + wire[2] = 0x50; + wire[3] = 0x00; + wire[4] = 0x7F; + wire[5] = 0x00; + wire[6] = 0x00; + wire[7] = 0x01; + size_t len = 16; + assert(len <= sizeof(s.buffer.raw)); + memcpy(&s.buffer.raw, wire, len); + + assert(s.buffer.b.tag == 2); + assert(((unsigned char *)&s.buffer.b.port)[0] == 0x50); + + memset(&s, 0, sizeof(s)); + assert(s.buffer.b.tag == 0); + + return 0; +} diff --git a/tests/unit/union_nested.c b/tests/unit/union_nested.c new file mode 100644 index 00000000..3ee3b2b0 --- /dev/null +++ b/tests/unit/union_nested.c @@ -0,0 +1,45 @@ +// translation-fail +#include +#include +#include + +struct header { + uint16_t tag; + char data[14]; +}; + +struct inner { + union { + struct header h; + char raw[128]; + } buffer; +}; + +struct Outer { + int kind; + int subtype; + int proto; + unsigned int len; + union { + struct header h; + struct inner nested; + } body; +}; + +int main(void) { + struct Outer ex; + memset(&ex, 0, sizeof(ex)); + + ex.kind = 2; + ex.subtype = 1; + ex.proto = 6; + ex.len = sizeof(struct header); + ex.body.h.tag = 2; + ex.body.h.data[0] = 'X'; + + assert(ex.body.h.tag == 2); + assert(ex.body.h.data[0] == 'X'); + + assert(ex.body.nested.buffer.h.tag == 2); + return 0; +} diff --git a/tests/unit/union_pointer_pun_address.c b/tests/unit/union_pointer_pun_address.c new file mode 100644 index 00000000..a5739639 --- /dev/null +++ b/tests/unit/union_pointer_pun_address.c @@ -0,0 +1,26 @@ +// translation-fail +#include + +struct node_a { + int n; +}; + +struct node_b { + void *data; + struct node_b *next; +}; + +int main(void) { + struct node_a a = {123}; + + union { + struct node_a *to_a; + struct node_b *to_b; + } ptr; + + ptr.to_a = &a; + struct node_b *out = ptr.to_b; + + assert((void *)out == (void *)&a); + return 0; +} diff --git a/tests/unit/union_pointer_pun_writethrough.c b/tests/unit/union_pointer_pun_writethrough.c new file mode 100644 index 00000000..13a71ebe --- /dev/null +++ b/tests/unit/union_pointer_pun_writethrough.c @@ -0,0 +1,17 @@ +// translation-fail +#include + +int main(void) { + long x = -1; + + union { + unsigned long *to_ulong; + long *to_long; + } lptr; + + lptr.to_long = &x; + *lptr.to_ulong = 42UL; + + assert(x == 42); + return 0; +} diff --git a/tests/unit/union_struct_dual_use.c b/tests/unit/union_struct_dual_use.c new file mode 100644 index 00000000..ef128e6c --- /dev/null +++ b/tests/unit/union_struct_dual_use.c @@ -0,0 +1,35 @@ +// translation-fail +#include +#include + +struct Inner { + int a; + int b; +}; + +static int sum_inner(struct Inner *i) { return i->a + i->b; } + +struct Outer { + union { + struct Inner inner; + char raw[16]; + } u; +}; + +int main(void) { + struct Inner standalone; + standalone.a = 3; + standalone.b = 4; + assert(sum_inner(&standalone) == 7); + + struct Outer outer; + memset(&outer, 0, sizeof(outer)); + outer.u.inner.a = 3; + outer.u.inner.b = 4; + assert(sum_inner(&outer.u.inner) == 7); + + assert((unsigned char)outer.u.raw[0] == 3); + assert((unsigned char)outer.u.raw[4] == 4); + + return 0; +} diff --git a/tests/unit/union_tagged_many_arms.c b/tests/unit/union_tagged_many_arms.c new file mode 100644 index 00000000..1c34c2e3 --- /dev/null +++ b/tests/unit/union_tagged_many_arms.c @@ -0,0 +1,52 @@ +// translation-fail +#include +#include + +typedef enum { + K_INT, + K_UINT, + K_STR, + K_DBL, + K_PTR, +} Kind; + +struct Arg { + Kind kind; + union { + const char *str; + void *ptr; + int64_t nums; + uint64_t numu; + double dnum; + } val; +}; + +int main(void) { + struct Arg a; + a.kind = K_INT; + a.val.nums = -7; + assert(a.val.nums == -7); + + struct Arg b; + b.kind = K_UINT; + b.val.numu = 0xDEADBEEFu; + assert(b.val.numu == 0xDEADBEEFu); + + struct Arg c; + c.kind = K_STR; + c.val.str = "hello"; + assert(c.val.str[0] == 'h'); + + struct Arg d; + d.kind = K_DBL; + d.val.dnum = 1.5; + assert(d.val.dnum == 1.5); + + int x = 0; + struct Arg e; + e.kind = K_PTR; + e.val.ptr = &x; + assert(e.val.ptr == &x); + + return 0; +} diff --git a/tests/unit/union_tagged_simple.c b/tests/unit/union_tagged_simple.c new file mode 100644 index 00000000..09406893 --- /dev/null +++ b/tests/unit/union_tagged_simple.c @@ -0,0 +1,35 @@ +// translation-fail +#include + +typedef enum { + KIND_NONE, + KIND_DONE, +} Kind; + +struct Event { + Kind kind; + void *handle; + union { + void *obj; + int code; + } payload; +}; + +int main(void) { + int dummy = 0; + + struct Event m1; + m1.kind = KIND_DONE; + m1.handle = &dummy; + m1.payload.code = 42; + assert(m1.kind == KIND_DONE); + assert(m1.payload.code == 42); + + struct Event m2; + m2.kind = KIND_NONE; + m2.handle = &dummy; + m2.payload.obj = &dummy; + assert(m2.payload.obj == &dummy); + + return 0; +} diff --git a/tests/unit/union_tagged_struct_arms.c b/tests/unit/union_tagged_struct_arms.c new file mode 100644 index 00000000..4afad172 --- /dev/null +++ b/tests/unit/union_tagged_struct_arms.c @@ -0,0 +1,69 @@ +// translation-fail +#include +#include + +typedef enum { + T_SET = 1, + T_RANGE_ASCII, + T_RANGE_NUM, +} VariantKind; + +struct Pattern { + VariantKind kind; + int index; + union { + struct { + char **elem; + int64_t size; + int64_t idx; + } set; + struct { + int min; + int max; + int letter; + unsigned char step; + } ascii; + struct { + int64_t min; + int64_t max; + int64_t idx; + int64_t step; + int npad; + } num; + } v; +}; + +int main(void) { + static char *items[] = {"a", "b", "c"}; + + struct Pattern p_set; + p_set.kind = T_SET; + p_set.index = 0; + p_set.v.set.elem = items; + p_set.v.set.size = 3; + p_set.v.set.idx = 1; + assert(p_set.v.set.size == 3); + assert(p_set.v.set.elem[1][0] == 'b'); + + struct Pattern p_ascii; + p_ascii.kind = T_RANGE_ASCII; + p_ascii.index = 1; + p_ascii.v.ascii.min = 'a'; + p_ascii.v.ascii.max = 'z'; + p_ascii.v.ascii.letter = 'm'; + p_ascii.v.ascii.step = 1; + assert(p_ascii.v.ascii.max - p_ascii.v.ascii.min == 25); + + struct Pattern p_num; + p_num.kind = T_RANGE_NUM; + p_num.index = 2; + p_num.v.num.min = 1; + p_num.v.num.max = 100; + p_num.v.num.idx = 1; + p_num.v.num.step = 1; + p_num.v.num.npad = 3; + assert(p_num.v.num.max == 100); + assert(p_num.v.num.npad == 3); + + return 0; +} diff --git a/tests/unit/union_void_ptr_sized_deref.c b/tests/unit/union_void_ptr_sized_deref.c new file mode 100644 index 00000000..def48e26 --- /dev/null +++ b/tests/unit/union_void_ptr_sized_deref.c @@ -0,0 +1,59 @@ +// translation-fail +#include +#include +#include + +typedef enum { + W_INT64, + W_INT32, + W_INT16, +} IntWidth; + +struct Arg { + IntWidth width; + union { + const char *str; + void *ptr; + int64_t nums; + double dnum; + } val; +}; + +static void store_count(struct Arg *in, int64_t count) { + switch (in->width) { + case W_INT64: + *(int64_t *)in->val.ptr = count; + break; + case W_INT32: + *(int32_t *)in->val.ptr = (int32_t)count; + break; + case W_INT16: + *(int16_t *)in->val.ptr = (int16_t)count; + break; + } +} + +int main(void) { + int64_t buf64 = 0; + int32_t buf32 = 0; + int16_t buf16 = 0; + + struct Arg in; + + in.width = W_INT64; + in.val.ptr = &buf64; + store_count(&in, 0x1122334455667788LL); + assert(buf64 == 0x1122334455667788LL); + + in.width = W_INT32; + in.val.ptr = &buf32; + store_count(&in, 0x12345678); + assert(buf32 == 0x12345678); + + in.width = W_INT16; + in.val.ptr = &buf16; + store_count(&in, 0x1234); + assert(buf16 == 0x1234); + + return 0; +} From dd535c67e115042615d4fc97f6cec4909006d0c7 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 27 Apr 2026 16:29:17 +0100 Subject: [PATCH 2/5] Add expected file for union_basic --- tests/unit/out/refcount/union_basic.rs | 45 ++++++++++++++++++++++++++ tests/unit/out/unsafe/union_basic.rs | 30 +++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/unit/out/refcount/union_basic.rs create mode 100644 tests/unit/out/unsafe/union_basic.rs diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs new file mode 100644 index 00000000..0aab690e --- /dev/null +++ b/tests/unit/out/refcount/union_basic.rs @@ -0,0 +1,45 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub struct basic { + __buf: Rc>>, + pub i: Value, + pub f: Value, +} +impl Default for basic { + fn default() -> Self { + let __buf = Rc::new(RefCell::new(vec![0u8; 4])); + Self { + __buf: __buf.clone(), + i: Value::new_reinterpreted( + Rc::new(SliceOriginalAlloc { + weak: Rc::downgrade(&__buf), + }), + 0, + ), + f: Value::new_reinterpreted( + Rc::new(SliceOriginalAlloc { + weak: Rc::downgrade(&__buf), + }), + 0, + ), + } + } +} +impl ByteRepr for basic {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let u: Value = >::default(); + (*u.borrow()).i.write(42); + assert!(((*u.borrow()).i.read() == 42)); + (*u.borrow()).f.write(3.140000105E+0); + assert!(((*u.borrow()).f.read() == 3.140000105E+0)); + return 0; +} diff --git a/tests/unit/out/unsafe/union_basic.rs b/tests/unit/out/unsafe/union_basic.rs new file mode 100644 index 00000000..00f13530 --- /dev/null +++ b/tests/unit/out/unsafe/union_basic.rs @@ -0,0 +1,30 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub union basic { + pub i: i32, + pub f: f32, +} +impl Default for basic { + fn default() -> Self { + unsafe { ::std::mem::MaybeUninit::zeroed().assume_init() } + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut u: basic = ::default(); + u.i = 42; + assert!(((u.i) == (42))); + u.f = 3.140000105E+0; + assert!(((u.f) == (3.140000105E+0))); + return 0; +} From ad249f1ec8f2ffa7fcaf77d8ac6cef617cdaa2f7 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 27 Apr 2026 16:32:48 +0100 Subject: [PATCH 3/5] Add correct generated output for union_basic --- tests/unit/out/refcount/union_basic.rs | 30 +++++--------------------- tests/unit/out/unsafe/union_basic.rs | 8 ++----- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs index 0aab690e..c7255a39 100644 --- a/tests/unit/out/refcount/union_basic.rs +++ b/tests/unit/out/refcount/union_basic.rs @@ -6,40 +6,20 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +#[derive(Default)] pub struct basic { - __buf: Rc>>, pub i: Value, pub f: Value, } -impl Default for basic { - fn default() -> Self { - let __buf = Rc::new(RefCell::new(vec![0u8; 4])); - Self { - __buf: __buf.clone(), - i: Value::new_reinterpreted( - Rc::new(SliceOriginalAlloc { - weak: Rc::downgrade(&__buf), - }), - 0, - ), - f: Value::new_reinterpreted( - Rc::new(SliceOriginalAlloc { - weak: Rc::downgrade(&__buf), - }), - 0, - ), - } - } -} impl ByteRepr for basic {} pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { let u: Value = >::default(); - (*u.borrow()).i.write(42); - assert!(((*u.borrow()).i.read() == 42)); - (*u.borrow()).f.write(3.140000105E+0); - assert!(((*u.borrow()).f.read() == 3.140000105E+0)); + (*(*u.borrow()).i.borrow_mut()) = 42; + assert!(((*(*u.borrow()).i.borrow()) == 42)); + (*(*u.borrow()).f.borrow_mut()) = 3.140000105E+0; + assert!(((*(*u.borrow()).f.borrow()) == 3.140000105E+0)); return 0; } diff --git a/tests/unit/out/unsafe/union_basic.rs b/tests/unit/out/unsafe/union_basic.rs index 00f13530..1ddfcb9c 100644 --- a/tests/unit/out/unsafe/union_basic.rs +++ b/tests/unit/out/unsafe/union_basic.rs @@ -6,15 +6,11 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -pub union basic { +#[derive(Copy, Clone, Default)] +pub struct basic { pub i: i32, pub f: f32, } -impl Default for basic { - fn default() -> Self { - unsafe { ::std::mem::MaybeUninit::zeroed().assume_init() } - } -} pub fn main() { unsafe { std::process::exit(main_0() as i32); From b90dde3cd72258f0e428b00da7e233964bf4655a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 27 Apr 2026 16:43:39 +0100 Subject: [PATCH 4/5] Rename identifiers --- tests/unit/union_addrof_external.c | 32 ++++---- tests/unit/union_cross_arm_cast.c | 44 +++++----- tests/unit/union_field_alignment.c | 20 ++--- tests/unit/union_flex_array_member.c | 28 +++---- tests/unit/union_memset_memcpy.c | 68 ++++++++-------- tests/unit/union_nested.c | 32 ++++---- tests/unit/union_pointer_pun_writethrough.c | 10 +-- tests/unit/union_tagged_many_arms.c | 76 ++++++++--------- tests/unit/union_tagged_struct_arms.c | 90 ++++++++++----------- tests/unit/union_void_ptr_sized_deref.c | 58 ++++++------- 10 files changed, 229 insertions(+), 229 deletions(-) diff --git a/tests/unit/union_addrof_external.c b/tests/unit/union_addrof_external.c index fff91224..2a7fab68 100644 --- a/tests/unit/union_addrof_external.c +++ b/tests/unit/union_addrof_external.c @@ -4,21 +4,21 @@ #include #include -struct header { - uint16_t tag; - uint16_t port; - uint32_t addr; +struct record { + uint16_t code; + uint16_t lo; + uint32_t hi; char pad[8]; }; -struct Storage { +struct Container { union { - struct header h; + struct record h; char raw[128]; - } buffer; + } view; }; -static void external_writer(void *out, size_t cap) { +static void fill(void *out, size_t cap) { unsigned char src[16] = {0}; src[0] = 2; src[1] = 0; @@ -33,17 +33,17 @@ static void external_writer(void *out, size_t cap) { } int main(void) { - struct Storage s; - memset(&s, 0, sizeof(s)); + struct Container c; + memset(&c, 0, sizeof(c)); - external_writer((void *)&s.buffer, sizeof(s.buffer)); + fill((void *)&c.view, sizeof(c.view)); - assert(s.buffer.h.tag == 2); - assert(((unsigned char *)&s.buffer.h.port)[0] == 0x00); - assert(((unsigned char *)&s.buffer.h.port)[1] == 0x50); + assert(c.view.h.code == 2); + assert(((unsigned char *)&c.view.h.lo)[0] == 0x00); + assert(((unsigned char *)&c.view.h.lo)[1] == 0x50); - assert(s.buffer.raw[0] == 2); - assert((unsigned char)s.buffer.raw[3] == 0x50); + assert(c.view.raw[0] == 2); + assert((unsigned char)c.view.raw[3] == 0x50); return 0; } diff --git a/tests/unit/union_cross_arm_cast.c b/tests/unit/union_cross_arm_cast.c index ec3f5f8c..0dc5d05c 100644 --- a/tests/unit/union_cross_arm_cast.c +++ b/tests/unit/union_cross_arm_cast.c @@ -4,43 +4,43 @@ #include #include -struct header_a { - uint16_t tag; - char data[14]; +struct shape_a { + uint16_t code; + char pad[14]; }; -struct header_b { - uint16_t tag; - uint16_t port; - uint32_t flags; - uint8_t body[16]; - uint32_t extra; +struct shape_b { + uint16_t code; + uint16_t lo; + uint32_t mid; + uint8_t fill[16]; + uint32_t tail; }; -struct Storage { +struct Container { unsigned int len; union { - struct header_a a; - struct header_b b; + struct shape_a a; + struct shape_b b; char raw[64]; } u; }; int main(void) { - struct Storage s; - memset(&s, 0, sizeof(s)); + struct Container c; + memset(&c, 0, sizeof(c)); - s.u.a.tag = 10; - s.len = sizeof(struct header_b); + c.u.a.code = 10; + c.len = sizeof(struct shape_b); - ((struct header_b *)(void *)&s.u.a)->extra = 0xDEADBEEF; + ((struct shape_b *)(void *)&c.u.a)->tail = 0xDEADBEEF; - assert(s.u.b.extra == 0xDEADBEEF); - assert(s.u.b.tag == 10); + assert(c.u.b.tail == 0xDEADBEEF); + assert(c.u.b.code == 10); - s.u.b.port = 0x1F90; - assert(((unsigned char *)&s.u.raw)[2] == 0x90); - assert(((unsigned char *)&s.u.raw)[3] == 0x1F); + c.u.b.lo = 0x1F90; + assert(((unsigned char *)&c.u.raw)[2] == 0x90); + assert(((unsigned char *)&c.u.raw)[3] == 0x1F); return 0; } diff --git a/tests/unit/union_field_alignment.c b/tests/unit/union_field_alignment.c index ca03bd29..70802d57 100644 --- a/tests/unit/union_field_alignment.c +++ b/tests/unit/union_field_alignment.c @@ -3,21 +3,21 @@ #include #include -struct chunk { - struct chunk *next; +struct node { + struct node *next; union { - uint8_t data[1]; - void *dummy; + uint8_t bytes[1]; + void *aligner; } x; }; int main(void) { - struct chunk c; - c.next = 0; - c.x.data[0] = 0xAB; + struct node n; + n.next = 0; + n.x.bytes[0] = 0xAB; - assert(c.x.data[0] == 0xAB); - assert(sizeof(c.x) >= sizeof(void *)); - assert(((uintptr_t)&c.x % _Alignof(void *)) == 0); + assert(n.x.bytes[0] == 0xAB); + assert(sizeof(n.x) >= sizeof(void *)); + assert(((uintptr_t)&n.x % _Alignof(void *)) == 0); return 0; } diff --git a/tests/unit/union_flex_array_member.c b/tests/unit/union_flex_array_member.c index ff3bfffa..e8efd7c9 100644 --- a/tests/unit/union_flex_array_member.c +++ b/tests/unit/union_flex_array_member.c @@ -5,31 +5,31 @@ #include #include -struct chunk { - size_t dlen; +struct node { + size_t len; union { - uint8_t data[1]; - void *dummy; + uint8_t bytes[1]; + void *aligner; } x; }; int main(void) { - size_t chunk_size = 32; - struct chunk *c = (struct chunk *)malloc(sizeof(struct chunk) + chunk_size); - c->dlen = chunk_size; + size_t tail_size = 32; + struct node *n = (struct node *)malloc(sizeof(struct node) + tail_size); + n->len = tail_size; - for (size_t i = 0; i < chunk_size; i++) { - c->x.data[i] = (uint8_t)(i & 0xFF); + for (size_t i = 0; i < tail_size; i++) { + n->x.bytes[i] = (uint8_t)(i & 0xFF); } - for (size_t i = 0; i < chunk_size; i++) { - assert(c->x.data[i] == (uint8_t)(i & 0xFF)); + for (size_t i = 0; i < tail_size; i++) { + assert(n->x.bytes[i] == (uint8_t)(i & 0xFF)); } - uint8_t *p = &c->x.data[10]; + uint8_t *p = &n->x.bytes[10]; assert(*p == 10); *p = 0xAA; - assert(c->x.data[10] == 0xAA); + assert(n->x.bytes[10] == 0xAA); - free(c); + free(n); return 0; } diff --git a/tests/unit/union_memset_memcpy.c b/tests/unit/union_memset_memcpy.c index 644ec67b..75c1ff61 100644 --- a/tests/unit/union_memset_memcpy.c +++ b/tests/unit/union_memset_memcpy.c @@ -4,52 +4,52 @@ #include #include -struct header_a { - uint16_t tag; - char data[14]; +struct shape_a { + uint16_t code; + char pad[14]; }; -struct header_b { - uint16_t tag; - uint16_t port; - uint32_t addr; - char zero[8]; +struct shape_b { + uint16_t code; + uint16_t lo; + uint32_t hi; + char fill[8]; }; -struct Storage { +struct Container { union { - struct header_a a; - struct header_b b; + struct shape_a a; + struct shape_b b; char raw[256]; - } buffer; + } view; }; int main(void) { - struct Storage s; - - memset(&s, 0, sizeof(s)); - assert(s.buffer.a.tag == 0); - assert(s.buffer.b.port == 0); - assert(s.buffer.raw[0] == 0); - assert(s.buffer.raw[255] == 0); - - unsigned char wire[16] = {0}; - wire[0] = 2; - wire[2] = 0x50; - wire[3] = 0x00; - wire[4] = 0x7F; - wire[5] = 0x00; - wire[6] = 0x00; - wire[7] = 0x01; + struct Container c; + + memset(&c, 0, sizeof(c)); + assert(c.view.a.code == 0); + assert(c.view.b.lo == 0); + assert(c.view.raw[0] == 0); + assert(c.view.raw[255] == 0); + + unsigned char src[16] = {0}; + src[0] = 2; + src[2] = 0x50; + src[3] = 0x00; + src[4] = 0x7F; + src[5] = 0x00; + src[6] = 0x00; + src[7] = 0x01; size_t len = 16; - assert(len <= sizeof(s.buffer.raw)); - memcpy(&s.buffer.raw, wire, len); + assert(len <= sizeof(c.view.raw)); + memcpy(&c.view.raw, src, len); - assert(s.buffer.b.tag == 2); - assert(((unsigned char *)&s.buffer.b.port)[0] == 0x50); + assert(c.view.b.code == 2); + assert(((unsigned char *)&c.view.b.lo)[0] == 0x50); - memset(&s, 0, sizeof(s)); - assert(s.buffer.b.tag == 0); + memset(&c, 0, sizeof(c)); + assert(c.view.b.code == 0); return 0; } diff --git a/tests/unit/union_nested.c b/tests/unit/union_nested.c index 3ee3b2b0..de3fa625 100644 --- a/tests/unit/union_nested.c +++ b/tests/unit/union_nested.c @@ -3,25 +3,25 @@ #include #include -struct header { - uint16_t tag; - char data[14]; +struct record { + uint16_t code; + char pad[14]; }; struct inner { union { - struct header h; + struct record h; char raw[128]; - } buffer; + } view; }; struct Outer { int kind; - int subtype; - int proto; + int level; + int variant; unsigned int len; union { - struct header h; + struct record h; struct inner nested; } body; }; @@ -31,15 +31,15 @@ int main(void) { memset(&ex, 0, sizeof(ex)); ex.kind = 2; - ex.subtype = 1; - ex.proto = 6; - ex.len = sizeof(struct header); - ex.body.h.tag = 2; - ex.body.h.data[0] = 'X'; + ex.level = 1; + ex.variant = 6; + ex.len = sizeof(struct record); + ex.body.h.code = 2; + ex.body.h.pad[0] = 'X'; - assert(ex.body.h.tag == 2); - assert(ex.body.h.data[0] == 'X'); + assert(ex.body.h.code == 2); + assert(ex.body.h.pad[0] == 'X'); - assert(ex.body.nested.buffer.h.tag == 2); + assert(ex.body.nested.view.h.code == 2); return 0; } diff --git a/tests/unit/union_pointer_pun_writethrough.c b/tests/unit/union_pointer_pun_writethrough.c index 13a71ebe..203ef9d1 100644 --- a/tests/unit/union_pointer_pun_writethrough.c +++ b/tests/unit/union_pointer_pun_writethrough.c @@ -5,12 +5,12 @@ int main(void) { long x = -1; union { - unsigned long *to_ulong; - long *to_long; - } lptr; + unsigned long *as_unsigned; + long *as_signed; + } pp; - lptr.to_long = &x; - *lptr.to_ulong = 42UL; + pp.as_signed = &x; + *pp.as_unsigned = 42UL; assert(x == 42); return 0; diff --git a/tests/unit/union_tagged_many_arms.c b/tests/unit/union_tagged_many_arms.c index 1c34c2e3..42146906 100644 --- a/tests/unit/union_tagged_many_arms.c +++ b/tests/unit/union_tagged_many_arms.c @@ -3,50 +3,50 @@ #include typedef enum { - K_INT, - K_UINT, - K_STR, - K_DBL, - K_PTR, -} Kind; - -struct Arg { - Kind kind; + T_NUM_S, + T_NUM_U, + T_TEXT, + T_FLOAT, + T_REF, +} Tag; + +struct Slot { + Tag tag; union { - const char *str; - void *ptr; - int64_t nums; - uint64_t numu; - double dnum; - } val; + const char *text; + void *handle; + int64_t signed_n; + uint64_t unsigned_n; + double f; + } payload; }; int main(void) { - struct Arg a; - a.kind = K_INT; - a.val.nums = -7; - assert(a.val.nums == -7); - - struct Arg b; - b.kind = K_UINT; - b.val.numu = 0xDEADBEEFu; - assert(b.val.numu == 0xDEADBEEFu); - - struct Arg c; - c.kind = K_STR; - c.val.str = "hello"; - assert(c.val.str[0] == 'h'); - - struct Arg d; - d.kind = K_DBL; - d.val.dnum = 1.5; - assert(d.val.dnum == 1.5); + struct Slot a; + a.tag = T_NUM_S; + a.payload.signed_n = -7; + assert(a.payload.signed_n == -7); + + struct Slot b; + b.tag = T_NUM_U; + b.payload.unsigned_n = 0xDEADBEEFu; + assert(b.payload.unsigned_n == 0xDEADBEEFu); + + struct Slot c; + c.tag = T_TEXT; + c.payload.text = "hello"; + assert(c.payload.text[0] == 'h'); + + struct Slot d; + d.tag = T_FLOAT; + d.payload.f = 1.5; + assert(d.payload.f == 1.5); int x = 0; - struct Arg e; - e.kind = K_PTR; - e.val.ptr = &x; - assert(e.val.ptr == &x); + struct Slot e; + e.tag = T_REF; + e.payload.handle = &x; + assert(e.payload.handle == &x); return 0; } diff --git a/tests/unit/union_tagged_struct_arms.c b/tests/unit/union_tagged_struct_arms.c index 4afad172..bc93bcac 100644 --- a/tests/unit/union_tagged_struct_arms.c +++ b/tests/unit/union_tagged_struct_arms.c @@ -3,67 +3,67 @@ #include typedef enum { - T_SET = 1, - T_RANGE_ASCII, - T_RANGE_NUM, -} VariantKind; + C_LIST = 1, + C_LETTERS, + C_INTEGERS, +} Choice; -struct Pattern { - VariantKind kind; +struct Branch { + Choice choice; int index; union { struct { - char **elem; - int64_t size; - int64_t idx; - } set; + char **items; + int64_t count; + int64_t cursor; + } list; struct { - int min; - int max; - int letter; + int lo; + int hi; + int curr; unsigned char step; - } ascii; + } letters; struct { - int64_t min; - int64_t max; - int64_t idx; + int64_t lo; + int64_t hi; + int64_t curr; int64_t step; - int npad; - } num; + int width; + } integers; } v; }; int main(void) { static char *items[] = {"a", "b", "c"}; - struct Pattern p_set; - p_set.kind = T_SET; - p_set.index = 0; - p_set.v.set.elem = items; - p_set.v.set.size = 3; - p_set.v.set.idx = 1; - assert(p_set.v.set.size == 3); - assert(p_set.v.set.elem[1][0] == 'b'); + struct Branch p_list; + p_list.choice = C_LIST; + p_list.index = 0; + p_list.v.list.items = items; + p_list.v.list.count = 3; + p_list.v.list.cursor = 1; + assert(p_list.v.list.count == 3); + assert(p_list.v.list.items[1][0] == 'b'); - struct Pattern p_ascii; - p_ascii.kind = T_RANGE_ASCII; - p_ascii.index = 1; - p_ascii.v.ascii.min = 'a'; - p_ascii.v.ascii.max = 'z'; - p_ascii.v.ascii.letter = 'm'; - p_ascii.v.ascii.step = 1; - assert(p_ascii.v.ascii.max - p_ascii.v.ascii.min == 25); + struct Branch p_letters; + p_letters.choice = C_LETTERS; + p_letters.index = 1; + p_letters.v.letters.lo = 'a'; + p_letters.v.letters.hi = 'z'; + p_letters.v.letters.curr = 'm'; + p_letters.v.letters.step = 1; + assert(p_letters.v.letters.hi - p_letters.v.letters.lo == 25); - struct Pattern p_num; - p_num.kind = T_RANGE_NUM; - p_num.index = 2; - p_num.v.num.min = 1; - p_num.v.num.max = 100; - p_num.v.num.idx = 1; - p_num.v.num.step = 1; - p_num.v.num.npad = 3; - assert(p_num.v.num.max == 100); - assert(p_num.v.num.npad == 3); + struct Branch p_integers; + p_integers.choice = C_INTEGERS; + p_integers.index = 2; + p_integers.v.integers.lo = 1; + p_integers.v.integers.hi = 100; + p_integers.v.integers.curr = 1; + p_integers.v.integers.step = 1; + p_integers.v.integers.width = 3; + assert(p_integers.v.integers.hi == 100); + assert(p_integers.v.integers.width == 3); return 0; } diff --git a/tests/unit/union_void_ptr_sized_deref.c b/tests/unit/union_void_ptr_sized_deref.c index def48e26..2f6bdeef 100644 --- a/tests/unit/union_void_ptr_sized_deref.c +++ b/tests/unit/union_void_ptr_sized_deref.c @@ -4,31 +4,31 @@ #include typedef enum { - W_INT64, - W_INT32, - W_INT16, -} IntWidth; + W_64, + W_32, + W_16, +} Width; -struct Arg { - IntWidth width; +struct Sink { + Width width; union { - const char *str; - void *ptr; - int64_t nums; - double dnum; - } val; + const char *text; + void *handle; + int64_t signed_n; + double f; + } out; }; -static void store_count(struct Arg *in, int64_t count) { - switch (in->width) { - case W_INT64: - *(int64_t *)in->val.ptr = count; +static void write_count(struct Sink *s, int64_t count) { + switch (s->width) { + case W_64: + *(int64_t *)s->out.handle = count; break; - case W_INT32: - *(int32_t *)in->val.ptr = (int32_t)count; + case W_32: + *(int32_t *)s->out.handle = (int32_t)count; break; - case W_INT16: - *(int16_t *)in->val.ptr = (int16_t)count; + case W_16: + *(int16_t *)s->out.handle = (int16_t)count; break; } } @@ -38,21 +38,21 @@ int main(void) { int32_t buf32 = 0; int16_t buf16 = 0; - struct Arg in; + struct Sink s; - in.width = W_INT64; - in.val.ptr = &buf64; - store_count(&in, 0x1122334455667788LL); + s.width = W_64; + s.out.handle = &buf64; + write_count(&s, 0x1122334455667788LL); assert(buf64 == 0x1122334455667788LL); - in.width = W_INT32; - in.val.ptr = &buf32; - store_count(&in, 0x12345678); + s.width = W_32; + s.out.handle = &buf32; + write_count(&s, 0x12345678); assert(buf32 == 0x12345678); - in.width = W_INT16; - in.val.ptr = &buf16; - store_count(&in, 0x1234); + s.width = W_16; + s.out.handle = &buf16; + write_count(&s, 0x1234); assert(buf16 == 0x1234); return 0; From fa79612e4dab7c6657e800141a71cdff3dc04fc2 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 27 Apr 2026 16:51:31 +0100 Subject: [PATCH 5/5] Delete alignof check --- tests/unit/union_field_alignment.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/union_field_alignment.c b/tests/unit/union_field_alignment.c index 70802d57..564f33c7 100644 --- a/tests/unit/union_field_alignment.c +++ b/tests/unit/union_field_alignment.c @@ -3,6 +3,8 @@ #include #include +// Just check if this compiles. node::x::aligner is used to impose a specific +// alignment on the bytes field. struct node { struct node *next; union { @@ -15,9 +17,6 @@ int main(void) { struct node n; n.next = 0; n.x.bytes[0] = 0xAB; - assert(n.x.bytes[0] == 0xAB); - assert(sizeof(n.x) >= sizeof(void *)); - assert(((uintptr_t)&n.x % _Alignof(void *)) == 0); return 0; }