diff options
| author | Oliver Schneider <github35764891676564198441@oli-obk.de> | 2018-06-02 23:34:25 +0200 |
|---|---|---|
| committer | Oliver Schneider <github35764891676564198441@oli-obk.de> | 2018-06-02 23:34:25 +0200 |
| commit | 47f37d67f14ef50829c4ff95a3a27a680fd4e1ba (patch) | |
| tree | 51e71813cffefd1d36c7c3efa9402a0117635355 /src/librustc_mir/interpret | |
| parent | d830f46b77bbb97fbff6397f0d9c352a880f796d (diff) | |
| download | rust-47f37d67f14ef50829c4ff95a3a27a680fd4e1ba.tar.gz rust-47f37d67f14ef50829c4ff95a3a27a680fd4e1ba.zip | |
Correctly access ScalarPair fields during const eval
Diffstat (limited to 'src/librustc_mir/interpret')
| -rw-r--r-- | src/librustc_mir/interpret/place.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/terminator/mod.rs | 90 |
2 files changed, 34 insertions, 60 deletions
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c1bcffe7e9a..d1f3b8b86de 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -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 diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 9151bfbdd1b..8ed60b2325a 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -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"); |
