Align unsized locals
Allocate an extra space for unsized locals and manually align the storage, since alloca doesn't support dynamic alignment.
This commit is contained in:
parent
ce042889f7
commit
83a5a69a4c
2 changed files with 45 additions and 11 deletions
|
@ -402,8 +402,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
|
||||||
indirect_dest: PlaceRef<'tcx, V>,
|
indirect_dest: PlaceRef<'tcx, V>,
|
||||||
) {
|
) {
|
||||||
debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
|
debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
|
||||||
let flags = MemFlags::empty();
|
|
||||||
|
|
||||||
// `indirect_dest` must have `*mut T` type. We extract `T` out of it.
|
// `indirect_dest` must have `*mut T` type. We extract `T` out of it.
|
||||||
let unsized_ty = indirect_dest
|
let unsized_ty = indirect_dest
|
||||||
.layout
|
.layout
|
||||||
|
@ -416,17 +414,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
|
||||||
bug!("store_unsized called with a sized value")
|
bug!("store_unsized called with a sized value")
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: choose an appropriate alignment, or use dynamic align somehow
|
// Allocate an appropriate region on the stack, and copy the value into it. Since alloca
|
||||||
let max_align = Align::from_bits(128).unwrap();
|
// doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
|
||||||
let min_align = Align::from_bits(8).unwrap();
|
// pointer manually.
|
||||||
|
let (size, align) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
|
||||||
// Allocate an appropriate region on the stack, and copy the value into it
|
let one = bx.const_usize(1);
|
||||||
let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
|
let align_minus_1 = bx.sub(align, one);
|
||||||
let lldst = bx.byte_array_alloca(llsize, max_align);
|
let size_extra = bx.add(size, align_minus_1);
|
||||||
bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags);
|
let min_align = Align::ONE;
|
||||||
|
let alloca = bx.byte_array_alloca(size_extra, min_align);
|
||||||
|
let address = bx.ptrtoint(alloca, bx.type_isize());
|
||||||
|
let neg_address = bx.neg(address);
|
||||||
|
let offset = bx.and(neg_address, align_minus_1);
|
||||||
|
let dst = bx.inbounds_gep(bx.type_i8(), alloca, &[offset]);
|
||||||
|
bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty());
|
||||||
|
|
||||||
// Store the allocated region and the extra to the indirect place.
|
// Store the allocated region and the extra to the indirect place.
|
||||||
let indirect_operand = OperandValue::Pair(lldst, llextra);
|
let indirect_operand = OperandValue::Pair(dst, llextra);
|
||||||
indirect_operand.store(bx, indirect_dest);
|
indirect_operand.store(bx, indirect_dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
tests/ui/unsized-locals/align.rs
Normal file
30
tests/ui/unsized-locals/align.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Test that unsized locals uphold alignment requirements.
|
||||||
|
// Regression test for #71416.
|
||||||
|
// run-pass
|
||||||
|
#![feature(unsized_locals)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
#[repr(align(256))]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct A {
|
||||||
|
v: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
impl A {
|
||||||
|
fn f(&self) -> *const A {
|
||||||
|
assert_eq!(self as *const A as usize % 256, 0);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mk() -> Box<dyn Any> {
|
||||||
|
Box::new(A { v: 4 })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = *mk();
|
||||||
|
let dwncst = x.downcast_ref::<A>().unwrap();
|
||||||
|
let addr = dwncst.f();
|
||||||
|
assert_eq!(addr as usize % 256, 0);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue