Skip to content

Commit f3832c6

Browse files
authored
Merge pull request rust-lang#218 from oli-obk/minimal_ctfe
Initial work towards checking const eval rules in miri
2 parents 14d1309 + ab400f3 commit f3832c6

File tree

4 files changed

+46
-0
lines changed

4 files changed

+46
-0
lines changed

src/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pub enum EvalError<'tcx> {
6363
HeapAllocNonPowerOfTwoAlignment(u64),
6464
Unreachable,
6565
Panic,
66+
NeedsRfc(String),
67+
NotConst(String),
6668
}
6769

6870
pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
@@ -156,6 +158,10 @@ impl<'tcx> Error for EvalError<'tcx> {
156158
"entered unreachable code",
157159
EvalError::Panic =>
158160
"the evaluated program panicked",
161+
EvalError::NeedsRfc(_) =>
162+
"this feature needs an rfc before being allowed inside constants",
163+
EvalError::NotConst(_) =>
164+
"this feature is not compatible with constant evaluation",
159165
}
160166
}
161167

@@ -191,6 +197,10 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
191197
write!(f, "expected primitive type, got {}", ty),
192198
EvalError::Layout(ref err) =>
193199
write!(f, "rustc layout computation failed: {:?}", err),
200+
EvalError::NeedsRfc(ref msg) =>
201+
write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg),
202+
EvalError::NotConst(ref msg) =>
203+
write!(f, "Cannot evaluate within constants: \"{}\"", msg),
194204
_ => write!(f, "{}", self.description()),
195205
}
196206
}

src/eval_context.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
655655
}
656656

657657
Len(ref lvalue) => {
658+
if self.frame().const_env() {
659+
return Err(EvalError::NeedsRfc("computing the length of arrays".to_string()));
660+
}
658661
let src = self.eval_lvalue(lvalue)?;
659662
let ty = self.lvalue_ty(lvalue);
660663
let (_, len) = src.elem_ty_and_len(ty);
@@ -701,6 +704,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
701704
}
702705

703706
NullaryOp(mir::NullOp::Box, ty) => {
707+
if self.frame().const_env() {
708+
return Err(EvalError::NeedsRfc("\"heap\" allocations".to_string()));
709+
}
704710
// FIXME: call the `exchange_malloc` lang item if available
705711
if self.type_size(ty)?.expect("box only works with sized types") == 0 {
706712
let align = self.type_align(ty)?;
@@ -712,6 +718,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
712718
}
713719

714720
NullaryOp(mir::NullOp::SizeOf, ty) => {
721+
if self.frame().const_env() {
722+
return Err(EvalError::NeedsRfc("computing the size of types (size_of)".to_string()));
723+
}
715724
let size = self.type_size(ty)?.expect("SizeOf nullary MIR operator called for unsized type");
716725
self.write_primval(dest, PrimVal::from_u128(size as u128), dest_ty)?;
717726
}
@@ -1583,6 +1592,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
15831592
}
15841593

15851594
impl<'tcx> Frame<'tcx> {
1595+
pub fn const_env(&self) -> bool {
1596+
match self.return_to_block {
1597+
StackPopCleanup::MarkStatic(_) => true,
1598+
_ => false,
1599+
}
1600+
}
15861601
pub fn get_local(&self, local: mir::Local, field: Option<usize>) -> EvalResult<'tcx, Value> {
15871602
// Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0.
15881603
if let Some(field) = field {

src/operator.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
151151
let usize = PrimValKind::from_uint_size(self.memory.pointer_size());
152152
let isize = PrimValKind::from_int_size(self.memory.pointer_size());
153153
if !left_kind.is_float() && !right_kind.is_float() {
154+
if (!left.is_bytes() && !right.is_bytes()) && self.frame().const_env() {
155+
if left.is_ptr() && right.is_ptr() {
156+
return Err(EvalError::NotConst("Comparing pointers".to_string()));
157+
} else {
158+
return Err(EvalError::NeedsRfc("Comparing Pointers integers with pointers".to_string()));
159+
}
160+
}
154161
match bin_op {
155162
Offset if left_kind == Ptr && right_kind == usize => {
156163
let pointee_ty = left_ty.builtin_deref(true, ty::LvaluePreference::NoPreference).expect("Offset called on non-ptr type").ty;

src/terminator/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
3737
Goto { target } => self.goto_block(target),
3838

3939
SwitchInt { ref discr, ref values, ref targets, .. } => {
40+
if self.frame().const_env() {
41+
return Err(EvalError::NeedsRfc("branching (if, match, loop, ...)".to_string()));
42+
}
4043
let discr_val = self.eval_operand(discr)?;
4144
let discr_ty = self.operand_ty(discr);
4245
let discr_prim = self.value_to_primval(discr_val, discr_ty)?;
@@ -92,6 +95,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
9295

9396
Drop { ref location, target, .. } => {
9497
trace!("TerminatorKind::drop: {:?}, {:?}", location, self.substs());
98+
if self.frame().const_env() {
99+
return Err(EvalError::NeedsRfc("invoking `Drop::drop`".to_string()));
100+
}
95101
let lval = self.eval_lvalue(location)?;
96102
let ty = self.lvalue_ty(location);
97103
self.goto_block(target);
@@ -424,11 +430,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
424430
let mir = match self.load_mir(instance.def) {
425431
Ok(mir) => mir,
426432
Err(EvalError::NoMirFor(path)) => {
433+
if self.frame().const_env() {
434+
return Err(EvalError::NeedsRfc(format!("calling extern function `{}`", path)));
435+
}
427436
self.call_missing_fn(instance, destination, arg_operands, sig, path)?;
428437
return Ok(true);
429438
},
430439
Err(other) => return Err(other),
431440
};
441+
442+
if self.frame().const_env() && !self.tcx.is_const_fn(instance.def_id()) {
443+
return Err(EvalError::NotConst(format!("calling non-const fn `{}`", instance)));
444+
}
445+
432446
let (return_lvalue, return_to_block) = match destination {
433447
Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
434448
None => (Lvalue::undef(), StackPopCleanup::None),

0 commit comments

Comments
 (0)