Skip to content

Commit 2c41369

Browse files
committed
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.
2 parents 1623978 + 83a5a69 commit 2c41369

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

compiler/rustc_codegen_ssa/src/mir/operand.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
402402
indirect_dest: PlaceRef<'tcx, V>,
403403
) {
404404
debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
405-
let flags = MemFlags::empty();
406-
407405
// `indirect_dest` must have `*mut T` type. We extract `T` out of it.
408406
let unsized_ty = indirect_dest
409407
.layout
@@ -416,17 +414,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
416414
bug!("store_unsized called with a sized value")
417415
};
418416

419-
// FIXME: choose an appropriate alignment, or use dynamic align somehow
420-
let max_align = Align::from_bits(128).unwrap();
421-
let min_align = Align::from_bits(8).unwrap();
422-
423-
// Allocate an appropriate region on the stack, and copy the value into it
424-
let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
425-
let lldst = bx.byte_array_alloca(llsize, max_align);
426-
bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags);
417+
// Allocate an appropriate region on the stack, and copy the value into it. Since alloca
418+
// doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
419+
// pointer manually.
420+
let (size, align) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
421+
let one = bx.const_usize(1);
422+
let align_minus_1 = bx.sub(align, one);
423+
let size_extra = bx.add(size, align_minus_1);
424+
let min_align = Align::ONE;
425+
let alloca = bx.byte_array_alloca(size_extra, min_align);
426+
let address = bx.ptrtoint(alloca, bx.type_isize());
427+
let neg_address = bx.neg(address);
428+
let offset = bx.and(neg_address, align_minus_1);
429+
let dst = bx.inbounds_gep(bx.type_i8(), alloca, &[offset]);
430+
bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty());
427431

428432
// Store the allocated region and the extra to the indirect place.
429-
let indirect_operand = OperandValue::Pair(lldst, llextra);
433+
let indirect_operand = OperandValue::Pair(dst, llextra);
430434
indirect_operand.store(bx, indirect_dest);
431435
}
432436
}

tests/ui/unsized-locals/align.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Test that unsized locals uphold alignment requirements.
2+
// Regression test for #71416.
3+
// run-pass
4+
#![feature(unsized_locals)]
5+
#![allow(incomplete_features)]
6+
use std::any::Any;
7+
8+
#[repr(align(256))]
9+
#[allow(dead_code)]
10+
struct A {
11+
v: u8
12+
}
13+
14+
impl A {
15+
fn f(&self) -> *const A {
16+
assert_eq!(self as *const A as usize % 256, 0);
17+
self
18+
}
19+
}
20+
21+
fn mk() -> Box<dyn Any> {
22+
Box::new(A { v: 4 })
23+
}
24+
25+
fn main() {
26+
let x = *mk();
27+
let dwncst = x.downcast_ref::<A>().unwrap();
28+
let addr = dwncst.f();
29+
assert_eq!(addr as usize % 256, 0);
30+
}

0 commit comments

Comments
 (0)