Skip to content

Commit 31cf66d

Browse files
committed
remove our array drop glue and use rustc's instead; implement the new Offset and SizeOf operators
1 parent 14848b3 commit 31cf66d

File tree

7 files changed

+52
-216
lines changed

7 files changed

+52
-216
lines changed

src/eval_context.rs

Lines changed: 15 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use std::fmt::Write;
44
use rustc::hir::def_id::DefId;
55
use rustc::hir::map::definitions::DefPathData;
66
use rustc::middle::const_val::ConstVal;
7-
use rustc_const_math::{ConstInt, ConstUsize};
87
use rustc::mir;
98
use rustc::traits::Reveal;
109
use rustc::ty::layout::{self, Layout, Size};
@@ -15,7 +14,6 @@ use rustc_data_structures::indexed_vec::Idx;
1514
use syntax::codemap::{self, DUMMY_SP, Span};
1615
use syntax::ast;
1716
use syntax::abi::Abi;
18-
use syntax::symbol::Symbol;
1917

2018
use error::{EvalError, EvalResult};
2119
use lvalue::{Global, GlobalId, Lvalue, LvalueExtra};
@@ -43,9 +41,6 @@ pub struct EvalContext<'a, 'tcx: 'a> {
4341
/// This prevents infinite loops and huge computations from freezing up const eval.
4442
/// Remove once halting problem is solved.
4543
pub(crate) steps_remaining: u64,
46-
47-
/// Drop glue for arrays and slices
48-
pub(crate) seq_drop_glue: &'tcx mir::Mir<'tcx>,
4944
}
5045

