Auto merge of #111374 - tmiasko:align-unsized-locals, r=cjgillot
Align unsized locals Allocate an extra space for unsized locals and manually align the storage, since alloca doesn't support dynamic alignment. Fixes #71416. Fixes #71695.
This commit is contained in:
commit
2c41369acc
@ -402,8 +402,6 @@ pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
||||
indirect_dest: PlaceRef<'tcx, V>,
|
||||
) {
|
||||
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.
|
||||
let unsized_ty = indirect_dest
|
||||
.layout
|
||||
@ -416,17 +414,23 @@ pub fn store_unsized<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
|
||||
bug!("store_unsized called with a sized value")
|
||||
};
|
||||
|
||||
// FIXME: choose an appropriate alignment, or use dynamic align somehow
|
||||
let max_align = Align::from_bits(128).unwrap();
|
||||
let min_align = Align::from_bits(8).unwrap();
|
||||
|
||||
// Allocate an appropriate region on the stack, and copy the value into it
|
||||
let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
|
||||
let lldst = bx.byte_array_alloca(llsize, max_align);
|
||||
bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags);
|
||||
// Allocate an appropriate region on the stack, and copy the value into it. Since alloca
|
||||
// doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
|
||||
// pointer manually.
|
||||
let (size, align) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
|
||||
let one = bx.const_usize(1);
|
||||
let align_minus_1 = bx.sub(align, one);
|
||||
let size_extra = bx.add(size, align_minus_1);
|
||||
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.
|
||||
let indirect_operand = OperandValue::Pair(lldst, llextra);
|
||||
let indirect_operand = OperandValue::Pair(dst, llextra);
|
||||
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…
Reference in New Issue
Block a user