Simplify value field access
This commit is contained in:
parent
47f37d67f1
commit
f7eedfab8e
3 changed files with 30 additions and 39 deletions
|
@ -120,7 +120,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
variant: Option<usize>,
|
variant: Option<usize>,
|
||||||
field: mir::Field,
|
field: mir::Field,
|
||||||
base_ty: Ty<'tcx>,
|
base_ty: Ty<'tcx>,
|
||||||
) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> {
|
) -> EvalResult<'tcx, ValTy<'tcx>> {
|
||||||
let mut base_layout = self.layout_of(base_ty)?;
|
let mut base_layout = self.layout_of(base_ty)?;
|
||||||
if let Some(variant_index) = variant {
|
if let Some(variant_index) = variant {
|
||||||
base_layout = base_layout.for_variant(self, variant_index);
|
base_layout = base_layout.for_variant(self, variant_index);
|
||||||
|
@ -128,21 +128,34 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
let field_index = field.index();
|
let field_index = field.index();
|
||||||
let field = base_layout.field(self, field_index)?;
|
let field = base_layout.field(self, field_index)?;
|
||||||
if field.size.bytes() == 0 {
|
if field.size.bytes() == 0 {
|
||||||
return Ok(Some((Value::Scalar(Scalar::undef()), field.ty)))
|
return Ok(ValTy {
|
||||||
|
value: Value::Scalar(Scalar::undef()),
|
||||||
|
ty: field.ty,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
let offset = base_layout.fields.offset(field_index);
|
let offset = base_layout.fields.offset(field_index);
|
||||||
match base {
|
let value = match base {
|
||||||
// the field covers the entire type
|
// the field covers the entire type
|
||||||
Value::ScalarPair(..) |
|
Value::ScalarPair(..) |
|
||||||
Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))),
|
Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => base,
|
||||||
// split fat pointers, 2 element tuples, ...
|
// extract fields from types with `ScalarPair` ABI
|
||||||
Value::ScalarPair(a, b) => {
|
Value::ScalarPair(a, b) => {
|
||||||
let val = if offset.bytes() == 0 { a } else { b };
|
let val = if offset.bytes() == 0 { a } else { b };
|
||||||
Ok(Some((Value::Scalar(val), field.ty)))
|
Value::Scalar(val)
|
||||||
},
|
},
|
||||||
// FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
|
Value::ByRef(base_ptr, align) => {
|
||||||
_ => Ok(None),
|
let offset = base_layout.fields.offset(field_index);
|
||||||
}
|
let ptr = base_ptr.ptr_offset(offset, self)?;
|
||||||
|
let align = align.min(base_layout.align).min(field.align);
|
||||||
|
assert!(!field.is_unsized());
|
||||||
|
Value::ByRef(ptr, align)
|
||||||
|
},
|
||||||
|
Value::Scalar(val) => bug!("field access on non aggregate {:?}, {:?}", val, base_ty),
|
||||||
|
};
|
||||||
|
Ok(ValTy {
|
||||||
|
value,
|
||||||
|
ty: field.ty,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_read_place_projection(
|
fn try_read_place_projection(
|
||||||
|
@ -156,7 +169,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
};
|
};
|
||||||
let base_ty = self.place_ty(&proj.base);
|
let base_ty = self.place_ty(&proj.base);
|
||||||
match proj.elem {
|
match proj.elem {
|
||||||
Field(field, _) => Ok(self.read_field(base, None, field, base_ty)?.map(|(f, _)| f)),
|
Field(field, _) => Ok(Some(self.read_field(base, None, field, base_ty)?.value)),
|
||||||
// The NullablePointer cases should work fine, need to take care for normal enums
|
// The NullablePointer cases should work fine, need to take care for normal enums
|
||||||
Downcast(..) |
|
Downcast(..) |
|
||||||
Subslice { .. } |
|
Subslice { .. } |
|
||||||
|
|
|
@ -4,7 +4,7 @@ use rustc::ty::layout::LayoutOf;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use rustc::mir::interpret::{EvalResult, Value};
|
use rustc::mir::interpret::EvalResult;
|
||||||
use super::{EvalContext, Place, Machine, ValTy};
|
use super::{EvalContext, Place, Machine, ValTy};
|
||||||
|
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
use rustc_data_structures::indexed_vec::Idx;
|
||||||
|
@ -345,31 +345,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
|
if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
|
||||||
for (i, arg_local) in arg_locals.enumerate() {
|
for (i, arg_local) in arg_locals.enumerate() {
|
||||||
let field = layout.field(&self, i)?;
|
let field = mir::Field::new(i);
|
||||||
if field.is_zst() {
|
let valty = self.read_field(args[1].value, None, field, args[1].ty)?;
|
||||||
continue;
|
let dest = self.eval_place(&mir::Place::Local(arg_local))?;
|
||||||
}
|
|
||||||
let offset = layout.fields.offset(i);
|
|
||||||
let value = match args[1].value {
|
|
||||||
Value::ByRef(ptr, align) => Value::ByRef(
|
|
||||||
ptr.ptr_offset(offset, &self)?,
|
|
||||||
align.min(field.align),
|
|
||||||
),
|
|
||||||
other if field.size == layout.size => {
|
|
||||||
// this is the case where the field covers the entire type
|
|
||||||
assert_eq!(offset.bytes(), 0);
|
|
||||||
other
|
|
||||||
},
|
|
||||||
Value::ScalarPair(a, _) if offset.bytes() == 0 => Value::Scalar(a),
|
|
||||||
Value::ScalarPair(_, b) => Value::Scalar(b),
|
|
||||||
Value::Scalar(_) => bug!("Scalar does not cover entire type"),
|
|
||||||
};
|
|
||||||
let dest =
|
|
||||||
self.eval_place(&mir::Place::Local(arg_local))?;
|
|
||||||
let valty = ValTy {
|
|
||||||
value,
|
|
||||||
ty: field.ty,
|
|
||||||
};
|
|
||||||
self.write_value(valty, dest)?;
|
self.write_value(valty, dest)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -214,10 +214,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
ProjectionElem::Field(field, _) => {
|
ProjectionElem::Field(field, _) => {
|
||||||
trace!("field proj on {:?}", proj.base);
|
trace!("field proj on {:?}", proj.base);
|
||||||
let (base, ty, span) = self.eval_place(&proj.base)?;
|
let (base, ty, span) = self.eval_place(&proj.base)?;
|
||||||
let (value, field_ty) = self.use_ecx(span, |this| {
|
let valty = self.use_ecx(span, |this| {
|
||||||
this.ecx.read_field(base, None, field, ty)
|
this.ecx.read_field(base, None, field, ty)
|
||||||
})??;
|
})?;
|
||||||
Some((value, field_ty, span))
|
Some((valty.value, valty.ty, span))
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue