Roll our own MIR for dropping arrays.
This commit is contained in:
parent
030f00a8a1
commit
7c12ebc78d
@ -5,6 +5,7 @@ use std::fmt::Write;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::map::definitions::DefPathData;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc_const_math::{ConstInt, ConstUsize};
|
||||
use rustc::mir;
|
||||
use rustc::traits::Reveal;
|
||||
use rustc::ty::layout::{self, Layout, Size};
|
||||
@ -44,6 +45,9 @@ pub struct EvalContext<'a, 'tcx: 'a> {
|
||||
/// This prevents infinite loops and huge computations from freezing up const eval.
|
||||
/// Remove once halting problem is solved.
|
||||
pub(crate) steps_remaining: u64,
|
||||
|
||||
/// Drop glue for arrays and slices
|
||||
pub(crate) seq_drop_glue: MirRef<'tcx>,
|
||||
}
|
||||
|
||||
/// A stack frame.
|
||||
@ -124,6 +128,176 @@ impl Default for ResourceLimits {
|
||||
|
||||
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, limits: ResourceLimits) -> Self {
|
||||
let source_info = mir::SourceInfo {
|
||||
span: DUMMY_SP,
|
||||
scope: mir::ARGUMENT_VISIBILITY_SCOPE
|
||||
};
|
||||
// i = 0; len = Len(*a0); goto head;
|
||||
let start_block = mir::BasicBlockData {
|
||||
statements: vec![
|
||||
mir::Statement {
|
||||
source_info,
|
||||
kind: mir::StatementKind::Assign(
|
||||
mir::Lvalue::Local(mir::Local::new(2)),
|
||||
mir::Rvalue::Use(mir::Operand::Constant(mir::Constant {
|
||||
span: DUMMY_SP,
|
||||
ty: tcx.types.usize,
|
||||
literal: mir::Literal::Value {
|
||||
value: ConstVal::Integral(ConstInt::Usize(ConstUsize::new(0, tcx.sess.target.uint_type).unwrap())),
|
||||
},
|
||||
}))
|
||||
)
|
||||
},
|
||||
mir::Statement {
|
||||
source_info,
|
||||
kind: mir::StatementKind::Assign(
|
||||
mir::Lvalue::Local(mir::Local::new(3)),
|
||||
mir::Rvalue::Len(mir::Lvalue::Projection(Box::new(mir::LvalueProjection {
|
||||
base: mir::Lvalue::Local(mir::Local::new(1)),
|
||||
elem: mir::ProjectionElem::Deref,
|
||||
}))),
|
||||
)
|
||||
},
|
||||
],
|
||||
terminator: Some(mir::Terminator {
|
||||
source_info: source_info,
|
||||
kind: mir::TerminatorKind::Goto { target: mir::BasicBlock::new(1) },
|
||||
}),
|
||||
is_cleanup: false
|
||||
};
|
||||
// head: done = i == len; switch done { 1 => ret, 0 => loop }
|
||||
let head = mir::BasicBlockData {
|
||||
statements: vec![
|
||||
mir::Statement {
|
||||
source_info,
|
||||
kind: mir::StatementKind::Assign(
|
||||
mir::Lvalue::Local(mir::Local::new(4)),
|
||||
mir::Rvalue::BinaryOp(
|
||||
mir::BinOp::Eq,
|
||||
mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(2))),
|
||||
mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(3))),
|
||||
)
|
||||
)
|
||||
},
|
||||
],
|
||||
terminator: Some(mir::Terminator {
|
||||
source_info: source_info,
|
||||
kind: mir::TerminatorKind::SwitchInt {
|
||||
targets: vec![
|
||||
mir::BasicBlock::new(2),
|
||||
mir::BasicBlock::new(4),
|
||||
],
|
||||
discr: mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(4))),
|
||||
switch_ty: tcx.types.bool,
|
||||
values: vec![ConstInt::U8(0)].into(),
|
||||
},
|
||||
}),
|
||||
is_cleanup: false
|
||||
};
|
||||
// loop: drop (*a0)[i]; goto inc;
|
||||
let loop_ = mir::BasicBlockData {
|
||||
statements: Vec::new(),
|
||||
terminator: Some(mir::Terminator {
|
||||
source_info: source_info,
|
||||
kind: mir::TerminatorKind::Drop {
|
||||
target: mir::BasicBlock::new(3),
|
||||
unwind: None,
|
||||
location: mir::Lvalue::Projection(Box::new(
|
||||
mir::LvalueProjection {
|
||||
base: mir::Lvalue::Projection(Box::new(
|
||||
mir::LvalueProjection {
|
||||
base: mir::Lvalue::Local(mir::Local::new(1)),
|
||||
elem: mir::ProjectionElem::Deref,
|
||||
}
|
||||
)),
|
||||
elem: mir::ProjectionElem::Index(mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(2)))),
|
||||
}
|
||||
)),
|
||||
},
|
||||
}),
|
||||
is_cleanup: false
|
||||
};
|
||||
// inc: i++; goto head;
|
||||
let inc = mir::BasicBlockData {
|
||||
statements: vec![
|
||||
mir::Statement {
|
||||
source_info,
|
||||
kind: mir::StatementKind::Assign(
|
||||
mir::Lvalue::Local(mir::Local::new(2)),
|
||||
mir::Rvalue::BinaryOp(
|
||||
mir::BinOp::Add,
|
||||
mir::Operand::Consume(mir::Lvalue::Local(mir::Local::new(2))),
|
||||
mir::Operand::Constant(mir::Constant {
|
||||
span: DUMMY_SP,
|
||||
ty: tcx.types.usize,
|
||||
literal: mir::Literal::Value {
|
||||
value: ConstVal::Integral(ConstInt::Usize(ConstUsize::new(0, tcx.sess.target.uint_type).unwrap())),
|
||||
},
|
||||
}),
|
||||
)
|
||||
)
|
||||
},
|
||||
],
|
||||
terminator: Some(mir::Terminator {
|
||||
source_info: source_info,
|
||||
kind: mir::TerminatorKind::Goto { target: mir::BasicBlock::new(1) },
|
||||
}),
|
||||
is_cleanup: false
|
||||
};
|
||||
// ret: return;
|
||||
let ret = mir::BasicBlockData {
|
||||
statements: Vec::new(),
|
||||
terminator: Some(mir::Terminator {
|
||||
source_info: source_info,
|
||||
kind: mir::TerminatorKind::Return,
|
||||
}),
|
||||
is_cleanup: false
|
||||
};
|
||||
let locals = vec![
|
||||
mir::LocalDecl {
|
||||
mutability: mir::Mutability::Mut,
|
||||
ty: tcx.mk_nil(),
|
||||
name: None,
|
||||
source_info: None,
|
||||
},
|
||||
mir::LocalDecl {
|
||||
mutability: mir::Mutability::Mut,
|
||||
ty: tcx.mk_mut_ptr(tcx.mk_self_type()),
|
||||
name: None,
|
||||
source_info: None,
|
||||
},
|
||||
mir::LocalDecl {
|
||||
mutability: mir::Mutability::Mut,
|
||||
ty: tcx.types.usize,
|
||||
name: None,
|
||||
source_info: None,
|
||||
},
|
||||
mir::LocalDecl {
|
||||
mutability: mir::Mutability::Mut,
|
||||
ty: tcx.types.usize,
|
||||
name: None,
|
||||
source_info: None,
|
||||
},
|
||||
mir::LocalDecl {
|
||||
mutability: mir::Mutability::Mut,
|
||||
ty: tcx.types.bool,
|
||||
name: None,
|
||||
source_info: None,
|
||||
},
|
||||
];
|
||||
let seq_drop_glue = mir::Mir::new(
|
||||
vec![start_block, head, loop_, inc, ret].into_iter().collect(),
|
||||
Vec::new().into_iter().collect(), // vis scopes
|
||||
Vec::new().into_iter().collect(), // promoted
|
||||
tcx.mk_nil(), // return type
|
||||
locals.into_iter().collect(),
|
||||
1, // arg_count
|
||||
Vec::new(), // upvars
|
||||
DUMMY_SP,
|
||||
);
|
||||
let seq_drop_glue = tcx.alloc_mir(seq_drop_glue);
|
||||
// Perma-borrow MIR from shims to prevent mutation.
|
||||
::std::mem::forget(seq_drop_glue.borrow());
|
||||
EvalContext {
|
||||
tcx,
|
||||
memory: Memory::new(&tcx.data_layout, limits.memory_size),
|
||||
@ -131,6 +305,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
stack: Vec::new(),
|
||||
stack_limit: limits.stack_limit,
|
||||
steps_remaining: limits.step_limit,
|
||||
seq_drop_glue: seq_drop_glue.borrow(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1958,3 +2133,13 @@ fn fulfill_obligation<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
vtable
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve_drop_in_place<'a, 'tcx>(
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> ty::Instance<'tcx>
|
||||
{
|
||||
let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem);
|
||||
let substs = tcx.intern_substs(&[Kind::from(ty)]);
|
||||
resolve(tcx, def_id, substs)
|
||||
}
|
||||
|
@ -80,18 +80,22 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
let src_ptr = self.force_allocation(lval)?.to_ptr();
|
||||
|
||||
let ty = self.lvalue_ty(location);
|
||||
let ty = ::eval_context::apply_param_substs(self.tcx, self.substs(), &ty);
|
||||
|
||||
self.goto_block(target);
|
||||
let drop_in_place = self.tcx.lang_items.drop_in_place_fn().expect("drop_in_place lang item not available");
|
||||
let env = self.tcx.empty_parameter_environment();
|
||||
let def = if self.tcx.type_needs_drop_given_env(ty, &env) {
|
||||
ty::InstanceDef::DropGlue(drop_in_place, Some(ty))
|
||||
} else {
|
||||
ty::InstanceDef::DropGlue(drop_in_place, None)
|
||||
let instance = ::eval_context::resolve_drop_in_place(self.tcx, ty);
|
||||
|
||||
if let ty::InstanceDef::DropGlue(_, None) = instance.def {
|
||||
// we don't actually need to drop anything
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mir = match ty.sty {
|
||||
ty::TyDynamic(..) => unimplemented!(),
|
||||
ty::TyArray(..) | ty::TySlice(..) => ::eval_context::MirRef::clone(&self.seq_drop_glue),
|
||||
_ => self.load_mir(instance.def)?,
|
||||
};
|
||||
let substs = self.substs();
|
||||
let instance = ty::Instance { substs, def };
|
||||
let mir = self.load_mir(instance.def)?;
|
||||
|
||||
self.push_stack_frame(
|
||||
instance,
|
||||
terminator.source_info.span,
|
||||
@ -162,19 +166,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
self.dump_local(ret);
|
||||
Ok(())
|
||||
},
|
||||
/*Abi::C => {
|
||||
let sig = self.erase_lifetimes(&sig);
|
||||
let ty = sig.output();
|
||||
let (ret, target) = destination.unwrap();
|
||||
match instance.def {
|
||||
ty::InstanceDef::Item(_) => {},
|
||||
_ => bug!("C abi function must be InstanceDef::Item"),
|
||||
}
|
||||
self.call_c_abi(instance.def_id(), arg_operands, ret, ty)?;
|
||||
self.dump_local(ret);
|
||||
self.goto_block(target);
|
||||
Ok(())
|
||||
},*/
|
||||
ty::InstanceDef::ClosureOnceShim{..} => {
|
||||
let mut args = Vec::new();
|
||||
for arg in arg_operands {
|
||||
@ -198,7 +189,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
args.push((arg_val, arg_ty));
|
||||
}
|
||||
match sig.abi {
|
||||
Abi::C => unimplemented!(),
|
||||
Abi::C => {
|
||||
let ty = sig.output();
|
||||
let (ret, target) = destination.unwrap();
|
||||
self.call_c_abi(instance.def_id(), arg_operands, ret, ty)?;
|
||||
self.dump_local(ret);
|
||||
self.goto_block(target);
|
||||
return Ok(());
|
||||
},
|
||||
Abi::Rust => {},
|
||||
Abi::RustCall => self.unpack_fn_args(&mut args)?,
|
||||
_ => unimplemented!(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user