提交 15d1c4d2 编写于 作者: C Cameron Hart

Implementation of `#[repr(packed(n))]` RFC 1399.

上级 ca26ef32
# `repr_packed`
The tracking issue for this feature is [#33158]
[#33158]: https://github.com/rust-lang/rust/issues/33158
------------------------
......@@ -62,6 +62,7 @@ pub struct TypeSizeInfo {
pub type_description: String,
pub align: u64,
pub overall_size: u64,
pub packed: bool,
pub opt_discr_size: Option<u64>,
pub variants: Vec<VariantInfo>,
}
......@@ -79,6 +80,7 @@ pub fn record_type_size<S: ToString>(&mut self,
type_desc: S,
align: Align,
overall_size: Size,
packed: bool,
opt_discr_size: Option<Size>,
variants: Vec<VariantInfo>) {
let info = TypeSizeInfo {
......@@ -86,6 +88,7 @@ pub fn record_type_size<S: ToString>(&mut self,
type_description: type_desc.to_string(),
align: align.abi(),
overall_size: overall_size.bytes(),
packed: packed,
opt_discr_size: opt_discr_size.map(|s| s.bytes()),
variants,
};
......@@ -153,24 +156,26 @@ pub fn print_type_sizes(&self) {
for field in fields.iter() {
let FieldInfo { ref name, offset, size, align } = *field;
// Include field alignment in output only if it caused padding injection
if min_offset != offset {
if offset > min_offset {
let pad = offset - min_offset;
println!("print-type-size {}padding: {} bytes",
indent, pad);
println!("print-type-size {}field `.{}`: {} bytes, \
alignment: {} bytes",
indent, name, size, align);
} else {
println!("print-type-size {}field `.{}`: {} bytes, \
offset: {} bytes, \
alignment: {} bytes",
indent, name, size, offset, align);
}
} else {
if offset > min_offset {
let pad = offset - min_offset;
println!("print-type-size {}padding: {} bytes",
indent, pad);
}
if offset < min_offset {
// if this happens something is very wrong
println!("print-type-size {}field `.{}`: {} bytes, \
offset: {} bytes, \
alignment: {} bytes",
indent, name, size, offset, align);
} else if info.packed || offset == min_offset {
println!("print-type-size {}field `.{}`: {} bytes",
indent, name, size);
} else {
// Include field alignment in output only if it caused padding injection
println!("print-type-size {}field `.{}`: {} bytes, \
alignment: {} bytes",
indent, name, size, align);
}
min_offset = offset + size;
......
......@@ -12,7 +12,7 @@
pub use self::Primitive::*;
use session::{self, DataTypeKind, Session};
use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};
use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions};
use syntax::ast::{self, FloatTy, IntTy, UintTy};
use syntax::attr;
......@@ -344,8 +344,8 @@ fn add_assign(&mut self, other: Size) {
/// a maximum capacity of 2<sup>31</sup> - 1 or 2147483647.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct Align {
abi: u8,
pref: u8,
abi_pow2: u8,
pref_pow2: u8,
}
impl Align {
......@@ -377,17 +377,17 @@ pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> {
};
Ok(Align {
abi: log2(abi)?,
pref: log2(pref)?,
abi_pow2: log2(abi)?,
pref_pow2: log2(pref)?,
})
}
pub fn abi(self) -> u64 {
1 << self.abi
1 << self.abi_pow2
}
pub fn pref(self) -> u64 {
1 << self.pref
1 << self.pref_pow2
}
pub fn abi_bits(self) -> u64 {
......@@ -400,15 +400,15 @@ pub fn pref_bits(self) -> u64 {
pub fn min(self, other: Align) -> Align {
Align {
abi: cmp::min(self.abi, other.abi),
pref: cmp::min(self.pref, other.pref),
abi_pow2: cmp::min(self.abi_pow2, other.abi_pow2),
pref_pow2: cmp::min(self.pref_pow2, other.pref_pow2),
}
}
pub fn max(self, other: Align) -> Align {
Align {
abi: cmp::max(self.abi, other.abi),
pref: cmp::max(self.pref, other.pref),
abi_pow2: cmp::max(self.abi_pow2, other.abi_pow2),
pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2),
}
}
}
......@@ -974,6 +974,11 @@ enum StructKind {
bug!("struct cannot be packed and aligned");
}
let pack = {
let pack = repr.pack as u64;
Align::from_bytes(pack, pack).unwrap()
};
let mut align = if packed {
dl.i8_align
} else {
......@@ -984,8 +989,7 @@ enum StructKind {
let mut offsets = vec![Size::from_bytes(0); fields.len()];
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
// Anything with repr(C) or repr(packed) doesn't optimize.
let mut optimize = (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty();
let mut optimize = !repr.inhibit_struct_field_reordering_opt();
if let StructKind::Prefixed(_, align) = kind {
optimize &= align.abi() == 1;
}
......@@ -997,6 +1001,9 @@ enum StructKind {
fields.len()
};
let optimizing = &mut inverse_memory_index[..end];
let field_align = |f: &TyLayout| {
if packed { f.align.min(pack).abi() } else { f.align.abi() }
};
match kind {
StructKind::AlwaysSized |
StructKind::MaybeUnsized => {
......@@ -1004,11 +1011,11 @@ enum StructKind {
// Place ZSTs first to avoid "interesting offsets",
// especially with only one or two non-ZST fields.
let f = &fields[x as usize];
(!f.is_zst(), cmp::Reverse(f.align.abi()))
})
(!f.is_zst(), cmp::Reverse(field_align(f)))
});
}
StructKind::Prefixed(..) => {
optimizing.sort_by_key(|&x| fields[x as usize].align.abi());
optimizing.sort_by_key(|&x| field_align(&fields[x as usize]));
}
}
}
......@@ -1022,7 +1029,10 @@ enum StructKind {
let mut offset = Size::from_bytes(0);
if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
if !packed {
if packed {
let prefix_align = prefix_align.min(pack);
align = align.max(prefix_align);
} else {
align = align.max(prefix_align);
}
offset = prefix_size.abi_align(prefix_align);
......@@ -1044,7 +1054,12 @@ enum StructKind {
}
// Invariant: offset < dl.obj_size_bound() <= 1<<61
if !packed {
if packed {
let field_pack = field.align.min(pack);
offset = offset.abi_align(field_pack);
align = align.max(field_pack);
}
else {
offset = offset.abi_align(field.align);
align = align.max(field.align);
}
......@@ -1377,7 +1392,12 @@ enum StructKind {
bug!("Union cannot be packed and aligned");
}
let mut align = if def.repr.packed() {
let pack = {
let pack = def.repr.pack as u64;
Align::from_bytes(pack, pack).unwrap()
};
let mut align = if packed {
dl.i8_align
} else {
dl.aggregate_align
......@@ -1393,7 +1413,10 @@ enum StructKind {
for field in &variants[0] {
assert!(!field.is_unsized());
if !packed {
if packed {
let field_pack = field.align.min(pack);
align = align.max(field_pack);
} else {
align = align.max(field.align);
}
size = cmp::max(size, field.size);
......@@ -1740,12 +1763,13 @@ fn record_layout_for_printing(self, layout: TyLayout<'tcx>) {
fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
let record = |kind, packed, opt_discr_size, variants| {
let type_desc = format!("{:?}", layout.ty);
self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
layout.align,
layout.size,
packed,
opt_discr_size,
variants);
};
......@@ -1758,7 +1782,7 @@ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
ty::TyClosure(..) => {
debug!("print-type-size t: `{:?}` record closure", layout.ty);
record(DataTypeKind::Closure, None, vec![]);
record(DataTypeKind::Closure, false, None, vec![]);
return;
}
......@@ -1769,6 +1793,7 @@ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
};
let adt_kind = adt_def.adt_kind();
let adt_packed = adt_def.repr.packed();
let build_variant_info = |n: Option<ast::Name>,
flds: &[ast::Name],
......@@ -1821,6 +1846,7 @@ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
let fields: Vec<_> =
variant_def.fields.iter().map(|f| f.name).collect();
record(adt_kind.into(),
adt_packed,
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
......@@ -1828,7 +1854,7 @@ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
} else {
// (This case arises for *empty* enums; so give it
// zero variants.)
record(adt_kind.into(), None, vec![]);
record(adt_kind.into(), adt_packed, None, vec![]);
}
}
......@@ -1845,7 +1871,7 @@ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
layout.for_variant(self, i))
})
.collect();
record(adt_kind.into(), match layout.variants {
record(adt_kind.into(), adt_packed, match layout.variants {
Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)),
_ => None
}, variant_infos);
......@@ -2518,8 +2544,8 @@ fn hash_stable<W: StableHasherResult>(&self,
});
impl_stable_hash_for!(struct ::ty::layout::Align {
abi,
pref
abi_pow2,
pref_pow2
});
impl_stable_hash_for!(struct ::ty::layout::Size {
......
......@@ -1623,15 +1623,13 @@ pub enum AdtKind { Struct, Union, Enum }
#[derive(RustcEncodable, RustcDecodable, Default)]
pub struct ReprFlags: u8 {
const IS_C = 1 << 0;
const IS_PACKED = 1 << 1;
const IS_SIMD = 1 << 2;
const IS_TRANSPARENT = 1 << 3;
const IS_SIMD = 1 << 1;
const IS_TRANSPARENT = 1 << 2;
// Internal only for now. If true, don't reorder fields.
const IS_LINEAR = 1 << 4;
const IS_LINEAR = 1 << 3;
// Any of these flags being set prevent field reordering optimisation.
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits |
ReprFlags::IS_PACKED.bits |
ReprFlags::IS_SIMD.bits |
ReprFlags::IS_LINEAR.bits;
}
......@@ -1648,11 +1646,13 @@ pub struct ReprFlags: u8 {
pub struct ReprOptions {
pub int: Option<attr::IntType>,
pub align: u32,
pub pack: u32,
pub flags: ReprFlags,
}
impl_stable_hash_for!(struct ReprOptions {
align,
pack,
int,
flags
});
......@@ -1662,11 +1662,19 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
let mut flags = ReprFlags::empty();
let mut size = None;
let mut max_align = 0;
let mut min_pack = 0;
for attr in tcx.get_attrs(did).iter() {
for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
flags.insert(match r {
attr::ReprC => ReprFlags::IS_C,
attr::ReprPacked => ReprFlags::IS_PACKED,
attr::ReprPacked(pack) => {
min_pack = if min_pack > 0 {
cmp::min(pack, min_pack)
} else {
pack
};
ReprFlags::empty()
},
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
attr::ReprSimd => ReprFlags::IS_SIMD,
attr::ReprInt(i) => {
......@@ -1685,7 +1693,7 @@ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) {
flags.insert(ReprFlags::IS_LINEAR);
}
ReprOptions { int: size, align: max_align, flags: flags }
ReprOptions { int: size, align: max_align, pack: min_pack, flags: flags }
}
#[inline]
......@@ -1693,7 +1701,7 @@ pub fn simd(&self) -> bool { self.flags.contains(ReprFlags::IS_SIMD) }
#[inline]
pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) }
#[inline]
pub fn packed(&self) -> bool { self.flags.contains(ReprFlags::IS_PACKED) }
pub fn packed(&self) -> bool { self.pack > 0 }
#[inline]
pub fn transparent(&self) -> bool { self.flags.contains(ReprFlags::IS_TRANSPARENT) }
#[inline]
......@@ -1709,6 +1717,12 @@ pub fn discr_type(&self) -> attr::IntType {
pub fn inhibit_enum_layout_opt(&self) -> bool {
self.c() || self.int.is_some()
}
/// Returns true if this `#[repr()]` should inhibit struct field reordering
/// optimizations, such as with repr(C) or repr(packed(1)).
pub fn inhibit_struct_field_reordering_opt(&self) -> bool {
!(self.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty() || (self.pack == 1)
}
}
impl<'a, 'gcx, 'tcx> AdtDef {
......
......@@ -1553,8 +1553,19 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
}
fn check_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId) {
if tcx.adt_def(def_id).repr.packed() {
if tcx.adt_def(def_id).repr.align > 0 {
let repr = tcx.adt_def(def_id).repr;
if repr.packed() {
for attr in tcx.get_attrs(def_id).iter() {
for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
if let attr::ReprPacked(pack) = r {
if pack != repr.pack {
struct_span_err!(tcx.sess, sp, E0634,
"type has conflicting packed representation hints").emit();
}
}
}
}
if repr.align > 0 {
struct_span_err!(tcx.sess, sp, E0587,
"type has conflicting packed and align representation hints").emit();
}
......
......@@ -4836,14 +4836,15 @@ fn is_null(self: *const Self) -> bool {
// E0563, // cannot determine a type for this `impl Trait`: {} // removed in 6383de15
E0564, // only named lifetimes are allowed in `impl Trait`,
// but `{}` was found in the type `{}`
E0587, // struct has conflicting packed and align representation hints
E0588, // packed struct cannot transitively contain a `[repr(align)]` struct
E0587, // type has conflicting packed and align representation hints
E0588, // packed type cannot transitively contain a `[repr(align)]` type
E0592, // duplicate definitions with name `{}`
// E0613, // Removed (merged with E0609)
E0640, // infer outlives
E0627, // yield statement outside of generator literal
E0632, // cannot provide explicit type parameters when `impl Trait` is used in
// argument position.
E0634, // type has conflicting packed representaton hints
E0641, // cannot cast to/from a pointer with an unknown kind
E0645, // trait aliases not finished
E0907, // type inside generator must be known in this context
......
......@@ -993,7 +993,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
let word = &*mi.ident.name.as_str();
let hint = match word {
"C" => Some(ReprC),
"packed" => Some(ReprPacked),
"packed" => Some(ReprPacked(1)),
"simd" => Some(ReprSimd),
"transparent" => Some(ReprTransparent),
_ => match int_type_of_word(word) {
......@@ -1009,27 +1009,41 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr>
acc.push(h);
}
} else if let Some((name, value)) = item.name_value_literal() {
if name == "align" {
recognised = true;
let mut align_error = None;
if let ast::LitKind::Int(align, ast::LitIntType::Unsuffixed) = value.node {
if align.is_power_of_two() {
let parse_alignment = |node: &ast::LitKind| -> Result<u32, &'static str> {
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
if literal.is_power_of_two() {
// rustc::ty::layout::Align restricts align to <= 2147483647
if align <= 2147483647 {
acc.push(ReprAlign(align as u32));
if *literal <= 2147483647 {
Ok(*literal as u32)
} else {
align_error = Some("larger than 2147483647");
Err("larger than 2147483647")
}
} else {
align_error = Some("not a power of two");
Err("not a power of two")
}
} else {
align_error = Some("not an unsuffixed integer");
}
if let Some(align_error) = align_error {
span_err!(diagnostic, item.span, E0589,
"invalid `repr(align)` attribute: {}", align_error);
Err("not an unsuffixed integer")
}
};
let mut literal_error = None;
if name == "align" {
recognised = true;
match parse_alignment(&value.node) {
Ok(literal) => acc.push(ReprAlign(literal)),
Err(message) => literal_error = Some(message)
};
}
else if name == "packed" {
recognised = true;
match parse_alignment(&value.node) {
Ok(literal) => acc.push(ReprPacked(literal)),
Err(message) => literal_error = Some(message)
};
}
if let Some(literal_error) = literal_error {
span_err!(diagnostic, item.span, E0589,
"invalid `repr(align)` attribute: {}", literal_error);
}
}
if !recognised {
......@@ -1065,7 +1079,7 @@ fn int_type_of_word(s: &str) -> Option<IntType> {
pub enum ReprAttr {
ReprInt(IntType),
ReprC,
ReprPacked,
ReprPacked(u32),
ReprSimd,
ReprTransparent,
ReprAlign(u32),
......
......@@ -432,6 +432,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
// Parentheses in patterns
(active, pattern_parentheses, "1.26.0", None, None),
// Allows `#[repr(packed)]` attribute on structs
(active, repr_packed, "1.26.0", Some(33158), None),
// `use path as _;` and `extern crate c as _;`
(active, underscore_imports, "1.26.0", Some(48216), None),
......@@ -1439,11 +1442,12 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
}
}
// allow attr_literals in #[repr(align(x))]
let mut is_repr_align = false;
// allow attr_literals in #[repr(align(x))] and #[repr(packed(n))]
let mut allow_attr_literal = false;
if attr.path == "repr" {
if let Some(content) = attr.meta_item_list() {
is_repr_align = content.iter().any(|c| c.check_name("align"));
allow_attr_literal = content.iter().any(
|c| c.check_name("align") || c.check_name("packed"));
}
}
......@@ -1451,7 +1455,7 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
return
}
if !is_repr_align {
if !allow_attr_literal {
let meta = panictry!(attr.parse_meta(self.context.parse_sess));
if contains_novel_literal(&meta) {
gate_feature_post!(&self, attr_literals, attr.span,
......@@ -1535,6 +1539,13 @@ fn visit_item(&mut self, i: &'a ast::Item) {
"the `#[repr(transparent)]` attribute \
is experimental");
}
if let Some((name, _)) = item.name_value_literal() {
if name == "packed" {
gate_feature_post!(&self, repr_packed, attr.span,
"the `#[repr(packed(n))]` attribute \
is experimental");
}
}
}
}
}
......
......@@ -413,8 +413,12 @@ pub fn expand_ext(self,
match *item {
Annotatable::Item(ref item) => {
let is_packed = item.attrs.iter().any(|attr| {
attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr)
.contains(&attr::ReprPacked)
for r in attr::find_repr_attrs(&cx.parse_sess.span_diagnostic, attr) {
if let attr::ReprPacked(_) = r {
return true;
}
}
false
});
let has_no_type_params = match item.node {
ast::ItemKind::Struct(_, ref generics) |
......@@ -831,7 +835,7 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> &
for a in type_attrs {
for r in &attr::find_repr_attrs(diagnostic, a) {
repr_type_name = match *r {
attr::ReprPacked | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent =>
attr::ReprPacked(_) | attr::ReprSimd | attr::ReprAlign(_) | attr::ReprTransparent =>
continue,
attr::ReprC => "i32",
......
......@@ -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
}
#[repr(packed(2))]
pub struct BigPacked2 {
dealign: u8,
data: Array
}
// CHECK-LABEL: @call_pkd
// 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));
#[repr(packed(2))]
#[derive(Copy, Clone)]
pub struct Packed2NestedPair((u32, u32));
// CHECK-LABEL: @pkd_nested_pair
// 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 @@ enum D { D }
#[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
}
// 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
}
#[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() {
assert_eq!(mem::size_of::<S<u8, u8>>(), 3);
check!(P1::<u8, u8>, 1, 3);
check!(P1::<u64, u16>, 1, 11);
check!(P2::<u8, u8>, 1, 3);
check!(P2::<u64, u16>, 2, 12);
assert_eq!(mem::size_of::<S<u64, u16>>(), 11);
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 @@
use std::mem;
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::<packed::S>(), 5);
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
pub fn main() {
let foos = [Foo { bar: 1, baz: 2 }; 10];
let foo1s = [Foo1 { bar: 1, baz: 2 }; 10];
assert_eq!(mem::align_of::<[Foo1; 10]>(), 1);
assert_eq!(mem::size_of::<[Foo1; 10]>(), 90);
for i in 0..10 {
assert_eq!(foo1s[i], Foo1 { 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::size_of::<[Foo; 10]>(), 90);
assert_eq!(mem::align_of::<[Foo4C; 10]>(), 4);
assert_eq!(mem::size_of::<[Foo4C; 10]>(), 120);
for i in 0..10 {
assert_eq!(foos[i], Foo { bar: 1, baz: 2});
assert_eq!(foo4s[i], Foo4C { bar: 1, baz: 2});
}
for &foo in &foos {
assert_eq!(foo, Foo { 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>>);
pub fn main() {
assert_eq!(mem::size_of::<S4>(), 4);
#[repr(packed(2))]
struct P2_Option(Option<Box<f64>>);
#[repr(packed(2))]
struct P2S7_Option(f32, u8, u16, Option<Box<f64>>);
assert_eq!(mem::size_of::<S5>(), 5);
fn align_to(value: usize, align: usize) -> usize {
(value + (align - 1)) & !(align - 1)
}
assert_eq!(mem::size_of::<S13>(), 13);
macro_rules! check {
($t:ty, $align:expr, $size:expr) => ({
assert_eq!(mem::align_of::<$t>(), $align);
assert_eq!(mem::size_of::<$t>(), $size);
});
}
assert_eq!(mem::size_of::<S3_Foo>(),
3 + mem::size_of::<Foo>());
pub fn main() {
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::<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 @@ struct S2 {
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);
}
}
// 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() {}
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
}
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册