Skip to content

Fix conversion from Miri Value to ConstValue #50710

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 67 additions & 56 deletions src/librustc_mir/interpret/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand Down Expand Up @@ -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) => {
Expand All @@ -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>(
Expand Down Expand Up @@ -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);
Expand Down
21 changes: 21 additions & 0 deletions src/test/run-pass/match-larger-const.rs
Original file line number Diff line number Diff line change
@@ -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)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The playpen is probably not on the latest nightly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah indeed. sorry

pub struct Data([u8; 4]);

const DATA: Data = Data([1, 2, 3, 4]);

fn main() {
match DATA {
DATA => (),
_ => (),
}
}