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::middle::region::CodeExtent;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::traits::Reveal;
|
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::subst::{Subst, Substs, Kind};
|
||||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
|
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
|
||||||
use rustc::traits;
|
use rustc::traits;
|
||||||
|
@ -277,6 +277,98 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
self.tcx.erase_regions(&value)
|
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>> {
|
pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
|
||||||
self.type_size_with_substs(ty, self.substs())
|
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 dest = self.force_allocation(dest)?.to_ptr()?;
|
||||||
let iter = src_fields.zip(dst_fields).enumerate();
|
let iter = src_fields.zip(dst_fields).enumerate();
|
||||||
for (i, (src_f, dst_f)) in iter {
|
for (i, (src_f, dst_f)) in iter {
|
||||||
let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
|
let src_fty = self.field_ty(substs_a, src_f);
|
||||||
let dst_fty = monomorphize_field_ty(self.tcx, dst_f, substs_b);
|
let dst_fty = self.field_ty(substs_b, dst_f);
|
||||||
if self.type_size(dst_fty)? == Some(0) {
|
if self.type_size(dst_fty)? == Some(0) {
|
||||||
continue;
|
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 {
|
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()
|
ty.uninhabited_from(&mut HashMap::default(), tcx).is_empty()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::traits::Reveal;
|
use rustc::traits::Reveal;
|
||||||
use rustc::ty::layout::{Layout, Size, Align};
|
use rustc::ty::layout::Layout;
|
||||||
use rustc::ty::subst::Substs;
|
|
||||||
use rustc::ty::{self, Ty};
|
use rustc::ty::{self, Ty};
|
||||||
|
|
||||||
use interpret::{
|
use interpret::{
|
||||||
|
@ -487,97 +486,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
||||||
// current frame.
|
// current frame.
|
||||||
Ok(())
|
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>(
|
fn numeric_intrinsic<'tcx>(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue