mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 04:57:19 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			241 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| // run-pass
 | |
| #![allow(dead_code, unused_allocation)]
 | |
| 
 | |
| use std::mem;
 | |
| 
 | |
| // Raising alignment
 | |
| #[repr(align(16))]
 | |
| #[derive(Clone, Copy, Debug)]
 | |
| struct Align16(i32);
 | |
| 
 | |
| // Lowering has no effect
 | |
| #[repr(align(1))]
 | |
| struct Align1(i32);
 | |
| 
 | |
| // Multiple attributes take the max
 | |
| #[repr(align(4))]
 | |
| #[repr(align(16))]
 | |
| #[repr(align(8))]
 | |
| struct AlignMany(i32);
 | |
| 
 | |
| // Raising alignment may not alter size.
 | |
| #[repr(align(8))]
 | |
| struct Align8Many {
 | |
|     a: i32,
 | |
|     b: i32,
 | |
|     c: i32,
 | |
|     d: u8,
 | |
| }
 | |
| 
 | |
| enum Enum {
 | |
|     A(i32),
 | |
|     B(Align16),
 | |
| }
 | |
| 
 | |
| // Nested alignment - use `#[repr(C)]` to suppress field reordering for sizeof test
 | |
| #[repr(C)]
 | |
| struct Nested {
 | |
|     a: i32,
 | |
|     b: i32,
 | |
|     c: Align16,
 | |
|     d: i8,
 | |
| }
 | |
| 
 | |
| #[repr(packed)]
 | |
| struct Packed(i32);
 | |
| 
 | |
| #[repr(align(16))]
 | |
| struct AlignContainsPacked {
 | |
|     a: Packed,
 | |
|     b: Packed,
 | |
| }
 | |
| 
 | |
| #[repr(C, packed(4))]
 | |
| struct Packed4C {
 | |
|     a: u32,
 | |
|     b: u64,
 | |
| }
 | |
| 
 | |
| #[repr(align(16))]
 | |
| struct AlignContainsPacked4C {
 | |
|     a: Packed4C,
 | |
|     b: u64,
 | |
| }
 | |
| 
 | |
| // The align limit was originally smaller (2^15).
 | |
| // Check that it works with big numbers.
 | |
| #[repr(align(0x10000))]
 | |
| struct AlignLarge {
 | |
|     stuff: [u8; 0x10000],
 | |
| }
 | |
| 
 | |
| union UnionContainsAlign {
 | |
|     a: Align16,
 | |
|     b: f32,
 | |
| }
 | |
| 
 | |
| impl Align16 {
 | |
|     // return aligned type
 | |
|     pub fn new(i: i32) -> Align16 {
 | |
|         Align16(i)
 | |
|     }
 | |
|     // pass aligned type
 | |
|     pub fn consume(a: Align16) -> i32 {
 | |
|         a.0
 | |
|     }
 | |
| }
 | |
| 
 | |
| const CONST_ALIGN16: Align16 = Align16(7);
 | |
| static STATIC_ALIGN16: Align16 = Align16(8);
 | |
| 
 | |
| // Check the actual address is aligned
 | |
| fn is_aligned_to<T>(p: &T, align: usize) -> bool {
 | |
|     let addr = p as *const T as usize;
 | |
|     (addr & (align - 1)) == 0
 | |
| }
 | |
| 
 | |
| pub fn main() {
 | |
|     // check alignment and size by type and value
 | |
|     assert_eq!(mem::align_of::<Align16>(), 16);
 | |
|     assert_eq!(mem::size_of::<Align16>(), 16);
 | |
| 
 | |
|     let a = Align16(7);
 | |
|     assert_eq!(a.0, 7);
 | |
|     assert_eq!(mem::align_of_val(&a), 16);
 | |
|     assert_eq!(mem::size_of_val(&a), 16);
 | |
| 
 | |
|     assert!(is_aligned_to(&a, 16));
 | |
| 
 | |
|     // lowering should have no effect
 | |
|     assert_eq!(mem::align_of::<Align1>(), 4);
 | |
|     assert_eq!(mem::size_of::<Align1>(), 4);
 | |
|     let a = Align1(7);
 | |
|     assert_eq!(a.0, 7);
 | |
|     assert_eq!(mem::align_of_val(&a), 4);
 | |
|     assert_eq!(mem::size_of_val(&a), 4);
 | |
|     assert!(is_aligned_to(&a, 4));
 | |
| 
 | |
|     // when multiple attributes are specified the max should be used
 | |
|     assert_eq!(mem::align_of::<AlignMany>(), 16);
 | |
|     assert_eq!(mem::size_of::<AlignMany>(), 16);
 | |
|     let a = AlignMany(7);
 | |
|     assert_eq!(a.0, 7);
 | |
|     assert_eq!(mem::align_of_val(&a), 16);
 | |
|     assert_eq!(mem::size_of_val(&a), 16);
 | |
|     assert!(is_aligned_to(&a, 16));
 | |
| 
 | |
|     // raising alignment should not reduce size
 | |
|     assert_eq!(mem::align_of::<Align8Many>(), 8);
 | |
|     assert_eq!(mem::size_of::<Align8Many>(), 16);
 | |
|     let a = Align8Many { a: 1, b: 2, c: 3, d: 4 };
 | |
|     assert_eq!(a.a, 1);
 | |
|     assert_eq!(mem::align_of_val(&a), 8);
 | |
|     assert_eq!(mem::size_of_val(&a), 16);
 | |
|     assert!(is_aligned_to(&a, 8));
 | |
| 
 | |
|     // return type
 | |
|     let a = Align16::new(1);
 | |
|     assert_eq!(mem::align_of_val(&a), 16);
 | |
|     assert_eq!(mem::size_of_val(&a), 16);
 | |
|     assert_eq!(a.0, 1);
 | |
|     assert!(is_aligned_to(&a, 16));
 | |
|     assert_eq!(Align16::consume(a), 1);
 | |
| 
 | |
|     // check const alignment, size and value
 | |
|     assert_eq!(mem::align_of_val(&CONST_ALIGN16), 16);
 | |
|     assert_eq!(mem::size_of_val(&CONST_ALIGN16), 16);
 | |
|     assert_eq!(CONST_ALIGN16.0, 7);
 | |
|     assert!(is_aligned_to(&CONST_ALIGN16, 16));
 | |
| 
 | |
|     // check global static alignment, size and value
 | |
|     assert_eq!(mem::align_of_val(&STATIC_ALIGN16), 16);
 | |
|     assert_eq!(mem::size_of_val(&STATIC_ALIGN16), 16);
 | |
|     assert_eq!(STATIC_ALIGN16.0, 8);
 | |
|     assert!(is_aligned_to(&STATIC_ALIGN16, 16));
 | |
| 
 | |
|     // Note that the size of Nested may change if struct field re-ordering is enabled
 | |
|     assert_eq!(mem::align_of::<Nested>(), 16);
 | |
|     assert_eq!(mem::size_of::<Nested>(), 48);
 | |
|     let a = Nested { a: 1, b: 2, c: Align16(3), d: 4 };
 | |
|     assert_eq!(mem::align_of_val(&a), 16);
 | |
|     assert_eq!(mem::align_of_val(&a.b), 4);
 | |
|     assert_eq!(mem::align_of_val(&a.c), 16);
 | |
|     assert_eq!(mem::size_of_val(&a), 48);
 | |
|     assert!(is_aligned_to(&a, 16));
 | |
|     // check the correct fields are indexed
 | |
|     assert_eq!(a.a, 1);
 | |
|     assert_eq!(a.b, 2);
 | |
|     assert_eq!(a.c.0, 3);
 | |
|     assert_eq!(a.d, 4);
 | |
| 
 | |
|     // enum should be aligned to max alignment
 | |
|     assert_eq!(mem::align_of::<Enum>(), 16);
 | |
|     assert_eq!(mem::align_of_val(&Enum::B(Align16(0))), 16);
 | |
|     let e = Enum::B(Align16(15));
 | |
|     match e {
 | |
|         Enum::B(ref a) => {
 | |
|             assert_eq!(a.0, 15);
 | |
|             assert_eq!(mem::align_of_val(a), 16);
 | |
|             assert_eq!(mem::size_of_val(a), 16);
 | |
|         }
 | |
|         _ => (),
 | |
|     }
 | |
|     assert!(is_aligned_to(&e, 16));
 | |
| 
 | |
|     // check union alignment
 | |
|     assert_eq!(mem::align_of::<UnionContainsAlign>(), 16);
 | |
|     assert_eq!(mem::size_of::<UnionContainsAlign>(), 16);
 | |
|     let u = UnionContainsAlign { a: Align16(10) };
 | |
|     unsafe {
 | |
|         assert_eq!(mem::align_of_val(&u.a), 16);
 | |
|         assert_eq!(mem::size_of_val(&u.a), 16);
 | |
|         assert_eq!(u.a.0, 10);
 | |
|         let UnionContainsAlign { a } = u;
 | |
|         assert_eq!(a.0, 10);
 | |
|     }
 | |
| 
 | |
|     // arrays of aligned elements should also be aligned
 | |
|     assert_eq!(mem::align_of::<[Align16; 2]>(), 16);
 | |
|     assert_eq!(mem::size_of::<[Align16; 2]>(), 32);
 | |
| 
 | |
|     let a = [Align16(0), Align16(1)];
 | |
|     assert_eq!(mem::align_of_val(&a[0]), 16);
 | |
|     assert_eq!(mem::align_of_val(&a[1]), 16);
 | |
|     assert!(is_aligned_to(&a, 16));
 | |
| 
 | |
|     // check heap value is aligned
 | |
|     assert_eq!(mem::align_of_val(Box::new(Align16(0)).as_ref()), 16);
 | |
| 
 | |
|     // check heap array is aligned
 | |
|     let a = vec![Align16(0), Align16(1)];
 | |
|     assert_eq!(mem::align_of_val(&a[0]), 16);
 | |
|     assert_eq!(mem::align_of_val(&a[1]), 16);
 | |
| 
 | |
|     assert_eq!(mem::align_of::<AlignContainsPacked>(), 16);
 | |
|     assert_eq!(mem::size_of::<AlignContainsPacked>(), 16);
 | |
|     let a = AlignContainsPacked { a: Packed(1), b: Packed(2) };
 | |
|     assert_eq!(mem::align_of_val(&a), 16);
 | |
|     assert_eq!(mem::align_of_val(&a.a), 1);
 | |
|     assert_eq!(mem::align_of_val(&a.b), 1);
 | |
|     assert_eq!(mem::size_of_val(&a), 16);
 | |
|     assert!(is_aligned_to(&a, 16));
 | |
| 
 | |
|     assert_eq!(mem::align_of::<AlignContainsPacked4C>(), 16);
 | |
|     assert_eq!(mem::size_of::<AlignContainsPacked4C>(), 32);
 | |
|     let a = AlignContainsPacked4C { a: Packed4C { a: 1, b: 2 }, b: 3 };
 | |
|     assert_eq!(mem::align_of_val(&a), 16);
 | |
|     assert_eq!(mem::align_of_val(&a.a), 4);
 | |
|     assert_eq!(mem::align_of_val(&a.b), mem::align_of::<u64>());
 | |
|     assert_eq!(mem::size_of_val(&a), 32);
 | |
|     assert!(is_aligned_to(&a, 16));
 | |
| 
 | |
|     let mut large = Box::new(AlignLarge { stuff: [0; 0x10000] });
 | |
|     large.stuff[0] = 132;
 | |
|     *large.stuff.last_mut().unwrap() = 102;
 | |
|     assert_eq!(large.stuff[0], 132);
 | |
|     assert_eq!(large.stuff.last(), Some(&102));
 | |
|     assert_eq!(mem::align_of::<AlignLarge>(), 0x10000);
 | |
|     assert_eq!(mem::align_of_val(&*large), 0x10000);
 | |
|     assert!(is_aligned_to(&*large, 0x10000));
 | |
| }
 | 
