Implementation of #[repr(packed(n))] RFC 1399.
This commit is contained in:
parent
ca26ef321c
commit
15d1c4d213
26 changed files with 849 additions and 167 deletions
|
|
@ -11,16 +11,23 @@
|
|||
// compile-flags: -C no-prepopulate-passes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(repr_packed)]
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct Packed {
|
||||
pub struct Packed1 {
|
||||
dealign: u8,
|
||||
data: u32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @write_pkd
|
||||
#[repr(packed(2))]
|
||||
pub struct Packed2 {
|
||||
dealign: u8,
|
||||
data: u32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @write_pkd1
|
||||
#[no_mangle]
|
||||
pub fn write_pkd(pkd: &mut Packed) -> u32 {
|
||||
pub fn write_pkd1(pkd: &mut Packed1) -> u32 {
|
||||
// CHECK: %{{.*}} = load i32, i32* %{{.*}}, align 1
|
||||
// CHECK: store i32 42, i32* %{{.*}}, align 1
|
||||
let result = pkd.data;
|
||||
|
|
@ -28,43 +35,94 @@ pub fn write_pkd(pkd: &mut Packed) -> u32 {
|
|||
result
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @write_pkd2
|
||||
#[no_mangle]
|
||||
pub fn write_pkd2(pkd: &mut Packed2) -> u32 {
|
||||
// CHECK: %{{.*}} = load i32, i32* %{{.*}}, align 2
|
||||
// CHECK: store i32 42, i32* %{{.*}}, align 2
|
||||
let result = pkd.data;
|
||||
pkd.data = 42;
|
||||
result
|
||||
}
|
||||
|
||||
pub struct Array([i32; 8]);
|
||||
#[repr(packed)]
|
||||
pub struct BigPacked {
|
||||
pub struct BigPacked1 {
|
||||
dealign: u8,
|
||||
data: Array
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @call_pkd
|
||||
#[repr(packed(2))]
|
||||
pub struct BigPacked2 {
|
||||
dealign: u8,
|
||||
data: Array
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @call_pkd1
|
||||
#[no_mangle]
|
||||
pub fn call_pkd(f: fn() -> Array) -> BigPacked {
|
||||
pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
|
||||
// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
|
||||
// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]])
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 1, i1 false)
|
||||
// check that calls whose destination is a field of a packed struct
|
||||
// go through an alloca rather than calling the function with an
|
||||
// unaligned destination.
|
||||
BigPacked { dealign: 0, data: f() }
|
||||
BigPacked1 { dealign: 0, data: f() }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @call_pkd2
|
||||
#[no_mangle]
|
||||
pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
|
||||
// CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
|
||||
// CHECK: call void %{{.*}}(%Array* noalias nocapture sret dereferenceable(32) [[ALLOCA]])
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 32, i32 2, i1 false)
|
||||
// check that calls whose destination is a field of a packed struct
|
||||
// go through an alloca rather than calling the function with an
|
||||
// unaligned destination.
|
||||
BigPacked2 { dealign: 0, data: f() }
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PackedPair(u8, u32);
|
||||
pub struct Packed1Pair(u8, u32);
|
||||
|
||||
// CHECK-LABEL: @pkd_pair
|
||||
#[repr(packed(2))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Packed2Pair(u8, u32);
|
||||
|
||||
// CHECK-LABEL: @pkd1_pair
|
||||
#[no_mangle]
|
||||
pub fn pkd_pair(pair1: &mut PackedPair, pair2: &mut PackedPair) {
|
||||
pub fn pkd1_pair(pair1: &mut Packed1Pair, pair2: &mut Packed1Pair) {
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 5, i32 1, i1 false)
|
||||
*pair2 = *pair1;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @pkd2_pair
|
||||
#[no_mangle]
|
||||
pub fn pkd2_pair(pair1: &mut Packed2Pair, pair2: &mut Packed2Pair) {
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 6, i32 2, i1 false)
|
||||
*pair2 = *pair1;
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PackedNestedPair((u32, u32));
|
||||
pub struct Packed1NestedPair((u32, u32));
|
||||
|
||||
// CHECK-LABEL: @pkd_nested_pair
|
||||
#[repr(packed(2))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Packed2NestedPair((u32, u32));
|
||||
|
||||
// CHECK-LABEL: @pkd1_nested_pair
|
||||
#[no_mangle]
|
||||
pub fn pkd_nested_pair(pair1: &mut PackedNestedPair, pair2: &mut PackedNestedPair) {
|
||||
pub fn pkd1_nested_pair(pair1: &mut Packed1NestedPair, pair2: &mut Packed1NestedPair) {
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 1, i1 false)
|
||||
*pair2 = *pair1;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @pkd2_nested_pair
|
||||
#[no_mangle]
|
||||
pub fn pkd2_nested_pair(pair1: &mut Packed2NestedPair, pair2: &mut Packed2NestedPair) {
|
||||
// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* %{{.*}}, i{{[0-9]+}} 8, i32 2, i1 false)
|
||||
*pair2 = *pair1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![feature(repr_packed)]
|
||||
|
||||
#[repr(C)]
|
||||
enum A { A }
|
||||
|
|
@ -36,6 +37,16 @@ struct G(i32); //~ ERROR type has conflicting packed and align representation hi
|
|||
#[repr(packed)]
|
||||
struct H(i32); //~ ERROR type has conflicting packed and align representation hints
|
||||
|
||||
#[repr(packed, packed(2))]
|
||||
struct I(i32); //~ ERROR type has conflicting packed representation hints
|
||||
|
||||
#[repr(packed(2))]
|
||||
#[repr(packed)]
|
||||
struct J(i32); //~ ERROR type has conflicting packed representation hints
|
||||
|
||||
#[repr(packed, packed(1))]
|
||||
struct K(i32);
|
||||
|
||||
#[repr(packed, align(8))]
|
||||
union X { //~ ERROR type has conflicting packed and align representation hints
|
||||
i: i32
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![feature(box_syntax)]
|
||||
#![feature(repr_packed)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
|
|
@ -60,6 +61,18 @@ struct AlignContainsPacked {
|
|||
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))]
|
||||
|
|
@ -218,6 +231,15 @@ pub fn main() {
|
|||
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 AlignLarge {
|
||||
stuff: [0; 0x10000],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,8 +8,24 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(repr_packed)]
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct S {
|
||||
pub struct P1S5 {
|
||||
a: u8,
|
||||
b: u32
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
pub struct P2S6 {
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u8
|
||||
}
|
||||
|
||||
#[repr(C, packed(2))]
|
||||
pub struct P2CS8 {
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u8
|
||||
}
|
||||
|
|
|
|||
37
src/test/run-pass/issue-48159.rs
Normal file
37
src/test/run-pass/issue-48159.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(repr_packed)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
pub enum c_void {}
|
||||
|
||||
type uintptr_t = usize;
|
||||
type int16_t = u16;
|
||||
type uint16_t = int16_t;
|
||||
type uint32_t = u32;
|
||||
type intptr_t = uintptr_t;
|
||||
|
||||
#[repr(C)]
|
||||
#[repr(packed(4))]
|
||||
pub struct kevent {
|
||||
pub ident: uintptr_t,
|
||||
pub filter: int16_t,
|
||||
pub flags: uint16_t,
|
||||
pub fflags: uint32_t,
|
||||
pub data: intptr_t,
|
||||
pub udata: *mut c_void,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(mem::align_of::<kevent>(), 4);
|
||||
}
|
||||
|
|
@ -10,15 +10,36 @@
|
|||
|
||||
// ignore-emscripten weird assertion?
|
||||
|
||||
#![feature(repr_packed)]
|
||||
|
||||
#[repr(packed)]
|
||||
struct Foo {
|
||||
struct Foo1 {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct Foo2 {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
struct Foo4C {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let foo = Foo { bar: 1, baz: 2 };
|
||||
let foo = Foo1 { bar: 1, baz: 2 };
|
||||
let brw = unsafe { &foo.baz };
|
||||
assert_eq!(*brw, 2);
|
||||
|
||||
let foo = Foo2 { bar: 1, baz: 2 };
|
||||
let brw = unsafe { &foo.baz };
|
||||
assert_eq!(*brw, 2);
|
||||
|
||||
let foo = Foo4C { bar: 1, baz: 2 };
|
||||
let brw = unsafe { &foo.baz };
|
||||
assert_eq!(*brw, 2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,45 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(repr_packed)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
#[repr(packed)]
|
||||
struct S<T, S> {
|
||||
struct P1<T, S> {
|
||||
a: T,
|
||||
b: u8,
|
||||
c: S
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(mem::size_of::<S<u8, u8>>(), 3);
|
||||
|
||||
assert_eq!(mem::size_of::<S<u64, u16>>(), 11);
|
||||
#[repr(packed(2))]
|
||||
struct P2<T, S> {
|
||||
a: T,
|
||||
b: u8,
|
||||
c: S
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
struct P4C<T, S> {
|
||||
a: T,
|
||||
b: u8,
|
||||
c: S
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($t:ty, $align:expr, $size:expr) => ({
|
||||
assert_eq!(mem::align_of::<$t>(), $align);
|
||||
assert_eq!(mem::size_of::<$t>(), $size);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
check!(P1::<u8, u8>, 1, 3);
|
||||
check!(P1::<u64, u16>, 1, 11);
|
||||
|
||||
check!(P2::<u8, u8>, 1, 3);
|
||||
check!(P2::<u64, u16>, 2, 12);
|
||||
|
||||
check!(P4C::<u8, u8>, 1, 3);
|
||||
check!(P4C::<u16, u64>, 4, 12);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,17 +8,46 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(repr_packed)]
|
||||
|
||||
#[repr(packed)]
|
||||
struct Foo {
|
||||
struct Foo1 {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct Foo2 {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
struct Foo4C {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let foo = Foo { bar: 1, baz: 2 };
|
||||
match foo {
|
||||
Foo {bar, baz} => {
|
||||
let foo1 = Foo1 { bar: 1, baz: 2 };
|
||||
match foo1 {
|
||||
Foo1 {bar, baz} => {
|
||||
assert_eq!(bar, 1);
|
||||
assert_eq!(baz, 2);
|
||||
}
|
||||
}
|
||||
|
||||
let foo2 = Foo2 { bar: 1, baz: 2 };
|
||||
match foo2 {
|
||||
Foo2 {bar, baz} => {
|
||||
assert_eq!(bar, 1);
|
||||
assert_eq!(baz, 2);
|
||||
}
|
||||
}
|
||||
|
||||
let foo4 = Foo4C { bar: 1, baz: 2 };
|
||||
match foo4 {
|
||||
Foo4C {bar, baz} => {
|
||||
assert_eq!(bar, 1);
|
||||
assert_eq!(baz, 2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,15 @@ extern crate packed;
|
|||
|
||||
use std::mem;
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(mem::size_of::<packed::S>(), 5);
|
||||
macro_rules! check {
|
||||
($t:ty, $align:expr, $size:expr) => ({
|
||||
assert_eq!(mem::align_of::<$t>(), $align);
|
||||
assert_eq!(mem::size_of::<$t>(), $size);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
check!(packed::P1S5, 1, 5);
|
||||
check!(packed::P2S6, 2, 6);
|
||||
check!(packed::P2CS8, 2, 8);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,44 +7,116 @@
|
|||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(repr_packed)]
|
||||
|
||||
|
||||
use std::mem;
|
||||
|
||||
#[repr(packed)]
|
||||
struct S4 {
|
||||
struct P1S4 {
|
||||
a: u8,
|
||||
b: [u8; 3],
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S4 {
|
||||
a: u8,
|
||||
b: [u8; 3],
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct S5 {
|
||||
struct P1S5 {
|
||||
a: u8,
|
||||
b: u32
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S2 {
|
||||
a: u8,
|
||||
b: u8
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S6 {
|
||||
a: u8,
|
||||
b: u32
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S12 {
|
||||
a: u32,
|
||||
b: u64
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct S13 {
|
||||
struct P1S13 {
|
||||
a: i64,
|
||||
b: f32,
|
||||
c: u8,
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S14 {
|
||||
a: i64,
|
||||
b: f32,
|
||||
c: u8,
|
||||
}
|
||||
|
||||
#[repr(packed(4))]
|
||||
struct P4S16 {
|
||||
a: u8,
|
||||
b: f32,
|
||||
c: i64,
|
||||
d: u16,
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
struct P4CS20 {
|
||||
a: u8,
|
||||
b: f32,
|
||||
c: i64,
|
||||
d: u16,
|
||||
}
|
||||
|
||||
enum Foo {
|
||||
Bar = 1,
|
||||
Baz = 2
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct S3_Foo {
|
||||
struct P1S3_Foo {
|
||||
a: u8,
|
||||
b: u16,
|
||||
c: Foo
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2_Foo {
|
||||
a: Foo,
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S3_Foo {
|
||||
a: u8,
|
||||
b: u16,
|
||||
c: Foo
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct S7_Option {
|
||||
struct P1S7_Option {
|
||||
a: f32,
|
||||
b: u8,
|
||||
c: u16,
|
||||
d: Option<Box<f64>>
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2_Option {
|
||||
a: Option<Box<f64>>
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S7_Option {
|
||||
a: f32,
|
||||
b: u8,
|
||||
c: u16,
|
||||
|
|
@ -52,15 +124,41 @@ struct S7_Option {
|
|||
}
|
||||
|
||||
// Placing packed structs in statics should work
|
||||
static TEST_S4: S4 = S4 { a: 1, b: [2, 3, 4] };
|
||||
static TEST_S5: S5 = S5 { a: 3, b: 67 };
|
||||
static TEST_S3_Foo: S3_Foo = S3_Foo { a: 1, b: 2, c: Foo::Baz };
|
||||
static TEST_P1S4: P1S4 = P1S4 { a: 1, b: [2, 3, 4] };
|
||||
static TEST_P1S5: P1S5 = P1S5 { a: 3, b: 67 };
|
||||
static TEST_P1S3_Foo: P1S3_Foo = P1S3_Foo { a: 1, b: 2, c: Foo::Baz };
|
||||
static TEST_P2S2: P2S2 = P2S2 { a: 1, b: 2 };
|
||||
static TEST_P2S4: P2S4 = P2S4 { a: 1, b: [2, 3, 4] };
|
||||
static TEST_P2S6: P2S6 = P2S6 { a: 1, b: 2 };
|
||||
static TEST_P2S12: P2S12 = P2S12 { a: 1, b: 2 };
|
||||
static TEST_P4S16: P4S16 = P4S16 { a: 1, b: 2.0, c: 3, d: 4 };
|
||||
static TEST_P4CS20: P4CS20 = P4CS20 { a: 1, b: 2.0, c: 3, d: 4 };
|
||||
|
||||
fn align_to(value: usize, align: usize) -> usize {
|
||||
(value + (align - 1)) & !(align - 1)
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($t:ty, $align:expr, $size:expr) => ({
|
||||
assert_eq!(mem::align_of::<$t>(), $align);
|
||||
assert_eq!(mem::size_of::<$t>(), $size);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(mem::size_of::<S4>(), 4);
|
||||
assert_eq!(mem::size_of::<S5>(), 5);
|
||||
assert_eq!(mem::size_of::<S13>(), 13);
|
||||
assert_eq!(mem::size_of::<S3_Foo>(), 3 + mem::size_of::<Foo>());
|
||||
assert_eq!(mem::size_of::<S7_Option>(), 7 + mem::size_of::<Option<Box<f64>>>());
|
||||
check!(P1S4, 1, 4);
|
||||
check!(P1S5, 1, 5);
|
||||
check!(P1S13, 1, 13);
|
||||
check!(P1S3_Foo, 1, 3 + mem::size_of::<Foo>());
|
||||
check!(P1S7_Option, 1, 7 + mem::size_of::<Option<Box<f64>>>());
|
||||
|
||||
check!(P2S2, 1, 2);
|
||||
check!(P2S4, 1, 4);
|
||||
check!(P2S6, 2, 6);
|
||||
check!(P2S12, 2, 12);
|
||||
check!(P2S14, 2, 14);
|
||||
check!(P4S16, 4, 16);
|
||||
check!(P4CS20, 4, 20);
|
||||
check!(P2S3_Foo, 2, align_to(3 + mem::size_of::<P2_Foo>(), 2));
|
||||
check!(P2S7_Option, 2, align_to(7 + mem::size_of::<P2_Option>(), 2));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,28 +8,80 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(repr_packed)]
|
||||
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
|
||||
#[repr(packed)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct Foo {
|
||||
struct Foo1 {
|
||||
bar: u8,
|
||||
baz: u64
|
||||
}
|
||||
|
||||
impl PartialEq for Foo {
|
||||
fn eq(&self, other: &Foo) -> bool {
|
||||
impl PartialEq for Foo1 {
|
||||
fn eq(&self, other: &Foo1) -> bool {
|
||||
self.bar == other.bar && self.baz == other.baz
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Foo {
|
||||
impl fmt::Debug for Foo1 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let bar = self.bar;
|
||||
let baz = self.baz;
|
||||
|
||||
f.debug_struct("Foo")
|
||||
f.debug_struct("Foo1")
|
||||
.field("bar", &bar)
|
||||
.field("baz", &baz)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
#[derive(Copy, Clone)]
|
||||
struct Foo2 {
|
||||
bar: u8,
|
||||
baz: u64
|
||||
}
|
||||
|
||||
impl PartialEq for Foo2 {
|
||||
fn eq(&self, other: &Foo2) -> bool {
|
||||
self.bar == other.bar && self.baz == other.baz
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Foo2 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let bar = self.bar;
|
||||
let baz = self.baz;
|
||||
|
||||
f.debug_struct("Foo2")
|
||||
.field("bar", &bar)
|
||||
.field("baz", &baz)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
#[derive(Copy, Clone)]
|
||||
struct Foo4C {
|
||||
bar: u8,
|
||||
baz: u64
|
||||
}
|
||||
|
||||
impl PartialEq for Foo4C {
|
||||
fn eq(&self, other: &Foo4C) -> bool {
|
||||
self.bar == other.bar && self.baz == other.baz
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Foo4C {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let bar = self.bar;
|
||||
let baz = self.baz;
|
||||
|
||||
f.debug_struct("Foo4C")
|
||||
.field("bar", &bar)
|
||||
.field("baz", &baz)
|
||||
.finish()
|
||||
|
|
@ -37,15 +89,42 @@ impl fmt::Debug for Foo {
|
|||
}
|
||||
|
||||
pub fn main() {
|
||||
let foos = [Foo { bar: 1, baz: 2 }; 10];
|
||||
let foo1s = [Foo1 { bar: 1, baz: 2 }; 10];
|
||||
|
||||
assert_eq!(mem::size_of::<[Foo; 10]>(), 90);
|
||||
assert_eq!(mem::align_of::<[Foo1; 10]>(), 1);
|
||||
assert_eq!(mem::size_of::<[Foo1; 10]>(), 90);
|
||||
|
||||
for i in 0..10 {
|
||||
assert_eq!(foos[i], Foo { bar: 1, baz: 2});
|
||||
assert_eq!(foo1s[i], Foo1 { bar: 1, baz: 2});
|
||||
}
|
||||
|
||||
for &foo in &foos {
|
||||
assert_eq!(foo, Foo { bar: 1, baz: 2 });
|
||||
for &foo in &foo1s {
|
||||
assert_eq!(foo, Foo1 { bar: 1, baz: 2 });
|
||||
}
|
||||
|
||||
let foo2s = [Foo2 { bar: 1, baz: 2 }; 10];
|
||||
|
||||
assert_eq!(mem::align_of::<[Foo2; 10]>(), 2);
|
||||
assert_eq!(mem::size_of::<[Foo2; 10]>(), 100);
|
||||
|
||||
for i in 0..10 {
|
||||
assert_eq!(foo2s[i], Foo2 { bar: 1, baz: 2});
|
||||
}
|
||||
|
||||
for &foo in &foo2s {
|
||||
assert_eq!(foo, Foo2 { bar: 1, baz: 2 });
|
||||
}
|
||||
|
||||
let foo4s = [Foo4C { bar: 1, baz: 2 }; 10];
|
||||
|
||||
assert_eq!(mem::align_of::<[Foo4C; 10]>(), 4);
|
||||
assert_eq!(mem::size_of::<[Foo4C; 10]>(), 120);
|
||||
|
||||
for i in 0..10 {
|
||||
assert_eq!(foo4s[i], Foo4C { bar: 1, baz: 2});
|
||||
}
|
||||
|
||||
for &foo in &foo4s {
|
||||
assert_eq!(foo, Foo4C { bar: 1, baz: 2 });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,33 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
#![feature(repr_packed)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
#[repr(packed)]
|
||||
struct S4(u8,[u8; 3]);
|
||||
struct P1S4(u8,[u8; 3]);
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S4(u8,[u8; 3]);
|
||||
|
||||
#[repr(packed)]
|
||||
struct S5(u8, u32);
|
||||
struct P1S5(u8, u32);
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S6(u8, u32);
|
||||
|
||||
#[repr(packed)]
|
||||
struct S13(i64, f32, u8);
|
||||
struct P1S13(i64, f32, u8);
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S14(i64, f32, u8);
|
||||
|
||||
#[repr(packed(4))]
|
||||
struct P4S16(u8, f32, i64, u16);
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
struct P4CS20(u8, f32, i64, u16);
|
||||
|
||||
enum Foo {
|
||||
Bar = 1,
|
||||
|
|
@ -27,21 +42,46 @@ enum Foo {
|
|||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct S3_Foo(u8, u16, Foo);
|
||||
struct P1S3_Foo(u8, u16, Foo);
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2_Foo(Foo);
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S3_Foo(u8, u16, Foo);
|
||||
|
||||
#[repr(packed)]
|
||||
struct S7_Option(f32, u8, u16, Option<Box<f64>>);
|
||||
struct P1S7_Option(f32, u8, u16, Option<Box<f64>>);
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2_Option(Option<Box<f64>>);
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct P2S7_Option(f32, u8, u16, Option<Box<f64>>);
|
||||
|
||||
fn align_to(value: usize, align: usize) -> usize {
|
||||
(value + (align - 1)) & !(align - 1)
|
||||
}
|
||||
|
||||
macro_rules! check {
|
||||
($t:ty, $align:expr, $size:expr) => ({
|
||||
assert_eq!(mem::align_of::<$t>(), $align);
|
||||
assert_eq!(mem::size_of::<$t>(), $size);
|
||||
});
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(mem::size_of::<S4>(), 4);
|
||||
check!(P1S4, 1, 4);
|
||||
check!(P1S5, 1, 5);
|
||||
check!(P1S13, 1, 13);
|
||||
check!(P1S3_Foo, 1, 3 + mem::size_of::<Foo>());
|
||||
check!(P1S7_Option, 1, 7 + mem::size_of::<Option<Box<f64>>>());
|
||||
|
||||
assert_eq!(mem::size_of::<S5>(), 5);
|
||||
|
||||
assert_eq!(mem::size_of::<S13>(), 13);
|
||||
|
||||
assert_eq!(mem::size_of::<S3_Foo>(),
|
||||
3 + mem::size_of::<Foo>());
|
||||
|
||||
assert_eq!(mem::size_of::<S7_Option>(),
|
||||
7 + mem::size_of::<Option<Box<f64>>>());
|
||||
check!(P2S4, 1, 4);
|
||||
check!(P2S6, 2, 6);
|
||||
check!(P2S14, 2, 14);
|
||||
check!(P4S16, 4, 16);
|
||||
check!(P4CS20, 4, 20);
|
||||
check!(P2S3_Foo, 2, align_to(3 + mem::size_of::<P2_Foo>(), 2));
|
||||
check!(P2S7_Option, 2, align_to(7 + mem::size_of::<P2_Option>(), 2));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![feature(untagged_unions)]
|
||||
#![feature(repr_packed)]
|
||||
|
||||
use std::mem::{size_of, size_of_val, align_of, align_of_val};
|
||||
|
||||
|
|
@ -18,7 +19,13 @@ struct S {
|
|||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct Sp {
|
||||
struct Sp1 {
|
||||
a: u16,
|
||||
b: [u8; 3],
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct Sp2 {
|
||||
a: u16,
|
||||
b: [u8; 3],
|
||||
}
|
||||
|
|
@ -29,15 +36,30 @@ union U {
|
|||
}
|
||||
|
||||
#[repr(packed)]
|
||||
union Up {
|
||||
union Up1 {
|
||||
a: u16,
|
||||
b: [u8; 3],
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
union Up2 {
|
||||
a: u16,
|
||||
b: [u8; 3],
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
union Up4c {
|
||||
a: u16,
|
||||
b: [u8; 3],
|
||||
}
|
||||
|
||||
const CS: S = S { a: 0, b: [0, 0, 0] };
|
||||
const CSP: Sp = Sp { a: 0, b: [0, 0, 0] };
|
||||
const CSP1: Sp1 = Sp1 { a: 0, b: [0, 0, 0] };
|
||||
const CSP2: Sp2 = Sp2 { a: 0, b: [0, 0, 0] };
|
||||
const CU: U = U { b: [0, 0, 0] };
|
||||
const CUP: Up = Up { b: [0, 0, 0] };
|
||||
const CUP1: Up1 = Up1 { b: [0, 0, 0] };
|
||||
const CUP2: Up2 = Up2 { b: [0, 0, 0] };
|
||||
const CUP4C: Up4c = Up4c { b: [0, 0, 0] };
|
||||
|
||||
fn main() {
|
||||
let s = S { a: 0, b: [0, 0, 0] };
|
||||
|
|
@ -48,13 +70,21 @@ fn main() {
|
|||
assert_eq!(align_of_val(&s), 2);
|
||||
assert_eq!(align_of_val(&CS), 2);
|
||||
|
||||
let sp = Sp { a: 0, b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<Sp>(), 5);
|
||||
assert_eq!(size_of_val(&sp), 5);
|
||||
assert_eq!(size_of_val(&CSP), 5);
|
||||
assert_eq!(align_of::<Sp>(), 1);
|
||||
assert_eq!(align_of_val(&sp), 1);
|
||||
assert_eq!(align_of_val(&CSP), 1);
|
||||
let sp1 = Sp1 { a: 0, b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<Sp1>(), 5);
|
||||
assert_eq!(size_of_val(&sp1), 5);
|
||||
assert_eq!(size_of_val(&CSP1), 5);
|
||||
assert_eq!(align_of::<Sp1>(), 1);
|
||||
assert_eq!(align_of_val(&sp1), 1);
|
||||
assert_eq!(align_of_val(&CSP1), 1);
|
||||
|
||||
let sp2 = Sp2 { a: 0, b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<Sp2>(), 6);
|
||||
assert_eq!(size_of_val(&sp2), 6);
|
||||
assert_eq!(size_of_val(&CSP2), 6);
|
||||
assert_eq!(align_of::<Sp2>(), 2);
|
||||
assert_eq!(align_of_val(&sp2), 2);
|
||||
assert_eq!(align_of_val(&CSP2), 2);
|
||||
|
||||
let u = U { b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<U>(), 4);
|
||||
|
|
@ -64,19 +94,35 @@ fn main() {
|
|||
assert_eq!(align_of_val(&u), 2);
|
||||
assert_eq!(align_of_val(&CU), 2);
|
||||
|
||||
let up = Up { b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<Up>(), 3);
|
||||
assert_eq!(size_of_val(&up), 3);
|
||||
assert_eq!(size_of_val(&CUP), 3);
|
||||
assert_eq!(align_of::<Up>(), 1);
|
||||
assert_eq!(align_of_val(&up), 1);
|
||||
assert_eq!(align_of_val(&CUP), 1);
|
||||
let Up1 = Up1 { b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<Up1>(), 3);
|
||||
assert_eq!(size_of_val(&Up1), 3);
|
||||
assert_eq!(size_of_val(&CUP1), 3);
|
||||
assert_eq!(align_of::<Up1>(), 1);
|
||||
assert_eq!(align_of_val(&Up1), 1);
|
||||
assert_eq!(align_of_val(&CUP1), 1);
|
||||
|
||||
let up2 = Up2 { b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<Up2>(), 4);
|
||||
assert_eq!(size_of_val(&up2), 4);
|
||||
assert_eq!(size_of_val(&CUP2), 4);
|
||||
assert_eq!(align_of::<Up2>(), 2);
|
||||
assert_eq!(align_of_val(&up2), 2);
|
||||
assert_eq!(align_of_val(&CUP2), 2);
|
||||
|
||||
let up4c = Up4c { b: [0, 0, 0] };
|
||||
assert_eq!(size_of::<Up4c>(), 4);
|
||||
assert_eq!(size_of_val(&up4c), 4);
|
||||
assert_eq!(size_of_val(&CUP4C), 4);
|
||||
assert_eq!(align_of::<Up4c>(), 2);
|
||||
assert_eq!(align_of_val(&up4c), 2);
|
||||
assert_eq!(align_of_val(&CUP4C), 2);
|
||||
|
||||
hybrid::check_hybrid();
|
||||
}
|
||||
|
||||
mod hybrid {
|
||||
use std::mem::size_of;
|
||||
use std::mem::{size_of, align_of};
|
||||
|
||||
#[repr(packed)]
|
||||
struct S1 {
|
||||
|
|
@ -96,9 +142,37 @@ mod hybrid {
|
|||
u: U,
|
||||
}
|
||||
|
||||
#[repr(C, packed(2))]
|
||||
struct S1C {
|
||||
a: u16,
|
||||
b: u8,
|
||||
}
|
||||
|
||||
#[repr(C, packed(2))]
|
||||
union UC {
|
||||
s: S1,
|
||||
c: u16,
|
||||
}
|
||||
|
||||
#[repr(C, packed(2))]
|
||||
struct S2C {
|
||||
d: u8,
|
||||
u: UC,
|
||||
}
|
||||
|
||||
pub fn check_hybrid() {
|
||||
assert_eq!(align_of::<S1>(), 1);
|
||||
assert_eq!(size_of::<S1>(), 3);
|
||||
assert_eq!(align_of::<U>(), 1);
|
||||
assert_eq!(size_of::<U>(), 3);
|
||||
assert_eq!(align_of::<S2>(), 1);
|
||||
assert_eq!(size_of::<S2>(), 4);
|
||||
|
||||
assert_eq!(align_of::<S1C>(), 2);
|
||||
assert_eq!(size_of::<S1C>(), 4);
|
||||
assert_eq!(align_of::<UC>(), 2);
|
||||
assert_eq!(size_of::<UC>(), 4);
|
||||
assert_eq!(align_of::<S2C>(), 2);
|
||||
assert_eq!(size_of::<S2C>(), 6);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
14
src/test/ui/feature-gate-repr_packed.rs
Normal file
14
src/test/ui/feature-gate-repr_packed.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[repr(packed(1))] //~ error: the `#[repr(packed(n))]` attribute is experimental
|
||||
struct Foo(u64);
|
||||
|
||||
fn main() {}
|
||||
11
src/test/ui/feature-gate-repr_packed.stderr
Normal file
11
src/test/ui/feature-gate-repr_packed.stderr
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
error[E0658]: the `#[repr(packed(n))]` attribute is experimental (see issue #33158)
|
||||
--> $DIR/feature-gate-repr_packed.rs:11:1
|
||||
|
|
||||
LL | #[repr(packed(1))] //~ error: the `#[repr(packed(n))]` attribute is experimental
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: add #![feature(repr_packed)] to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -21,10 +21,34 @@
|
|||
|
||||
#![allow(dead_code)]
|
||||
#![feature(start)]
|
||||
#![feature(repr_packed)]
|
||||
|
||||
#[derive(Default)]
|
||||
#[repr(packed)]
|
||||
struct Packed {
|
||||
struct Packed1 {
|
||||
a: u8,
|
||||
b: u8,
|
||||
g: i32,
|
||||
c: u8,
|
||||
h: i16,
|
||||
d: u8,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[repr(packed(2))]
|
||||
struct Packed2 {
|
||||
a: u8,
|
||||
b: u8,
|
||||
g: i32,
|
||||
c: u8,
|
||||
h: i16,
|
||||
d: u8,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[repr(packed(2))]
|
||||
#[repr(C)]
|
||||
struct Packed2C {
|
||||
a: u8,
|
||||
b: u8,
|
||||
g: i32,
|
||||
|
|
@ -45,7 +69,9 @@ struct Padded {
|
|||
|
||||
#[start]
|
||||
fn start(_: isize, _: *const *const u8) -> isize {
|
||||
let _c: Packed = Default::default();
|
||||
let _d: Padded = Default::default();
|
||||
let _c: Packed1 = Default::default();
|
||||
let _d: Packed2 = Default::default();
|
||||
let _e: Packed2C = Default::default();
|
||||
let _f: Padded = Default::default();
|
||||
0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
print-type-size type: `Packed2C`: 12 bytes, alignment: 2 bytes
|
||||
print-type-size field `.a`: 1 bytes
|
||||
print-type-size field `.b`: 1 bytes
|
||||
print-type-size field `.g`: 4 bytes
|
||||
print-type-size field `.c`: 1 bytes
|
||||
print-type-size padding: 1 bytes
|
||||
print-type-size field `.h`: 2 bytes
|
||||
print-type-size field `.d`: 1 bytes
|
||||
print-type-size end padding: 1 bytes
|
||||
print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
|
||||
print-type-size field `.g`: 4 bytes
|
||||
print-type-size field `.h`: 2 bytes
|
||||
|
|
@ -6,10 +15,17 @@ print-type-size field `.b`: 1 bytes
|
|||
print-type-size field `.c`: 1 bytes
|
||||
print-type-size field `.d`: 1 bytes
|
||||
print-type-size end padding: 2 bytes
|
||||
print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
|
||||
print-type-size type: `Packed1`: 10 bytes, alignment: 1 bytes
|
||||
print-type-size field `.a`: 1 bytes
|
||||
print-type-size field `.b`: 1 bytes
|
||||
print-type-size field `.g`: 4 bytes
|
||||
print-type-size field `.c`: 1 bytes
|
||||
print-type-size field `.h`: 2 bytes
|
||||
print-type-size field `.d`: 1 bytes
|
||||
print-type-size type: `Packed2`: 10 bytes, alignment: 2 bytes
|
||||
print-type-size field `.g`: 4 bytes
|
||||
print-type-size field `.h`: 2 bytes
|
||||
print-type-size field `.a`: 1 bytes
|
||||
print-type-size field `.b`: 1 bytes
|
||||
print-type-size field `.c`: 1 bytes
|
||||
print-type-size field `.d`: 1 bytes
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue