Correctly access ScalarPair fields during const eval
This commit is contained in:
parent
d830f46b77
commit
47f37d67f1
4 changed files with 80 additions and 79 deletions
|
|
@ -136,8 +136,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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];
|
||||
Value::ScalarPair(a, b) => {
|
||||
let val = if offset.bytes() == 0 { a } else { b };
|
||||
Ok(Some((Value::Scalar(val), field.ty)))
|
||||
},
|
||||
// FIXME(oli-obk): figure out whether we should be calling `try_read_value` here
|
||||
|
|
|
|||
|
|
@ -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, Value};
|
||||
use super::{EvalContext, Place, Machine, ValTy};
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
|
@ -338,65 +338,39 @@ 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 = layout.field(&self, i)?;
|
||||
if field.is_zst() {
|
||||
continue;
|
||||
}
|
||||
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)?;
|
||||
}
|
||||
} else {
|
||||
trace!("manual impl of rust-call ABI");
|
||||
|
|
|
|||
|
|
@ -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 (value, field_ty) = self.use_ecx(span, |this| {
|
||||
this.ecx.read_field(base, None, field, ty)
|
||||
})??;
|
||||
Some((value, field_ty, span))
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
|
|
|
|||
41
src/test/ui/const-eval/issue-51300.rs
Normal file
41
src/test/ui/const-eval/issue-51300.rs
Normal 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() { }
|
||||
Loading…
Add table
Add a link
Reference in a new issue