about summary refs log tree commit diff
path: root/src/librustc_mir
diff options
context:
space:
mode:
authorOliver Schneider <github35764891676564198441@oli-obk.de>2018-06-02 23:34:25 +0200
committerOliver Schneider <github35764891676564198441@oli-obk.de>2018-06-02 23:34:25 +0200
commit47f37d67f14ef50829c4ff95a3a27a680fd4e1ba (patch)
tree51e71813cffefd1d36c7c3efa9402a0117635355 /src/librustc_mir
parentd830f46b77bbb97fbff6397f0d9c352a880f796d (diff)
downloadrust-47f37d67f14ef50829c4ff95a3a27a680fd4e1ba.tar.gz
rust-47f37d67f14ef50829c4ff95a3a27a680fd4e1ba.zip
Correctly access ScalarPair fields during const eval
Diffstat (limited to 'src/librustc_mir')
-rw-r--r--src/librustc_mir/interpret/place.rs4
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs90
-rw-r--r--src/librustc_mir/transform/const_prop.rs24
3 files changed, 39 insertions, 79 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");
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index ef61fe099bf..4ef3fb5663f 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -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,
             },