diff --git a/example/dst-field-align.rs b/example/dst-field-align.rs new file mode 100644 index 000000000000..6c338e99912e --- /dev/null +++ b/example/dst-field-align.rs @@ -0,0 +1,67 @@ +// run-pass +#![allow(dead_code)] +struct Foo { + a: u16, + b: T +} + +trait Bar { + fn get(&self) -> usize; +} + +impl Bar for usize { + fn get(&self) -> usize { *self } +} + +struct Baz { + a: T +} + +struct HasDrop { + ptr: Box, + data: T +} + +fn main() { + // Test that zero-offset works properly + let b : Baz = Baz { a: 7 }; + assert_eq!(b.a.get(), 7); + let b : &Baz = &b; + assert_eq!(b.a.get(), 7); + + // Test that the field is aligned properly + let f : Foo = Foo { a: 0, b: 11 }; + assert_eq!(f.b.get(), 11); + let ptr1 : *const u8 = &f.b as *const _ as *const u8; + + let f : &Foo = &f; + let ptr2 : *const u8 = &f.b as *const _ as *const u8; + assert_eq!(f.b.get(), 11); + + // The pointers should be the same + assert_eq!(ptr1, ptr2); + + // Test that nested DSTs work properly + let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; + assert_eq!(f.b.b.get(), 17); + let f : &Foo> = &f; + assert_eq!(f.b.b.get(), 17); + + // Test that get the pointer via destructuring works + + let f : Foo = Foo { a: 0, b: 11 }; + let f : &Foo = &f; + let &Foo { a: _, b: ref bar } = f; + assert_eq!(bar.get(), 11); + + // Make sure that drop flags don't screw things up + + let d : HasDrop> = HasDrop { + ptr: Box::new(0), + data: Baz { a: [1,2,3,4] } + }; + assert_eq!([1,2,3,4], d.data.a); + + let d : &HasDrop> = &d; + assert_eq!(&[1,2,3,4], &d.data.a); +} diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 09db4b144002..d6ae021a44d5 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -3,18 +3,54 @@ use crate::prelude::*; fn codegen_field<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Backend>, base: Value, + extra: Option, layout: TyLayout<'tcx>, field: mir::Field, ) -> (Value, TyLayout<'tcx>) { let field_offset = layout.fields.offset(field.index()); - let field_ty = layout.field(&*fx, field.index()); - if field_offset.bytes() > 0 { - ( - fx.bcx.ins().iadd_imm(base, field_offset.bytes() as i64), - field_ty, - ) + let field_layout = layout.field(&*fx, field.index()); + + let simple = |fx: &mut FunctionCx<_>| { + if field_offset.bytes() > 0 { + ( + fx.bcx.ins().iadd_imm(base, field_offset.bytes() as i64), + field_layout, + ) + } else { + (base, field_layout) + } + }; + + if let Some(extra) = extra { + if !field_layout.is_unsized() { + return simple(fx); + } + match field_layout.ty.sty { + ty::Slice(..) | ty::Str | ty::Foreign(..) => return simple(fx), + ty::Adt(def, _) if def.repr.packed() => { + assert_eq!(layout.align.abi.bytes(), 1); + return simple(fx); + } + _ => { + // We have to align the offset for DST's + let unaligned_offset = field_offset.bytes(); + let (_, unsized_align) = crate::unsize::size_and_align_of_dst(fx, field_layout.ty, extra); + + let one = fx.bcx.ins().iconst(pointer_ty(fx.tcx), 1); + let align_sub_1 = fx.bcx.ins().isub(unsized_align, one); + let and_lhs = fx.bcx.ins().iadd_imm(align_sub_1, unaligned_offset as i64); + let zero = fx.bcx.ins().iconst(pointer_ty(fx.tcx), 0); + let and_rhs = fx.bcx.ins().isub(zero, unsized_align); + let offset = fx.bcx.ins().band(and_lhs, and_rhs); + + ( + fx.bcx.ins().iadd(base, offset), + field_layout, + ) + } + } } else { - (base, field_ty) + simple(fx) } } @@ -125,7 +161,7 @@ impl<'tcx> CValue<'tcx> { _ => bug!("place_field for {:?}", self), }; - let (field_ptr, field_layout) = codegen_field(fx, base, layout, field); + let (field_ptr, field_layout) = codegen_field(fx, base, None, layout, field); CValue::by_ref(field_ptr, field_layout) } @@ -431,7 +467,7 @@ impl<'tcx> CPlace<'tcx> { let layout = self.layout(); let (base, extra) = self.to_addr_maybe_unsized(fx); - let (field_ptr, field_layout) = codegen_field(fx, base, layout, field); + let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field); if field_layout.is_unsized() { CPlace::for_addr_with_extra(field_ptr, extra.unwrap(), field_layout) } else { diff --git a/test.sh b/test.sh index 3b390c386d22..532a96945a62 100755 --- a/test.sh +++ b/test.sh @@ -50,6 +50,10 @@ $RUSTC example/alloc_example.rs --crate-type bin jit std_example example/std_example.rs +echo "[AOT] dst_field_align" +$RUSTC example/dst-field-align.rs -Zmir-opt-level=2 --crate-name dst_field_align --crate-type bin +./target/out/dst_field_align + echo "[AOT] std_example" $RUSTC example/std_example.rs --crate-type bin ./target/out/std_example