Fix conversion from Miri Value to ConstValue
This commit is contained in:
parent
0d48c96507
commit
41a032db90
2 changed files with 91 additions and 59 deletions
|
@ -93,50 +93,69 @@ pub fn eval_body<'a, 'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_to_const_value<'a, 'tcx>(
|
pub fn value_to_const_value<'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
|
||||||
val: Value,
|
mut val: Value,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> &'tcx ty::Const<'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() {
|
let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
|
||||||
return ty::Const::from_const_value(
|
|
||||||
tcx,
|
if layout.is_zst() {
|
||||||
ConstValue::ByVal(PrimVal::Undef),
|
return Ok(ty::Const::from_const_value(
|
||||||
ty);
|
ecx.tcx.tcx,
|
||||||
|
ConstValue::ByVal(PrimVal::Undef),
|
||||||
|
ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
let val = match layout.abi {
|
||||||
|
layout::Abi::Scalar(..) => {
|
||||||
|
if let Value::ByVal(val) = val {
|
||||||
|
ConstValue::ByVal(val)
|
||||||
|
} else {
|
||||||
|
bug!("expected ByVal value, got {:?}", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layout::Abi::ScalarPair(..) => {
|
||||||
|
if let Value::ByValPair(a, b) = val {
|
||||||
|
ConstValue::ByValPair(a, b)
|
||||||
|
} else {
|
||||||
|
bug!("expected ByValPair value, got {:?}", val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = match layout.abi {
|
|
||||||
layout::Abi::Scalar(..) => {
|
|
||||||
if let Value::ByVal(val) = val {
|
|
||||||
ConstValue::ByVal(val)
|
|
||||||
} else {
|
|
||||||
bug!("expected ByVal value, got {:?}", val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
layout::Abi::ScalarPair(..) => {
|
|
||||||
if let Value::ByValPair(a, b) = val {
|
|
||||||
ConstValue::ByValPair(a, b)
|
|
||||||
} else {
|
|
||||||
bug!("expected ByValPair 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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
ty::Const::from_const_value(tcx, val, ty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
|
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 mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
|
||||||
let result = (|| {
|
let result = (|| {
|
||||||
let value = ecx.const_value_to_value(value, ty)?;
|
let value = ecx.const_value_to_value(value, ty)?;
|
||||||
let (mut field, ty) = match value {
|
let (field, ty) = match value {
|
||||||
Value::ByValPair(..) | Value::ByVal(_) =>
|
Value::ByValPair(..) | Value::ByVal(_) =>
|
||||||
ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
|
ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
|
||||||
Value::ByRef(ptr, align) => {
|
Value::ByRef(ptr, align) => {
|
||||||
|
@ -438,24 +457,16 @@ pub fn const_val_field<'a, 'tcx>(
|
||||||
(Value::ByRef(ptr, align), layout.ty)
|
(Value::ByRef(ptr, align), layout.ty)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Value::ByRef(ptr, align) = field {
|
Ok(value_to_const_value(&ecx, field, ty))
|
||||||
if let Some(val) = ecx.try_read_value(ptr, align, ty)? {
|
|
||||||
field = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok((field, ty))
|
|
||||||
})();
|
})();
|
||||||
match result {
|
result.map_err(|err| {
|
||||||
Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
|
let (trace, span) = ecx.generate_stacktrace(None);
|
||||||
Err(err) => {
|
let err = ErrKind::Miri(err, trace);
|
||||||
let (trace, span) = ecx.generate_stacktrace(None);
|
ConstEvalErr {
|
||||||
let err = ErrKind::Miri(err, trace);
|
kind: err.into(),
|
||||||
Err(ConstEvalErr {
|
span,
|
||||||
kind: err.into(),
|
}
|
||||||
span,
|
})
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn const_variant_index<'a, 'tcx>(
|
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);
|
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
|
||||||
res.map(|(val, _, miri_ty)| {
|
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| {
|
}).map_err(|mut err| {
|
||||||
if tcx.is_static(def_id).is_some() {
|
if tcx.is_static(def_id).is_some() {
|
||||||
ecx.report(&mut err, true, None);
|
ecx.report(&mut err, true, None);
|
||||||
|
|
21
src/test/run-pass/match-larger-const.rs
Normal file
21
src/test/run-pass/match-larger-const.rs
Normal file
|
@ -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 => (),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue