about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-05-16 21:01:31 +0000
committerbors <bors@rust-lang.org>2018-05-16 21:01:31 +0000
commit2f2a11dfc436fc0f401b595f22ed043c46dbebe7 (patch)
treed22171e4a637913a739fdfac01df1fe3f341d3b4
parente1151c9819cca90e511f60757297629177272d16 (diff)
parent41a032db9050941e19fec7f3409de00ae175848d (diff)
downloadrust-2f2a11dfc436fc0f401b595f22ed043c46dbebe7.tar.gz
rust-2f2a11dfc436fc0f401b595f22ed043c46dbebe7.zip
Auto merge of #50710 - Zoxc:value_to_constvalue, r=oli-obk
Fix conversion from Miri Value to ConstValue

This fixes an error compiling the `immeta` 0.3.6 crate. https://github.com/rust-lang/rust/issues/50707 may be fixed too.

r? @oli-obk
-rw-r--r--src/librustc_mir/interpret/const_eval.rs123
-rw-r--r--src/test/run-pass/match-larger-const.rs21
2 files changed, 88 insertions, 56 deletions
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 6bf965aaf44..7d0c16de0a4 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -93,50 +93,69 @@ pub fn eval_body<'a, 'tcx>(
     }
 }
 
-pub fn value_to_const_value<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    val: Value,
+pub fn value_to_const_value<'tcx>(
+    ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
+    mut val: Value,
     ty: Ty<'tcx>,
 ) -> &'tcx ty::Const<'tcx> {
-    let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+    let result = (|| {
+        // Convert to ByVal or ByValPair if possible
+        if let Value::ByRef(ptr, align) = val {
+            if let Some(read_val) = ecx.try_read_value(ptr, align, ty)? {
+                val = read_val;
+            }
+        }
 
-    if layout.is_zst() {
-        return ty::Const::from_const_value(
-            tcx,
-            ConstValue::ByVal(PrimVal::Undef),
-            ty);
-    }
+        let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
 
-    let val = match layout.abi {
-        layout::Abi::Scalar(..) => {
-            if let Value::ByVal(val) = val {
-                ConstValue::ByVal(val)
-            } else {
-                bug!("expected ByVal value, got {:?}", val);
-            }
+        if layout.is_zst() {
+            return Ok(ty::Const::from_const_value(
+                ecx.tcx.tcx,
+                ConstValue::ByVal(PrimVal::Undef),
+                ty));
         }
-        layout::Abi::ScalarPair(..) => {
-            if let Value::ByValPair(a, b) = val {
-                ConstValue::ByValPair(a, b)
-            } else {
-                bug!("expected ByValPair value, got {:?}", val);
+
+        let val = match layout.abi {
+            layout::Abi::Scalar(..) => {
+                if let Value::ByVal(val) = val {
+                    ConstValue::ByVal(val)
+                } else {
+                    bug!("expected ByVal value, got {:?}", val);
+                }
             }
-        }
-        _ => {
-            if let Value::ByRef(ptr, align) = val {
-                let ptr = ptr.primval.to_ptr().unwrap();
-                assert_eq!(ptr.offset, 0);
-                let alloc = tcx.interpret_interner
-                               .get_alloc(ptr.alloc_id)
-                               .expect("miri allocation never successfully created");
-                assert_eq!(align, alloc.align);
-                ConstValue::ByRef(alloc)
-            } else {
-                bug!("expected ByRef value, got {:?}", val);
+            layout::Abi::ScalarPair(..) => {
+                if let Value::ByValPair(a, b) = val {
+                    ConstValue::ByValPair(a, b)
+                } else {
+                    bug!("expected ByValPair value, got {:?}", val);
+                }
             }
-        },
-    };
-    ty::Const::from_const_value(tcx, val, ty)
+            _ => {
+                if let Value::ByRef(ptr, _) = val {
+                    let ptr = ptr.primval.to_ptr().unwrap();
+                    assert_eq!(ptr.offset, 0);
+                    let alloc = ecx.memory.get(ptr.alloc_id)?;
+                    assert!(alloc.align.abi() >= layout.align.abi());
+                    assert!(alloc.bytes.len() as u64 == layout.size.bytes());
+                    let mut alloc = alloc.clone();
+                    // The align field is meaningless for values, so just use the layout's align
+                    alloc.align = layout.align;
+                    let alloc = ecx.tcx.intern_const_alloc(alloc);
+                    ConstValue::ByRef(alloc)
+                } else {
+                    bug!("expected ByRef value, got {:?}", val);
+                }
+            },
+        };
+        Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, ty))
+    })();
+    match result {
+        Ok(v) => v,
+        Err(mut err) => {
+            ecx.report(&mut err, true, None);
+            bug!("miri error occured when converting Value to ConstValue")
+        }
+    }
 }
 
 fn eval_body_and_ecx<'a, 'mir, 'tcx>(
@@ -423,7 +442,7 @@ pub fn const_val_field<'a, 'tcx>(
     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
     let result = (|| {
         let value = ecx.const_value_to_value(value, ty)?;
-        let (mut field, ty) = match value {
+        let (field, ty) = match value {
             Value::ByValPair(..) | Value::ByVal(_) => 
                 ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
             Value::ByRef(ptr, align) => {
@@ -438,24 +457,16 @@ pub fn const_val_field<'a, 'tcx>(
                 (Value::ByRef(ptr, align), layout.ty)
             }
         };
-        if let Value::ByRef(ptr, align) = field {
-            if let Some(val) = ecx.try_read_value(ptr, align, ty)? {
-                field = val;
-            }
-        }
-        Ok((field, ty))
+        Ok(value_to_const_value(&ecx, field, ty))
     })();
-    match result {
-        Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
-        Err(err) => {
-            let (trace, span) = ecx.generate_stacktrace(None);
-            let err = ErrKind::Miri(err, trace);
-            Err(ConstEvalErr {
-                kind: err.into(),
-                span,
-            })
-        },
-    }
+    result.map_err(|err| {
+        let (trace, span) = ecx.generate_stacktrace(None);
+        let err = ErrKind::Miri(err, trace);
+        ConstEvalErr {
+            kind: err.into(),
+            span,
+        }
+    })
 }
 
 pub fn const_variant_index<'a, 'tcx>(
@@ -541,7 +552,7 @@ pub fn const_eval_provider<'a, 'tcx>(
 
     let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
     res.map(|(val, _, miri_ty)| {
-        value_to_const_value(tcx, val, miri_ty)
+        value_to_const_value(&ecx, val, miri_ty)
     }).map_err(|mut err| {
         if tcx.is_static(def_id).is_some() {
             ecx.report(&mut err, true, None);
diff --git a/src/test/run-pass/match-larger-const.rs b/src/test/run-pass/match-larger-const.rs
new file mode 100644
index 00000000000..8cb4d92c21c
--- /dev/null
+++ b/src/test/run-pass/match-larger-const.rs
@@ -0,0 +1,21 @@
+// 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.
+
+#[derive(Eq, PartialEq)]
+pub struct Data([u8; 4]);
+
+const DATA: Data = Data([1, 2, 3, 4]);
+
+fn main() {
+    match DATA {
+        DATA => (),
+        _ => (),
+    }
+}