Skip to content

Commit 93a7aeb

Browse files
committed
Move all intrinsics out of interpret and fail CTFE on intrinsic calls
1 parent e26f533 commit 93a7aeb

File tree

13 files changed

+149
-58
lines changed

13 files changed

+149
-58
lines changed

miri/helpers.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use rustc_miri::interpret::{
2+
Pointer,
3+
EvalResult, EvalError,
4+
PrimVal,
5+
EvalContext,
6+
};
7+
8+
use rustc::ty::Ty;
9+
use rustc::ty::layout::Layout;
10+
11+
pub trait EvalContextExt<'tcx> {
12+
fn wrapping_pointer_offset(
13+
&self,
14+
ptr: Pointer,
15+
pointee_ty: Ty<'tcx>,
16+
offset: i64,
17+
) -> EvalResult<'tcx, Pointer>;
18+
19+
fn pointer_offset(
20+
&self,
21+
ptr: Pointer,
22+
pointee_ty: Ty<'tcx>,
23+
offset: i64,
24+
) -> EvalResult<'tcx, Pointer>;
25+
}
26+
27+
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
28+
fn wrapping_pointer_offset(
29+
&self,
30+
ptr: Pointer,
31+
pointee_ty: Ty<'tcx>,
32+
offset: i64,
33+
) -> EvalResult<'tcx, Pointer> {
34+
// FIXME: assuming here that type size is < i64::max_value()
35+
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
36+
let offset = offset.overflowing_mul(pointee_size).0;
37+
ptr.wrapping_signed_offset(offset, self)
38+
}
39+
40+
fn pointer_offset(
41+
&self,
42+
ptr: Pointer,
43+
pointee_ty: Ty<'tcx>,
44+
offset: i64,
45+
) -> EvalResult<'tcx, Pointer> {
46+
// This function raises an error if the offset moves the pointer outside of its allocation. We consider
47+
// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0).
48+
// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
49+
// allocation.
50+
51+
if ptr.is_null()? { // NULL pointers must only be offset by 0
52+
return if offset == 0 { Ok(ptr) } else { Err(EvalError::InvalidNullPointerUsage) };
53+
}
54+
// FIXME: assuming here that type size is < i64::max_value()
55+
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
56+
return if let Some(offset) = offset.checked_mul(pointee_size) {
57+
let ptr = ptr.signed_offset(offset, self)?;
58+
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
59+
if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
60+
self.memory.check_bounds(ptr, false)?;
61+
} else if ptr.is_null()? {
62+
// We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
63+
return Err(EvalError::InvalidNullPointerUsage);
64+
}
65+
Ok(ptr)
66+
} else {
67+
Err(EvalError::OverflowingMath)
68+
}
69+
}
70+
}

src/librustc_mir/interpret/terminator/intrinsic.rs renamed to miri/intrinsic.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,31 @@ use rustc::traits::Reveal;
33
use rustc::ty::layout::Layout;
44
use rustc::ty::{self, Ty};
55

6-
use interpret::{
6+
use rustc_miri::interpret::{
77
EvalError, EvalResult,
8-
EvalContext,
98
Lvalue, LvalueExtra,
109
PrimVal, PrimValKind, Value, Pointer,
1110
HasMemory,
1211
Machine,
12+
EvalContext,
1313
};
1414

15-
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
16-
pub(super) fn call_intrinsic(
15+
use helpers::EvalContextExt as HelperEvalContextExt;
16+
17+
pub trait EvalContextExt<'tcx> {
18+
fn call_intrinsic(
19+
&mut self,
20+
instance: ty::Instance<'tcx>,
21+
args: &[mir::Operand<'tcx>],
22+
dest: Lvalue<'tcx>,
23+
dest_ty: Ty<'tcx>,
24+
dest_layout: &'tcx Layout,
25+
target: mir::BasicBlock,
26+
) -> EvalResult<'tcx>;
27+
}
28+
29+
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
30+
fn call_intrinsic(
1731
&mut self,
1832
instance: ty::Instance<'tcx>,
1933
args: &[mir::Operand<'tcx>],
@@ -495,7 +509,7 @@ fn numeric_intrinsic<'tcx>(
495509
) -> EvalResult<'tcx, PrimVal> {
496510
macro_rules! integer_intrinsic {
497511
($method:ident) => ({
498-
use interpret::PrimValKind::*;
512+
use rustc_miri::interpret::PrimValKind::*;
499513
let result_bytes = match kind {
500514
I8 => (bytes as i8).$method() as u128,
501515
U8 => (bytes as u8).$method() as u128,

miri/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ extern crate rustc_data_structures;
1414
extern crate syntax;
1515

1616
use rustc::ty::{self, TyCtxt};
17+
use rustc::ty::layout::Layout;
1718
use rustc::hir::def_id::DefId;
1819
use rustc::mir;
1920

@@ -29,9 +30,12 @@ pub use rustc_miri::interpret::*;
2930

3031
mod fn_call;
3132
mod operator;
33+
mod intrinsic;
34+
mod helpers;
3235

3336
use fn_call::EvalContextExt as MissingFnsEvalContextExt;
3437
use operator::EvalContextExt as OperatorEvalContextExt;
38+
use intrinsic::EvalContextExt as IntrinsicEvalContextExt;
3539

3640
pub fn eval_main<'a, 'tcx: 'a>(
3741
tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -287,6 +291,18 @@ impl<'tcx> Machine<'tcx> for Evaluator {
287291
ecx.eval_fn_call(instance, destination, arg_operands, span, sig)
288292
}
289293

294+
fn call_intrinsic<'a>(
295+
ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
296+
instance: ty::Instance<'tcx>,
297+
args: &[mir::Operand<'tcx>],
298+
dest: Lvalue<'tcx>,
299+
dest_ty: ty::Ty<'tcx>,
300+
dest_layout: &'tcx Layout,
301+
target: mir::BasicBlock,
302+
) -> EvalResult<'tcx> {
303+
ecx.call_intrinsic(instance, args, dest, dest_ty, dest_layout, target)
304+
}
305+
290306
fn ptr_op<'a>(
291307
ecx: &rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
292308
bin_op: mir::BinOp,

miri/operator.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use rustc::mir;
33

44
use rustc_miri::interpret::*;
55

6+
use helpers::EvalContextExt as HelperEvalContextExt;
7+
68
pub trait EvalContextExt<'tcx> {
79
fn ptr_op(
810
&self,

src/librustc_mir/interpret/const_eval.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc::traits::Reveal;
2-
use rustc::ty::{self, TyCtxt, Ty, Instance};
2+
use rustc::ty::{self, TyCtxt, Ty, Instance, layout};
33
use rustc::mir;
44

55
use syntax::ast::Mutability;
@@ -163,6 +163,18 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
163163
Ok(false)
164164
}
165165

166+
fn call_intrinsic<'a>(
167+
_ecx: &mut EvalContext<'a, 'tcx, Self>,
168+
_instance: ty::Instance<'tcx>,
169+
_args: &[mir::Operand<'tcx>],
170+
_dest: Lvalue<'tcx>,
171+
_dest_ty: Ty<'tcx>,
172+
_dest_layout: &'tcx layout::Layout,
173+
_target: mir::BasicBlock,
174+
) -> EvalResult<'tcx> {
175+
Err(ConstEvalError::NeedsRfc("calling intrinsics".to_string()).into())
176+
}
177+
166178
fn ptr_op<'a>(
167179
_ecx: &EvalContext<'a, 'tcx, Self>,
168180
_bin_op: mir::BinOp,

src/librustc_mir/interpret/eval_context.rs

Lines changed: 7 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
205205
false
206206
}
207207

208-
pub(crate) fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
208+
pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
209209
let ptr = self.memory.allocate_cached(s.as_bytes())?;
210210
Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128)))
211211
}
@@ -363,11 +363,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
363363
self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs))
364364
}
365365

366-
pub(super) fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
366+
pub fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
367367
self.type_size_with_substs(ty, self.substs())
368368
}
369369

370-
pub(super) fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
370+
pub fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> {
371371
self.type_align_with_substs(ty, self.substs())
372372
}
373373

@@ -1000,39 +1000,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
10001000
}
10011001
}
10021002

