Auto merge of #51307 - oli-obk:miri_fixes, r=eddyb

ScalarPairs are offset==0 field + other non-zst field

r? @eddyb

fixes #51300
This commit is contained in:
bors 2018-06-04 23:10:15 +00:00
commit c610be92e2
4 changed files with 82 additions and 90 deletions

View File

@ -120,7 +120,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
variant: Option<usize>,
field: mir::Field,
base_ty: Ty<'tcx>,
) -> EvalResult<'tcx, Option<(Value, Ty<'tcx>)>> {
) -> EvalResult<'tcx, ValTy<'tcx>> {
let mut base_layout = self.layout_of(base_ty)?;
if let Some(variant_index) = variant {
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 = base_layout.field(self, field_index)?;
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);
match base {
let value = match base {
// the field covers the entire type
Value::ScalarPair(..) |
Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => Ok(Some((base, field.ty))),
// split fat pointers, 2 element tuples, ...
Value::ScalarPair(a, b) if base_layout.fields.count() == 2 => {
let val = [a, b][field_index];
Ok(Some((Value::Scalar(val), field.ty)))
Value::Scalar(_) if offset.bytes() == 0 && field.size == base_layout.size => base,
// extract fields from types with `ScalarPair` ABI
Value::ScalarPair(a, b) => {
let val = if offset.bytes() == 0 { a } else { b };
Value::Scalar(val)
},
// FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
_ => Ok(None),
}
Value::ByRef(base_ptr, align) => {
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(
@ -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);
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
Downcast(..) |
Subslice { .. } |

View File

@ -4,7 +4,7 @@ use rustc::ty::layout::LayoutOf;
use syntax::codemap::Span;
use rustc_target::spec::abi::Abi;
use rustc::mir::interpret::{EvalResult, Scalar, Value};
use rustc::mir::interpret::EvalResult;
use super::{EvalContext, Place, Machine, ValTy};
use rustc_data_structures::indexed_vec::Idx;
@ -338,65 +338,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
// unpack and write all other args
let layout = self.layout_of(args[1].ty)?;
if let ty::TyTuple(..) = args[1].ty.sty {
if let ty::TyTuple(_) = args[1].ty.sty {
if layout.is_zst() {
// Nothing to do, no need to unpack zsts
return Ok(());
}
if self.frame().mir.args_iter().count() == layout.fields.count() + 1 {
match args[1].value {
Value::ByRef(ptr, align) => {
for (i, arg_local) in arg_locals.enumerate() {
let field = layout.field(&self, i)?;
let offset = layout.fields.offset(i);
let arg = Value::ByRef(ptr.ptr_offset(offset, &self)?,
align.min(field.align));
let dest =
self.eval_place(&mir::Place::Local(arg_local))?;
trace!(
"writing arg {:?} to {:?} (type: {})",
arg,
dest,
field.ty
);
let valty = ValTy {
value: arg,
ty: field.ty,
};
self.write_value(valty, dest)?;
}
}
Value::Scalar(Scalar::Bits { defined: 0, .. }) => {}
other => {
trace!("{:#?}, {:#?}", other, layout);
let mut layout = layout;
'outer: loop {
for i in 0..layout.fields.count() {
let field = layout.field(&self, i)?;
if layout.fields.offset(i).bytes() == 0 && layout.size == field.size {
layout = field;
continue 'outer;
}
}
break;
}
{
let mut write_next = |value| {
let dest = self.eval_place(&mir::Place::Local(
arg_locals.next().unwrap(),
))?;
let valty = ValTy {
value: Value::Scalar(value),
ty: layout.ty,
};
self.write_value(valty, dest)
};
match other {
Value::Scalar(value) | Value::ScalarPair(value, _) => write_next(value)?,
_ => unreachable!(),
}
if let Value::ScalarPair(_, value) = other {
write_next(value)?;
}
}
assert!(arg_locals.next().is_none());
}
for (i, arg_local) in arg_locals.enumerate() {
let field = mir::Field::new(i);
let valty = self.read_field(args[1].value, None, field, args[1].ty)?;
let dest = self.eval_place(&mir::Place::Local(arg_local))?;
self.write_value(valty, dest)?;
}
} else {
trace!("manual impl of rust-call ABI");

View File

@ -29,7 +29,7 @@ use rustc::ty::subst::Substs;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::ty::ParamEnv;
use rustc::ty::layout::{
LayoutOf, TyLayout, LayoutError, LayoutCx,
LayoutOf, TyLayout, LayoutError,
HasTyCtxt, TargetDataLayout, HasDataLayout,
};
@ -214,24 +214,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
ProjectionElem::Field(field, _) => {
trace!("field proj on {:?}", proj.base);
let (base, ty, span) = self.eval_place(&proj.base)?;
match base {
Value::ScalarPair(a, b) => {
trace!("by val pair: {:?}, {:?}", a, b);
let base_layout = self.tcx.layout_of(self.param_env.and(ty)).ok()?;
trace!("layout computed");
use rustc_data_structures::indexed_vec::Idx;
let field_index = field.index();
let val = [a, b][field_index];
let cx = LayoutCx {
tcx: self.tcx,
param_env: self.param_env,
};
let field = base_layout.field(cx, field_index).ok()?;
trace!("projection resulted in: {:?}", val);
Some((Value::Scalar(val), field.ty, span))
},
_ => None,
}
let valty = self.use_ecx(span, |this| {
this.ecx.read_field(base, None, field, ty)
})?;
Some((valty.value, valty.ty, span))
},
_ => None,
},

View File

@ -0,0 +1,41 @@
// Copyright 2018 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-pass
// https://github.com/rust-lang/rust/issues/51300
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Stat {
pub id: u8,
pub index: usize,
}
impl Stat {
pub const STUDENT_HAPPINESS: Stat = Stat{
id: 0,
index: 0,
};
pub const STUDENT_HUNGER: Stat = Stat{
id: 0,
index: Self::STUDENT_HAPPINESS.index + 1,
};
}
pub fn from_index(id: u8, index: usize) -> Option<Stat> {
let stat = Stat{id, index};
match stat {
Stat::STUDENT_HAPPINESS => Some(Stat::STUDENT_HAPPINESS),
Stat::STUDENT_HUNGER => Some(Stat::STUDENT_HUNGER),
_ => None,
}
}
fn main() { }