Skip to content

Commit

Permalink
Rollup merge of #133355 - chorman0773:spec-layout-tests, r=jieyouxu
Browse files Browse the repository at this point in the history
Add language tests for aggregate types

This adds some tests for struct and union types, ensuring that they satisfy the rules for all structs and unions - namely that fields of structs do not overlap, fields are well-aligned, and the size of the entire.

The reference annotations used are from rust-lang/reference#1654, though the rules tested here were FCPed in <rust-lang/reference#1152>.
  • Loading branch information
jieyouxu authored Nov 23, 2024
2 parents 75b8f43 + 8578ccc commit ae4fdf1
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 0 deletions.
29 changes: 29 additions & 0 deletions tests/ui/layout/aggregate-lang/struct-align.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//@ run-pass
//@ reference: layout.aggregate.struct-size-align
//@ edition: 2018

#[repr(align(64))]
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub struct Overaligned(u8);

#[allow(dead_code)]
struct ReprRustStruct {
x: i32,
y: [u32; 4],
z: f32,
a: u128,
b: Overaligned,
}

fn test_alignment_contains_all_fields() {
assert!(core::mem::align_of::<ReprRustStruct>() >= core::mem::align_of::<i32>());
assert!(core::mem::align_of::<ReprRustStruct>() >= core::mem::align_of::<[u32; 4]>());
assert!(core::mem::align_of::<ReprRustStruct>() >= core::mem::align_of::<f32>());
assert!(core::mem::align_of::<ReprRustStruct>() >= core::mem::align_of::<u128>());
assert!(core::mem::align_of::<ReprRustStruct>() >= core::mem::align_of::<Overaligned>());
}

fn main() {
test_alignment_contains_all_fields();
}
78 changes: 78 additions & 0 deletions tests/ui/layout/aggregate-lang/struct-offsets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//@ run-pass
//@ reference: layout.aggregate.struct-offsets
//@ edition: 2018

#[repr(align(64))]
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub struct Overaligned(u8);

#[allow(dead_code)]
struct ReprRustStruct {
x: i32,
y: [u32; 4],
z: f32,
a: u128,
b: Overaligned,
}

macro_rules! span_of {
($ty:ty , $field:tt) => {{
let __field = unsafe { ::core::mem::zeroed::<$ty>() };

(
core::mem::offset_of!($ty, $field),
core::mem::offset_of!($ty, $field) + core::mem::size_of_val(&__field.$field),
)
}};
}

fn test_fields_make_sense(a: &(usize, usize)) {
assert!(a.0 <= a.1);
}

// order is `begin, end`
fn test_non_overlapping(a: &(usize, usize), b: &(usize, usize)) {
assert!((a.1 <= b.0) || (b.1 <= a.0));
}

fn test_fields_non_overlapping() {
let fields = [
span_of!(ReprRustStruct, x),
span_of!(ReprRustStruct, y),
span_of!(ReprRustStruct, z),
span_of!(ReprRustStruct, a),
span_of!(ReprRustStruct, b),
];

test_fields_make_sense(&fields[0]);
test_fields_make_sense(&fields[1]);
test_fields_make_sense(&fields[2]);
test_fields_make_sense(&fields[3]);
test_fields_make_sense(&fields[4]);

test_non_overlapping(&fields[0], &fields[1]);
test_non_overlapping(&fields[0], &fields[2]);
test_non_overlapping(&fields[0], &fields[3]);
test_non_overlapping(&fields[0], &fields[4]);
test_non_overlapping(&fields[1], &fields[2]);
test_non_overlapping(&fields[2], &fields[3]);
test_non_overlapping(&fields[2], &fields[4]);
test_non_overlapping(&fields[3], &fields[4]);
}

fn test_fields_aligned() {
assert_eq!((core::mem::offset_of!(ReprRustStruct, x) % (core::mem::align_of::<i32>())), 0);
assert_eq!((core::mem::offset_of!(ReprRustStruct, y) % (core::mem::align_of::<[u32; 4]>())), 0);
assert_eq!((core::mem::offset_of!(ReprRustStruct, z) % (core::mem::align_of::<f32>())), 0);
assert_eq!((core::mem::offset_of!(ReprRustStruct, a) % (core::mem::align_of::<u128>())), 0);
assert_eq!(
(core::mem::offset_of!(ReprRustStruct, b) % (core::mem::align_of::<Overaligned>())),
0
);
}

fn main() {
test_fields_non_overlapping();
test_fields_aligned();
}
50 changes: 50 additions & 0 deletions tests/ui/layout/aggregate-lang/struct-size.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//@ run-pass
//@ reference: layout.aggregate.struct-size-align
//@ edition: 2018

#[allow(dead_code)]
struct ReprRustStruct {
x: i32,
y: [u32; 4],
z: f32,
a: u128,
}

fn test_size_contains_all_types() {
assert!(
core::mem::size_of::<ReprRustStruct>()
>= (core::mem::size_of::<i32>()
+ core::mem::size_of::<[u32; 4]>()
+ core::mem::size_of::<f32>()
+ core::mem::size_of::<u128>())
);
}

fn test_size_contains_all_fields() {
assert!(
(core::mem::offset_of!(ReprRustStruct, x) + core::mem::size_of::<i32>())
<= core::mem::size_of::<ReprRustStruct>()
);
assert!(
(core::mem::offset_of!(ReprRustStruct, y) + core::mem::size_of::<[u32; 4]>())
<= core::mem::size_of::<ReprRustStruct>()
);
assert!(
(core::mem::offset_of!(ReprRustStruct, z) + core::mem::size_of::<f32>())
<= core::mem::size_of::<ReprRustStruct>()
);
assert!(
(core::mem::offset_of!(ReprRustStruct, a) + core::mem::size_of::<u128>())
<= core::mem::size_of::<ReprRustStruct>()
);
}

fn test_size_modulo_align() {
assert_eq!(core::mem::size_of::<ReprRustStruct>() % core::mem::align_of::<ReprRustStruct>(), 0);
}

fn main() {
test_size_contains_all_fields();
test_size_contains_all_types();
test_size_modulo_align();
}
29 changes: 29 additions & 0 deletions tests/ui/layout/aggregate-lang/union-align.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//@ run-pass
//@ reference: layout.aggregate.struct-size-align
//@ edition: 2018

#[repr(align(64))]
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub struct Overaligned(u8);

#[allow(dead_code)]
union ReprRustUnion {
x: i32,
y: [u32; 4],
z: f32,
a: u128,
b: Overaligned,
}

fn test_alignment_contains_all_fields() {
assert!(core::mem::align_of::<ReprRustUnion>() >= core::mem::align_of::<i32>());
assert!(core::mem::align_of::<ReprRustUnion>() >= core::mem::align_of::<[u32; 4]>());
assert!(core::mem::align_of::<ReprRustUnion>() >= core::mem::align_of::<f32>());
assert!(core::mem::align_of::<ReprRustUnion>() >= core::mem::align_of::<u128>());
assert!(core::mem::align_of::<ReprRustUnion>() >= core::mem::align_of::<Overaligned>());
}

fn main() {
test_alignment_contains_all_fields();
}
32 changes: 32 additions & 0 deletions tests/ui/layout/aggregate-lang/union-offsets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//@ run-pass
//@ reference: layout.aggregate.struct-offsets
//@ edition: 2018

#[repr(align(64))]
#[derive(Copy, Clone)]
#[allow(dead_code)]
pub struct Overaligned(u8);

#[allow(dead_code)]
union ReprRustUnion {
x: i32,
y: [u32; 4],
z: f32,
a: u128,
b: Overaligned,
}

fn test_fields_aligned() {
assert_eq!((core::mem::offset_of!(ReprRustUnion, x) % (core::mem::align_of::<i32>())), 0);
assert_eq!((core::mem::offset_of!(ReprRustUnion, y) % (core::mem::align_of::<[u32; 4]>())), 0);
assert_eq!((core::mem::offset_of!(ReprRustUnion, z) % (core::mem::align_of::<f32>())), 0);
assert_eq!((core::mem::offset_of!(ReprRustUnion, a) % (core::mem::align_of::<u128>())), 0);
assert_eq!(
(core::mem::offset_of!(ReprRustUnion, b) % (core::mem::align_of::<Overaligned>())),
0
);
}

fn main() {
test_fields_aligned();
}
47 changes: 47 additions & 0 deletions tests/ui/layout/aggregate-lang/union-size.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//@ run-pass
//@ reference: layout.aggregate.struct-size-align
//@ edition: 2018

#[allow(dead_code)]
union ReprRustUnion {
x: i32,
y: [u32; 4],
z: f32,
a: u128,
}

fn test_size_contains_each_type() {
assert!(core::mem::size_of::<i32>() <= core::mem::size_of::<ReprRustUnion>());
assert!(core::mem::size_of::<[u32; 4]>() <= core::mem::size_of::<ReprRustUnion>());
assert!(core::mem::size_of::<f32>() <= core::mem::size_of::<ReprRustUnion>());
assert!(core::mem::size_of::<u128>() <= core::mem::size_of::<ReprRustUnion>());
}

fn test_size_contains_all_fields() {
assert!(
(core::mem::offset_of!(ReprRustUnion, x) + core::mem::size_of::<i32>())
<= core::mem::size_of::<ReprRustUnion>()
);
assert!(
(core::mem::offset_of!(ReprRustUnion, y) + core::mem::size_of::<[u32; 4]>())
<= core::mem::size_of::<ReprRustUnion>()
);
assert!(
(core::mem::offset_of!(ReprRustUnion, z) + core::mem::size_of::<f32>())
<= core::mem::size_of::<ReprRustUnion>()
);
assert!(
(core::mem::offset_of!(ReprRustUnion, a) + core::mem::size_of::<u128>())
<= core::mem::size_of::<ReprRustUnion>()
);
}

fn test_size_modulo_align() {
assert_eq!(core::mem::size_of::<ReprRustUnion>() % core::mem::align_of::<ReprRustUnion>(), 0);
}

fn main() {
test_size_contains_each_type();
test_size_contains_all_fields();
test_size_modulo_align();
}

0 comments on commit ae4fdf1

Please sign in to comment.