1003-
pub(super) fn wrapping_pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> {
1004-
// FIXME: assuming here that type size is < i64::max_value()
1005-
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
1006-
let offset = offset.overflowing_mul(pointee_size).0;
1007-
ptr.wrapping_signed_offset(offset, self)
1008-
}
1009-
1010-
pub fn pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> {
1011-
// This function raises an error if the offset moves the pointer outside of its allocation. We consider
1012-
// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0).
1013-
// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own
1014-
// allocation.
1015-
1016-
if ptr.is_null()? { // NULL pointers must only be offset by 0
1017-
return if offset == 0 { Ok(ptr) } else { Err(EvalError::InvalidNullPointerUsage) };
1018-
}
1019-
// FIXME: assuming here that type size is < i64::max_value()
1020-
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
1021-
return if let Some(offset) = offset.checked_mul(pointee_size) {
1022-
let ptr = ptr.signed_offset(offset, self)?;
1023-
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
1024-
if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() {
1025-
self.memory.check_bounds(ptr, false)?;
1026-
} else if ptr.is_null()? {
1027-
// We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now.
1028-
return Err(EvalError::InvalidNullPointerUsage);
1029-
}
1030-
Ok(ptr)
1031-
} else {
1032-
Err(EvalError::OverflowingMath)
1033-
}
1034-
}
1035-
10361003
pub(super) fn eval_operand_to_primval(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, PrimVal> {
10371004
let value = self.eval_operand(op)?;
10381005
let ty = self.operand_ty(op);
@@ -1081,7 +1048,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
10811048
Ok(())
10821049
}
10831050

1084-
pub(super) fn force_allocation(
1051+
pub fn force_allocation(
10851052
&mut self,
10861053
lvalue: Lvalue<'tcx>,
10871054
) -> EvalResult<'tcx, Lvalue<'tcx>> {
@@ -1275,7 +1242,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
12751242
Ok(())
12761243
}
12771244

1278-
pub(super) fn write_value_to_ptr(
1245+
pub fn write_value_to_ptr(
12791246
&mut self,
12801247
value: Value,
12811248
dest: Pointer,
@@ -1293,7 +1260,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
12931260
}
12941261
}
12951262

1296-
pub(super) fn write_pair_to_ptr(
1263+
pub fn write_pair_to_ptr(
12971264
&mut self,
12981265
a: PrimVal,
12991266
b: PrimVal,
@@ -1416,7 +1383,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
14161383
}
14171384
}
14181385

1419-
pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
1386+
pub fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
14201387
if let Some(val) = self.try_read_value(ptr, ty)? {
14211388
Ok(val)
14221389
} else {

src/librustc_mir/interpret/lvalue.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl<'tcx> Lvalue<'tcx> {
7373
Self::from_primval_ptr(PrimVal::Undef.into())
7474
}
7575

76-
pub(crate) fn from_primval_ptr(ptr: Pointer) -> Self {
76+
pub fn from_primval_ptr(ptr: Pointer) -> Self {
7777
Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true }
7878
}
7979

@@ -89,7 +89,7 @@ impl<'tcx> Lvalue<'tcx> {
8989
}
9090
}
9191

92-
pub(super) fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
92+
pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
9393
let (ptr, extra, _aligned) = self.to_ptr_extra_aligned();
9494
// At this point, we forget about the alignment information -- the lvalue has been turned into a reference,
9595
// and no matter where it came from, it now must be aligned.

src/librustc_mir/interpret/machine.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ pub trait Machine<'tcx>: Sized {
3636
sig: ty::FnSig<'tcx>,
3737
) -> EvalResult<'tcx, bool>;
3838

39+
/// directly process an intrinsic without pushing a stack frame.
40+
fn call_intrinsic<'a>(
41+
ecx: &mut EvalContext<'a, 'tcx, Self>,
42+
instance: ty::Instance<'tcx>,
43+
args: &[mir::Operand<'tcx>],
44+
dest: Lvalue<'tcx>,
45+
dest_ty: ty::Ty<'tcx>,
46+
dest_layout: &'tcx ty::layout::Layout,
47+
target: mir::BasicBlock,
48+
) -> EvalResult<'tcx>;
49+
3950
/// Called when operating on the value of pointers.
4051
///
4152
/// Returns `None` if the operation should be handled by the integer

src/librustc_mir/interpret/memory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
433433
}
434434
}
435435

436-
pub(crate) fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx> {
436+
pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx> {
437437
let alloc = self.get(ptr.alloc_id)?;
438438
let allocation_size = alloc.bytes.len() as u64;
439439
if ptr.offset > allocation_size {
@@ -1310,7 +1310,7 @@ fn bit_index(bits: u64) -> (usize, usize) {
13101310
// Unaligned accesses
13111311
////////////////////////////////////////////////////////////////////////////////
13121312

1313-
pub(crate) trait HasMemory<'a, 'tcx, M: Machine<'tcx>> {
1313+
pub trait HasMemory<'a, 'tcx, M: Machine<'tcx>> {
13141314
fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M>;
13151315
fn memory(&self) -> &Memory<'a, 'tcx, M>;
13161316

src/librustc_mir/interpret/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ pub use self::memory::{
3939
Memory,
4040
MemoryPointer,
4141
Kind,
42+
HasMemory,
4243
};
4344

4445
use self::memory::{
45-
HasMemory,
4646
PointerArithmetic,
4747
LockInfo,
4848
AccessKind,

src/librustc_mir/interpret/operator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
3434

3535
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
3636
/// and a boolean signifying the potential overflow to the destination.
37-
pub(super) fn intrinsic_with_overflow(
37+
pub fn intrinsic_with_overflow(
3838
&mut self,
3939
op: mir::BinOp,
4040
left: &mir::Operand<'tcx>,
@@ -49,7 +49,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
4949

5050
/// Applies the binary operation `op` to the arguments and writes the result to the
5151
/// destination. Returns `true` if the operation overflowed.
52-
pub(super) fn intrinsic_overflowing(
52+
pub fn intrinsic_overflowing(
5353
&mut self,
5454
op: mir::BinOp,
5555
left: &mir::Operand<'tcx>,

src/librustc_mir/interpret/terminator/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use super::eval_context::IntegerExt;
1717
use rustc_data_structures::indexed_vec::Idx;
1818

1919
mod drop;
20-
mod intrinsic;
2120

2221
impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
2322
pub fn goto_block(&mut self, target: mir::BasicBlock) {
@@ -221,7 +220,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
221220
return Err(EvalError::Unreachable);
222221
}
223222
let layout = self.type_layout(ty)?;
224-
self.call_intrinsic(instance, arg_operands, ret, ty, layout, target)?;
223+
M::call_intrinsic(self, instance, arg_operands, ret, ty, layout, target)?;
225224
self.dump_local(ret);
226225
Ok(())
227226
},

0 commit comments

Comments
 (0)