mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-18 18:04:13 +00:00
rustc_codegen_llvm: don't assume offsets are always aligned.
This commit is contained in:
parent
27e5457f3f
commit
b9e7574bf2
@ -174,7 +174,10 @@ impl PlaceRef<'ll, 'tcx> {
|
||||
let cx = bx.cx;
|
||||
let field = self.layout.field(cx, ix);
|
||||
let offset = self.layout.fields.offset(ix);
|
||||
let align = self.align.min(self.layout.align).min(field.align);
|
||||
let effective_field_align = self.align
|
||||
.min(self.layout.align)
|
||||
.min(field.align)
|
||||
.restrict_for_offset(offset);
|
||||
|
||||
let simple = || {
|
||||
// Unions and newtypes only use an offset of 0.
|
||||
@ -196,7 +199,7 @@ impl PlaceRef<'ll, 'tcx> {
|
||||
None
|
||||
},
|
||||
layout: field,
|
||||
align,
|
||||
align: effective_field_align,
|
||||
}
|
||||
};
|
||||
|
||||
@ -269,7 +272,7 @@ impl PlaceRef<'ll, 'tcx> {
|
||||
llval: bx.pointercast(byte_ptr, ll_fty.ptr_to()),
|
||||
llextra: self.llextra,
|
||||
layout: field,
|
||||
align,
|
||||
align: effective_field_align,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,25 +122,29 @@ fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
|
||||
let mut packed = false;
|
||||
let mut offset = Size::ZERO;
|
||||
let mut prev_align = layout.align;
|
||||
let mut prev_effective_align = layout.align;
|
||||
let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
|
||||
for i in layout.fields.index_by_increasing_offset() {
|
||||
let field = layout.field(cx, i);
|
||||
packed |= layout.align.abi() < field.align.abi();
|
||||
|
||||
let target_offset = layout.fields.offset(i as usize);
|
||||
debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}",
|
||||
i, field, offset, target_offset);
|
||||
let field = layout.field(cx, i);
|
||||
let effective_field_align = layout.align
|
||||
.min(field.align)
|
||||
.restrict_for_offset(target_offset);
|
||||
packed |= effective_field_align.abi() < field.align.abi();
|
||||
|
||||
debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?} \
|
||||
effective_field_align: {}",
|
||||
i, field, offset, target_offset, effective_field_align.abi());
|
||||
assert!(target_offset >= offset);
|
||||
let padding = target_offset - offset;
|
||||
let padding_align = layout.align.min(prev_align).min(field.align);
|
||||
let padding_align = prev_effective_align.min(effective_field_align);
|
||||
assert_eq!(offset.abi_align(padding_align) + padding, target_offset);
|
||||
result.push(Type::padding_filler(cx, padding, padding_align));
|
||||
debug!(" padding before: {:?}", padding);
|
||||
|
||||
result.push(field.llvm_type(cx));
|
||||
offset = target_offset + field.size;
|
||||
prev_align = field.align;
|
||||
prev_effective_align = effective_field_align;
|
||||
}
|
||||
if !layout.is_unsized() && field_count > 0 {
|
||||
if offset > layout.size {
|
||||
@ -148,7 +152,7 @@ fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
|
||||
layout, layout.size, offset);
|
||||
}
|
||||
let padding = layout.size - offset;
|
||||
let padding_align = layout.align.min(prev_align);
|
||||
let padding_align = prev_effective_align;
|
||||
assert_eq!(offset.abi_align(padding_align) + padding, layout.size);
|
||||
debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
|
||||
padding, offset, layout.size);
|
||||
|
@ -416,6 +416,24 @@ impl Align {
|
||||
pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the best alignment possible for the given offset
|
||||
/// (the largest power of two that the offset is a multiple of).
|
||||
///
|
||||
/// NB: for an offset of `0`, this happens to return `2^64`.
|
||||
pub fn max_for_offset(offset: Size) -> Align {
|
||||
let pow2 = offset.bytes().trailing_zeros() as u8;
|
||||
Align {
|
||||
abi_pow2: pow2,
|
||||
pref_pow2: pow2,
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower the alignment, if necessary, such that the given offset
|
||||
/// is aligned to it (the offset is a multiple of the aligment).
|
||||
pub fn restrict_for_offset(self, offset: Size) -> Align {
|
||||
self.min(Align::max_for_offset(offset))
|
||||
}
|
||||
}
|
||||
|
||||
/// Integers, also used for enum discriminants.
|
||||
|
26
src/test/run-pass/issue-53728.rs
Normal file
26
src/test/run-pass/issue-53728.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// 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(u16)]
|
||||
enum DeviceKind {
|
||||
Nil = 0,
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
struct DeviceInfo {
|
||||
endianness: u8,
|
||||
device_kind: DeviceKind,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _x = None::<(DeviceInfo, u8)>;
|
||||
let _y = None::<(DeviceInfo, u16)>;
|
||||
let _z = None::<(DeviceInfo, u64)>;
|
||||
}
|
Loading…
Reference in New Issue
Block a user