Move a method used everywhere out of intrinsic.rs
This commit is contained in:
parent
e15d374dda
commit
df7c42bcc8
2 changed files with 96 additions and 102 deletions
|
@ -7,7 +7,7 @@ use rustc::middle::const_val::ConstVal;
|
|||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::mir;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::layout::{self, Layout, Size};
|
||||
use rustc::ty::layout::{self, Layout, Size, Align};
|
||||
use rustc::ty::subst::{Subst, Substs, Kind};
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
|
||||
use rustc::traits;
|
||||
|
@ -277,6 +277,98 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
self.tcx.erase_regions(&value)
|
||||
}
|
||||
|
||||
pub fn size_and_align_of_dst(
|
||||
&mut self,
|
||||
ty: ty::Ty<'tcx>,
|
||||
value: Value,
|
||||
) -> EvalResult<'tcx, (u64, u64)> {
|
||||
if let Some(size) = self.type_size(ty)? {
|
||||
Ok((size as u64, self.type_align(ty)? as u64))
|
||||
} else {
|
||||
match ty.sty {
|
||||
ty::TyAdt(def, substs) => {
|
||||
// First get the size of all statically known fields.
|
||||
// Don't use type_of::sizing_type_of because that expects t to be sized,
|
||||
// and it also rounds up to alignment, which we want to avoid,
|
||||
// as the unsized field's alignment could be smaller.
|
||||
assert!(!ty.is_simd());
|
||||
let layout = self.type_layout(ty)?;
|
||||
debug!("DST {} layout: {:?}", ty, layout);
|
||||
|
||||
let (sized_size, sized_align) = match *layout {
|
||||
ty::layout::Layout::Univariant { ref variant, .. } => {
|
||||
(variant.offsets.last().map_or(0, |o| o.bytes()), variant.align)
|
||||
}
|
||||
_ => {
|
||||
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
|
||||
ty, layout);
|
||||
}
|
||||
};
|
||||
debug!("DST {} statically sized prefix size: {} align: {:?}",
|
||||
ty, sized_size, sized_align);
|
||||
|
||||
// Recurse to get the size of the dynamically sized field (must be
|
||||
// the last field).
|
||||
let last_field = def.struct_variant().fields.last().unwrap();
|
||||
let field_ty = self.field_ty(substs, last_field);
|
||||
let (unsized_size, unsized_align) = self.size_and_align_of_dst(field_ty, value)?;
|
||||
|
||||
// FIXME (#26403, #27023): We should be adding padding
|
||||
// to `sized_size` (to accommodate the `unsized_align`
|
||||
// required of the unsized field that follows) before
|
||||
// summing it with `sized_size`. (Note that since #26403
|
||||
// is unfixed, we do not yet add the necessary padding
|
||||
// here. But this is where the add would go.)
|
||||
|
||||
// Return the sum of sizes and max of aligns.
|
||||
let size = sized_size + unsized_size;
|
||||
|
||||
// Choose max of two known alignments (combined value must
|
||||
// be aligned according to more restrictive of the two).
|
||||
let align = sized_align.max(Align::from_bytes(unsized_align, unsized_align).unwrap());
|
||||
|
||||
// Issue #27023: must add any necessary padding to `size`
|
||||
// (to make it a multiple of `align`) before returning it.
|
||||
//
|
||||
// Namely, the returned size should be, in C notation:
|
||||
//
|
||||
// `size + ((size & (align-1)) ? align : 0)`
|
||||
//
|
||||
// emulated via the semi-standard fast bit trick:
|
||||
//
|
||||
// `(size + (align-1)) & -align`
|
||||
|
||||
let size = Size::from_bytes(size).abi_align(align).bytes();
|
||||
Ok((size, align.abi()))
|
||||
}
|
||||
ty::TyDynamic(..) => {
|
||||
let (_, vtable) = value.into_ptr_vtable_pair(&mut self.memory)?;
|
||||
// the second entry in the vtable is the dynamic size of the object.
|
||||
self.read_size_and_align_from_vtable(vtable)
|
||||
}
|
||||
|
||||
ty::TySlice(_) | ty::TyStr => {
|
||||
let elem_ty = ty.sequence_element_type(self.tcx);
|
||||
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64;
|
||||
let (_, len) = value.into_slice(&mut self.memory)?;
|
||||
let align = self.type_align(elem_ty)?;
|
||||
Ok((len * elem_size, align as u64))
|
||||
}
|
||||
|
||||
_ => bug!("size_of_val::<{:?}>", ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the normalized type of a struct field
|
||||
fn field_ty(
|
||||
&self,
|
||||
param_substs: &Substs<'tcx>,
|
||||
f: &ty::FieldDef,
|
||||
) -> ty::Ty<'tcx> {
|
||||
self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs))
|
||||
}
|
||||
|
||||
pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
|
||||
self.type_size_with_substs(ty, self.substs())
|
||||
}
|
||||
|
@ -1556,8 +1648,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
let dest = self.force_allocation(dest)?.to_ptr()?;
|
||||
let iter = src_fields.zip(dst_fields).enumerate();
|
||||
for (i, (src_f, dst_f)) in iter {
|
||||
let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
|
||||
let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
|
||||
let src_fty = self.field_ty(substs_a, src_f);
|
||||
let dst_fty = self.field_ty(substs_b, dst_f);
|
||||
if self.type_size(dst_fty)? == Some(0) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1726,12 +1818,6 @@ impl IntegerExt for layout::Integer {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn monomorphize_field_ty<'a, 'tcx:'a >(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: &ty::FieldDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
|
||||
let substituted = f.ty(tcx, substs);
|
||||
tcx.normalize_associated_type(&substituted)
|
||||
}
|
||||
|
||||
pub fn is_inhabited<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
ty.uninhabited_from(&mut HashMap::default(), tcx).is_empty()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use rustc::mir;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::layout::{Layout, Size, Align};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc::ty::layout::Layout;
|
||||
use rustc::ty::{self, Ty};
|
||||
|
||||
use interpret::{
|
||||
|
@ -487,97 +486,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
// current frame.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn size_and_align_of_dst(
|
||||
&mut self,
|
||||
ty: ty::Ty<'tcx>,
|
||||
value: Value,
|
||||
) -> EvalResult<'tcx, (u64, u64)> {
|
||||
if let Some(size) = self.type_size(ty)? {
|
||||
Ok((size as u64, self.type_align(ty)? as u64))
|
||||
} else {
|
||||
match ty.sty {
|
||||
ty::TyAdt(def, substs) => {
|
||||
// First get the size of all statically known fields.
|
||||
// Don't use type_of::sizing_type_of because that expects t to be sized,
|
||||
// and it also rounds up to alignment, which we want to avoid,
|
||||
// as the unsized field's alignment could be smaller.
|
||||
assert!(!ty.is_simd());
|
||||
let layout = self.type_layout(ty)?;
|
||||
debug!("DST {} layout: {:?}", ty, layout);
|
||||
|
||||
let (sized_size, sized_align) = match *layout {
|
||||
ty::layout::Layout::Univariant { ref variant, .. } => {
|
||||
(variant.offsets.last().map_or(0, |o| o.bytes()), variant.align)
|
||||
}
|
||||
_ => {
|
||||
bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}",
|
||||
ty, layout);
|
||||
}
|
||||
};
|
||||
debug!("DST {} statically sized prefix size: {} align: {:?}",
|
||||
ty, sized_size, sized_align);
|
||||
|
||||
// Recurse to get the size of the dynamically sized field (must be
|
||||
// the last field).
|
||||
let last_field = def.struct_variant().fields.last().unwrap();
|
||||
let field_ty = self.field_ty(substs, last_field);
|
||||
let (unsized_size, unsized_align) = self.size_and_align_of_dst(field_ty, value)?;
|
||||
|
||||
// FIXME (#26403, #27023): We should be adding padding
|
||||
// to `sized_size` (to accommodate the `unsized_align`
|
||||
// required of the unsized field that follows) before
|
||||
// summing it with `sized_size`. (Note that since #26403
|
||||
// is unfixed, we do not yet add the necessary padding
|
||||
// here. But this is where the add would go.)
|
||||
|
||||
// Return the sum of sizes and max of aligns.
|
||||
let size = sized_size + unsized_size;
|
||||
|
||||
// Choose max of two known alignments (combined value must
|
||||
// be aligned according to more restrictive of the two).
|
||||
let align = sized_align.max(Align::from_bytes(unsized_align, unsized_align).unwrap());
|
||||
|
||||
// Issue #27023: must add any necessary padding to `size`
|
||||
// (to make it a multiple of `align`) before returning it.
|
||||
//
|
||||
// Namely, the returned size should be, in C notation:
|
||||
//
|
||||
// `size + ((size & (align-1)) ? align : 0)`
|
||||
//
|
||||
// emulated via the semi-standard fast bit trick:
|
||||
//
|
||||
// `(size + (align-1)) & -align`
|
||||
|
||||
let size = Size::from_bytes(size).abi_align(align).bytes();
|
||||
Ok((size, align.abi()))
|
||||
}
|
||||
ty::TyDynamic(..) => {
|
||||
let (_, vtable) = value.into_ptr_vtable_pair(&self.memory)?;
|
||||
// the second entry in the vtable is the dynamic size of the object.
|
||||
self.read_size_and_align_from_vtable(vtable)
|
||||
}
|
||||
|
||||
ty::TySlice(_) | ty::TyStr => {
|
||||
let elem_ty = ty.sequence_element_type(self.tcx);
|
||||
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64;
|
||||
let (_, len) = value.into_slice(&self.memory)?;
|
||||
let align = self.type_align(elem_ty)?;
|
||||
Ok((len * elem_size, align as u64))
|
||||
}
|
||||
|
||||
_ => bug!("size_of_val::<{:?}>", ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Returns the normalized type of a struct field
|
||||
fn field_ty(
|
||||
&self,
|
||||
param_substs: &Substs<'tcx>,
|
||||
f: &ty::FieldDef,
|
||||
) -> ty::Ty<'tcx> {
|
||||
self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs))
|
||||
}
|
||||
}
|
||||
|
||||
fn numeric_intrinsic<'tcx>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue