From 1844381ad024f322f7427d03ac261d131eb0e86b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Feb 2017 08:38:01 +0100 Subject: [PATCH 1/2] compute the offset of dst fields by checking the vtable --- src/lvalue.rs | 11 ++++++++++- src/terminator/intrinsic.rs | 2 +- tests/run-pass/dst-field-align.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/run-pass/dst-field-align.rs diff --git a/src/lvalue.rs b/src/lvalue.rs index d54c27904763c..2cce67689d72e 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -214,7 +214,16 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { _ => bug!("field access on non-product type: {:?}", base_layout), }; - let ptr = base_ptr.offset(offset.bytes()); + let offset = match base_extra { + LvalueExtra::Vtable(tab) => { + let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(PrimVal::Ptr(base_ptr), PrimVal::Ptr(tab)))?; + // magical formula taken from rustc + (offset.bytes() + (align - 1)) & (-(align as i64) as u64) + } + _ => offset.bytes(), + }; + + let ptr = base_ptr.offset(offset); if packed { let size = self.type_size(field_ty)?.expect("packed struct must be sized"); diff --git a/src/terminator/intrinsic.rs b/src/terminator/intrinsic.rs index 811ae7888d729..44a636997d952 100644 --- a/src/terminator/intrinsic.rs +++ b/src/terminator/intrinsic.rs @@ -405,7 +405,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { Ok(()) } - fn size_and_align_of_dst( + pub fn size_and_align_of_dst( &self, ty: ty::Ty<'tcx>, value: Value, diff --git a/tests/run-pass/dst-field-align.rs b/tests/run-pass/dst-field-align.rs new file mode 100644 index 0000000000000..ce3fb82cb3f28 --- /dev/null +++ b/tests/run-pass/dst-field-align.rs @@ -0,0 +1,30 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +struct Foo { + a: u16, + b: T +} + +trait Bar { + fn get(&self) -> usize; +} + +impl Bar for usize { + fn get(&self) -> usize { *self } +} + +fn main() { + let f : Foo = Foo { a: 0, b: 11 }; + let f : &Foo = &f; + assert_eq!(f.b.get(), 11); +} From 8030800b15931f50dbe8944addc1afb4c3750a67 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 9 Feb 2017 08:50:35 +0100 Subject: [PATCH 2/2] use pre-existing `abi_align` method instead of magic formula --- src/lvalue.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lvalue.rs b/src/lvalue.rs index 2cce67689d72e..e86c480aa0b66 100644 --- a/src/lvalue.rs +++ b/src/lvalue.rs @@ -1,6 +1,6 @@ use rustc::hir::def_id::DefId; use rustc::mir; -use rustc::ty::layout::Size; +use rustc::ty::layout::{Size, Align}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; use rustc_data_structures::indexed_vec::Idx; @@ -217,8 +217,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { let offset = match base_extra { LvalueExtra::Vtable(tab) => { let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(PrimVal::Ptr(base_ptr), PrimVal::Ptr(tab)))?; - // magical formula taken from rustc - (offset.bytes() + (align - 1)) & (-(align as i64) as u64) + offset.abi_align(Align::from_bytes(align, align).unwrap()).bytes() } _ => offset.bytes(), };