diff --git a/tests/unit/out/refcount/union_basic.rs b/tests/unit/out/refcount/union_basic.rs new file mode 100644 index 00000000..c7255a39 --- /dev/null +++ b/tests/unit/out/refcount/union_basic.rs @@ -0,0 +1,25 @@ +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}; +#[derive(Default)] +pub struct basic { + pub i: Value, + pub f: Value, +} +impl ByteRepr for basic {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let u: Value = >::default(); + (*(*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 new file mode 100644 index 00000000..1ddfcb9c --- /dev/null +++ b/tests/unit/out/unsafe/union_basic.rs @@ -0,0 +1,26 @@ +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; +#[derive(Copy, Clone, Default)] +pub struct basic { + pub i: i32, + pub f: f32, +} +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; +} diff --git a/tests/unit/union_addrof_external.c b/tests/unit/union_addrof_external.c new file mode 100644 index 00000000..2a7fab68 --- /dev/null +++ b/tests/unit/union_addrof_external.c @@ -0,0 +1,49 @@ +// translation-fail +#include +#include +#include +#include + +struct record { + uint16_t code; + uint16_t lo; + uint32_t hi; + char pad[8]; +}; + +struct Container { + union { + struct record h; + char raw[128]; + } view; +}; + +static void fill(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 Container c; + memset(&c, 0, sizeof(c)); + + fill((void *)&c.view, sizeof(c.view)); + + 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(c.view.raw[0] == 2); + assert((unsigned char)c.view.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..0dc5d05c --- /dev/null +++ b/tests/unit/union_cross_arm_cast.c @@ -0,0 +1,46 @@ +// translation-fail +#include +#include +#include +#include + +struct shape_a { + uint16_t code; + char pad[14]; +}; + +struct shape_b { + uint16_t code; + uint16_t lo; + uint32_t mid; + uint8_t fill[16]; + uint32_t tail; +}; + +struct Container { + unsigned int len; + union { + struct shape_a a; + struct shape_b b; + char raw[64]; + } u; +}; + +int main(void) { + struct Container c; + memset(&c, 0, sizeof(c)); + + c.u.a.code = 10; + c.len = sizeof(struct shape_b); + + ((struct shape_b *)(void *)&c.u.a)->tail = 0xDEADBEEF; + + assert(c.u.b.tail == 0xDEADBEEF); + assert(c.u.b.code == 10); + + 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 new file mode 100644 index 00000000..564f33c7 --- /dev/null +++ b/tests/unit/union_field_alignment.c @@ -0,0 +1,22 @@ +// translation-fail +#include +#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 { + uint8_t bytes[1]; + void *aligner; + } x; +}; + +int main(void) { + struct node n; + n.next = 0; + n.x.bytes[0] = 0xAB; + assert(n.x.bytes[0] == 0xAB); + 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..e8efd7c9 --- /dev/null +++ b/tests/unit/union_flex_array_member.c @@ -0,0 +1,35 @@ +// translation-fail +#include +#include +#include +#include +#include + +struct node { + size_t len; + union { + uint8_t bytes[1]; + void *aligner; + } x; +}; + +int main(void) { + 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 < tail_size; i++) { + n->x.bytes[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 = &n->x.bytes[10]; + assert(*p == 10); + *p = 0xAA; + assert(n->x.bytes[10] == 0xAA); + + free(n); + return 0; +} diff --git a/tests/unit/union_memset_memcpy.c b/tests/unit/union_memset_memcpy.c new file mode 100644 index 00000000..75c1ff61 --- /dev/null +++ b/tests/unit/union_memset_memcpy.c @@ -0,0 +1,55 @@ +// translation-fail +#include +#include +#include +#include + +struct shape_a { + uint16_t code; + char pad[14]; +}; + +struct shape_b { + uint16_t code; + uint16_t lo; + uint32_t hi; + char fill[8]; +}; + +struct Container { + union { + struct shape_a a; + struct shape_b b; + char raw[256]; + } view; +}; + +int main(void) { + 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(c.view.raw)); + memcpy(&c.view.raw, src, len); + + assert(c.view.b.code == 2); + assert(((unsigned char *)&c.view.b.lo)[0] == 0x50); + + 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 new file mode 100644 index 00000000..de3fa625 --- /dev/null +++ b/tests/unit/union_nested.c @@ -0,0 +1,45 @@ +// translation-fail +#include +#include +#include + +struct record { + uint16_t code; + char pad[14]; +}; + +struct inner { + union { + struct record h; + char raw[128]; + } view; +}; + +struct Outer { + int kind; + int level; + int variant; + unsigned int len; + union { + struct record h; + struct inner nested; + } body; +}; + +int main(void) { + struct Outer ex; + memset(&ex, 0, sizeof(ex)); + + ex.kind = 2; + 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.code == 2); + assert(ex.body.h.pad[0] == 'X'); + + assert(ex.body.nested.view.h.code == 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..203ef9d1 --- /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 *as_unsigned; + long *as_signed; + } pp; + + pp.as_signed = &x; + *pp.as_unsigned = 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..42146906 --- /dev/null +++ b/tests/unit/union_tagged_many_arms.c @@ -0,0 +1,52 @@ +// translation-fail +#include +#include + +typedef enum { + T_NUM_S, + T_NUM_U, + T_TEXT, + T_FLOAT, + T_REF, +} Tag; + +struct Slot { + Tag tag; + union { + const char *text; + void *handle; + int64_t signed_n; + uint64_t unsigned_n; + double f; + } payload; +}; + +int main(void) { + 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 Slot e; + e.tag = T_REF; + e.payload.handle = &x; + assert(e.payload.handle == &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..bc93bcac --- /dev/null +++ b/tests/unit/union_tagged_struct_arms.c @@ -0,0 +1,69 @@ +// translation-fail +#include +#include + +typedef enum { + C_LIST = 1, + C_LETTERS, + C_INTEGERS, +} Choice; + +struct Branch { + Choice choice; + int index; + union { + struct { + char **items; + int64_t count; + int64_t cursor; + } list; + struct { + int lo; + int hi; + int curr; + unsigned char step; + } letters; + struct { + int64_t lo; + int64_t hi; + int64_t curr; + int64_t step; + int width; + } integers; + } v; +}; + +int main(void) { + static char *items[] = {"a", "b", "c"}; + + 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 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 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 new file mode 100644 index 00000000..2f6bdeef --- /dev/null +++ b/tests/unit/union_void_ptr_sized_deref.c @@ -0,0 +1,59 @@ +// translation-fail +#include +#include +#include + +typedef enum { + W_64, + W_32, + W_16, +} Width; + +struct Sink { + Width width; + union { + const char *text; + void *handle; + int64_t signed_n; + double f; + } out; +}; + +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_32: + *(int32_t *)s->out.handle = (int32_t)count; + break; + case W_16: + *(int16_t *)s->out.handle = (int16_t)count; + break; + } +} + +int main(void) { + int64_t buf64 = 0; + int32_t buf32 = 0; + int16_t buf16 = 0; + + struct Sink s; + + s.width = W_64; + s.out.handle = &buf64; + write_count(&s, 0x1122334455667788LL); + assert(buf64 == 0x1122334455667788LL); + + s.width = W_32; + s.out.handle = &buf32; + write_count(&s, 0x12345678); + assert(buf32 == 0x12345678); + + s.width = W_16; + s.out.handle = &buf16; + write_count(&s, 0x1234); + assert(buf16 == 0x1234); + + return 0; +}