5146
/// A stack frame.
@@ -127,188 +122,13 @@ impl Default for ResourceLimits {
127122

128123
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
129124
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, limits: ResourceLimits) -> Self {
130-
// Register array drop glue code
131-
let source_info = mir::SourceInfo {
132-
span: DUMMY_SP,
133-
scope: mir::ARGUMENT_VISIBILITY_SCOPE
134-
};
135-
// i = 0; len = Len(*a0); goto head;
136-
let start_block = mir::BasicBlockData {
137-
statements: vec![
138-
mir::Statement {
139-
source_info,
140-
kind: mir::StatementKind::Assign(
141-
mir::Lvalue::Local(mir::Local::new(2)),
142-
mir::Rvalue::Use(mir::Operand::Constant(Box::new(mir::Constant {
143-
span: DUMMY_SP,
144-
ty: tcx.types.usize,
145-
literal: mir::Literal::Value {
146-
value: ConstVal::Integral(ConstInt::Usize(ConstUsize::new(0, tcx.sess.target.uint_type).unwrap())),
147-
},
148-
})))
149-
)
150-
},
151-
mir::Statement {
152-
source_info,
153-
kind: mir::StatementKind::Assign(
154-
mir::Lvalue::Local(mir::Local::new(3)),
155-
mir::Rvalue::Len(mir::Lvalue::Projection(Box::new(mir::LvalueProjection {
156-
base: mir::Lvalue::Local(mir::Local::new(1)),
157-
elem: mir::ProjectionElem::Deref,
158-
}))),
159-
)
160-
},
161-
],
162-
terminator: Some(mir::Terminator {
163-
source_info: source_info,
164-
kind: mir::TerminatorKind::Goto { target: mir::BasicBlock::new(1) },
165-
}),
166-
is_cleanup: false
167-
};
168-
// head: done = i == len; switch done { 1 => ret, 0 => loop }
169-
let head = mir::BasicBlockData {
170-
statements: vec![
171-
mir::Statement {
172-
source_info,
173-
kind: mir::StatementKind::Assign(
174-
mir::Lvalue::Local(mir::Local::new(4)),
175-
mir::Rvalue::BinaryOp(
176-
mir::BinOp::Eq,
177-
mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(2))),
178-
mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(3))),
179-
)
180-
)
181-
},
182-
],
183-
terminator: Some(mir::Terminator {
184-
source_info: source_info,
185-
kind: mir::TerminatorKind::SwitchInt {
186-
targets: vec![
187-
mir::BasicBlock::new(2),
188-
mir::BasicBlock::new(4),
189-
],
190-
discr: mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(4))),
191-
switch_ty: tcx.types.bool,
192-
values: vec![ConstInt::U8(0)].into(),
193-
},
194-
}),
195-
is_cleanup: false
196-
};
197-
// loop: drop (*a0)[i]; goto inc;
198-
let loop_ = mir::BasicBlockData {
199-
statements: Vec::new(),
200-
terminator: Some(mir::Terminator {
201-
source_info: source_info,
202-
kind: mir::TerminatorKind::Drop {
203-
target: mir::BasicBlock::new(3),
204-
unwind: None,
205-
location: mir::Lvalue::Projection(Box::new(
206-
mir::LvalueProjection {
207-
base: mir::Lvalue::Projection(Box::new(
208-
mir::LvalueProjection {
209-
base: mir::Lvalue::Local(mir::Local::new(1)),
210-
elem: mir::ProjectionElem::Deref,
211-
}
212-
)),
213-
elem: mir::ProjectionElem::Index(mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(2)))),
214-
}
215-
)),
216-
},
217-
}),
218-
is_cleanup: false
219-
};
220-
// inc: i++; goto head;
221-
let inc = mir::BasicBlockData {
222-
statements: vec![
223-
mir::Statement {
224-
source_info,
225-
kind: mir::StatementKind::Assign(
226-
mir::Lvalue::Local(mir::Local::new(2)),
227-
mir::Rvalue::BinaryOp(
228-
mir::BinOp::Add,
229-
mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(2))),
230-
mir::Operand::Constant(Box::new(mir::Constant {
231-
span: DUMMY_SP,
232-
ty: tcx.types.usize,
233-
literal: mir::Literal::Value {
234-
value: ConstVal::Integral(ConstInt::Usize(ConstUsize::new(1, tcx.sess.target.uint_type).unwrap())),
235-
},
236-
})),
237-
)
238-
)
239-
},
240-
],
241-
terminator: Some(mir::Terminator {
242-
source_info: source_info,
243-
kind: mir::TerminatorKind::Goto { target: mir::BasicBlock::new(1) },
244-
}),
245-
is_cleanup: false
246-
};
247-
// ret: return;
248-
let ret = mir::BasicBlockData {
249-
statements: Vec::new(),
250-
terminator: Some(mir::Terminator {
251-
source_info: source_info,
252-
kind: mir::TerminatorKind::Return,
253-
}),
254-
is_cleanup: false
255-
};
256-
let locals = vec![
257-
mir::LocalDecl {
258-
mutability: mir::Mutability::Mut,
259-
ty: tcx.mk_nil(),
260-
name: None,
261-
source_info,
262-
is_user_variable: false,
263-
},
264-
mir::LocalDecl {
265-
mutability: mir::Mutability::Mut,
266-
ty: tcx.mk_mut_ptr(tcx.mk_slice(tcx.mk_param(0, Symbol::intern("T")))),
267-
name: None,
268-
source_info,
269-
is_user_variable: false,
270-
},
271-
mir::LocalDecl {
272-
mutability: mir::Mutability::Mut,
273-
ty: tcx.types.usize,
274-
name: None,
275-
source_info,
276-
is_user_variable: false,
277-
},
278-
mir::LocalDecl {
279-
mutability: mir::Mutability::Mut,
280-
ty: tcx.types.usize,
281-
name: None,
282-
source_info,
283-
is_user_variable: false,
284-
},
285-
mir::LocalDecl {
286-
mutability: mir::Mutability::Mut,
287-
ty: tcx.types.bool,
288-
name: None,
289-
source_info,
290-
is_user_variable: false,
291-
},
292-
];
293-
let seq_drop_glue = mir::Mir::new(
294-
vec![start_block, head, loop_, inc, ret].into_iter().collect(),
295-
Vec::new().into_iter().collect(), // vis scopes
296-
Vec::new().into_iter().collect(), // promoted
297-
tcx.mk_nil(), // return type
298-
locals.into_iter().collect(),
299-
1, // arg_count
300-
Vec::new(), // upvars
301-
DUMMY_SP,
302-
);
303-
let seq_drop_glue = tcx.alloc_mir(seq_drop_glue);
304125
EvalContext {
305126
tcx,
306127
memory: Memory::new(&tcx.data_layout, limits.memory_size),
307128
globals: HashMap::new(),
308129
stack: Vec::new(),
309130
stack_limit: limits.stack_limit,
310131
steps_remaining: limits.step_limit,
311-
seq_drop_glue: seq_drop_glue,
312132
}
313133
}
314134

@@ -631,6 +451,18 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
631451
self.write_value(value, dest, dest_ty)?;
632452
}
633453

454+
BinaryOp(mir::BinOp::Offset, ref left, ref right) => {
455+
let pointer_ty = self.operand_ty(left);
456+
let pointee_ty = pointer_ty.builtin_deref(true, ty::LvaluePreference::NoPreference).expect("Offset called on non-ptr type").ty;
457+
// FIXME: assuming here that type size is < i64::max_value()
458+
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
459+
let offset = self.eval_operand_to_primval(right)?.to_i128()? as i64;
460+
461+
let ptr = self.eval_operand_to_primval(left)?.to_ptr()?;
462+
let result_ptr = ptr.signed_offset(offset * pointee_size);
463+
self.write_primval(dest, PrimVal::Ptr(result_ptr), dest_ty)?;
464+
}
465+
634466
BinaryOp(bin_op, ref left, ref right) => {
635467
// ignore overflow bit, rustc inserts check branches for us
636468
self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?;
@@ -823,8 +655,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
823655
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
824656
}
825657

826-
NullaryOp(mir::NullOp::SizeOf, _ty) => {
827-
unimplemented!()
658+
NullaryOp(mir::NullOp::SizeOf, ty) => {
659+
let size = self.type_size(ty)?.expect("SizeOf nullary MIR operator called for unsized type");
660+
self.write_primval(dest, PrimVal::from_u128(size as u128), dest_ty)?;
828661
}
829662

830663
Cast(kind, ref operand, cast_ty) => {

src/lvalue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
362362
let n_ptr = self.eval_operand(operand)?;
363363
let usize = self.tcx.types.usize;
364364
let n = self.value_to_primval(n_ptr, usize)?.to_u64()?;
365-
assert!(n < len);
365+
assert!(n < len, "Tried to access element {} of array/slice with length {}", n, len);
366366
let ptr = base_ptr.offset(n * elem_size);
367367
(ptr, LvalueExtra::None)
368368
}

src/terminator/drop.rs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use rustc::mir;
22
use rustc::ty::{self, Ty};
3-
use rustc::ty::subst::Kind;
43
use syntax::codemap::Span;
54

65
use error::EvalResult;
@@ -21,7 +20,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
2120
};
2221
self.drop(val, instance, ty, span)
2322
}
24-
pub(crate) fn drop(&mut self, mut arg: Value, mut instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> {
23+
pub(crate) fn drop(&mut self, arg: Value, mut instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> {
2524
trace!("drop: {:#?}, {:?}, {:?}", arg, ty.sty, instance.def);
2625

2726
if let ty::InstanceDef::DropGlue(_, None) = instance.def {
@@ -44,23 +43,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
4443
None => return Ok(()),
4544
}
4645
},
47-
ty::TyArray(elem, n) => {
48-
instance.substs = self.tcx.mk_substs([
49-
Kind::from(elem),
50-
].iter().cloned());
51-
let ptr = match arg {
52-
Value::ByVal(PrimVal::Ptr(src_ptr)) => src_ptr,
53-
_ => bug!("expected thin ptr, got {:?}", arg),
54-
};
55-
arg = Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(n as u128));
56-
self.seq_drop_glue
57-
},
58-
ty::TySlice(elem) => {
59-
instance.substs = self.tcx.mk_substs([
60-
Kind::from(elem),
61-
].iter().cloned());
62-
self.seq_drop_glue
63-
},
6446
_ => self.load_mir(instance.def)?,
6547
};
6648

src/terminator/intrinsic.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
360360

361361
"size_of" => {
362362
let ty = substs.type_at(0);
363-
// FIXME: change the `box_free` lang item to take `T: ?Sized` and have it use the
364-
// `size_of_val` intrinsic, then change this back to
365-
// .expect("size_of intrinsic called on unsized value")
366-
// see https://github.com/rust-lang/rust/pull/37708
367-
let size = self.type_size(ty)?.unwrap_or(!0) as u128;
363+
let size = self.type_size(ty)?.expect("size_of intrinsic called on unsized value") as u128;
368364
self.write_primval(dest, PrimVal::from_u128(size), dest_ty)?;
369365
}
370366

src/terminator/mod.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc::hir::def_id::DefId;
22
use rustc::mir;
3-
use rustc::ty::{self, TypeVariants, Ty, TypeAndMut};
3+
use rustc::ty::{self, TypeVariants, Ty};
44
use rustc::ty::layout::Layout;
55
use syntax::codemap::Span;
66
use syntax::attr;
@@ -730,12 +730,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
730730
let dtor = if dtor_ptr.is_null_ptr() { None } else { Some(self.memory.get_fn(dtor_ptr.alloc_id)?) };
731731

732732
// Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
733-
let key_size = match self.operand_ty(&arg_operands[0]).sty {
734-
TypeVariants::TyRawPtr(TypeAndMut { ty, .. }) => {
735-
let layout = self.type_layout(ty)?;
736-
layout.size(&self.tcx.data_layout)
737-
}
738-
_ => return Err(EvalError::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))
733+
let key_type = self.operand_ty(&arg_operands[0]).builtin_deref(true, ty::LvaluePreference::NoPreference)
734+
.ok_or(EvalError::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
735+
let key_size = {
736+
let layout = self.type_layout(key_type)?;
737+
layout.size(&self.tcx.data_layout)
739738
};
740739

741740
// Create key and write it into the memory where key_ptr wants it

tests/run-pass/call_drop_on_array_elements.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
struct Bar;
1+
struct Bar(i32); // ZSTs are tested separately
22

33
static mut DROP_COUNT: usize = 0;
44

@@ -9,8 +9,13 @@ impl Drop for Bar {
99
}
1010

1111
fn main() {
12-
let b = [Bar, Bar, Bar, Bar];
12+
let b = [Bar(0), Bar(0), Bar(0), Bar(0)];
1313
assert_eq!(unsafe { DROP_COUNT }, 0);
1414
drop(b);
1515
assert_eq!(unsafe { DROP_COUNT }, 4);
16+
17+
// check empty case
18+
let b : [Bar; 0] = [];
19+
drop(b);
20+
assert_eq!(unsafe { DROP_COUNT }, 4);
1621
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
struct Bar;
2+
3+
static mut DROP_COUNT: usize = 0;
4+
5+
impl Drop for Bar {
6+
fn drop(&mut self) {
7+
unsafe { DROP_COUNT += 1; }
8+
}
9+
}
10+
11+
fn main() {
12+
let b = [Bar, Bar, Bar, Bar];
13+
assert_eq!(unsafe { DROP_COUNT }, 0);
14+
drop(b);
15+
assert_eq!(unsafe { DROP_COUNT }, 4);
16+
17+
// check empty case
18+
let b : [Bar; 0] = [];
19+
drop(b);
20+
assert_eq!(unsafe { DROP_COUNT }, 4);
21+
}

0 commit comments

Comments
 (0)