refactor AbstractConstBuilder
This commit is contained in:
parent
c3a772f55f
commit
f24d532749
@ -187,70 +187,79 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Option<()> {
|
||||||
|
debug!("AbstractConstBuilder: stmt={:?}", stmt);
|
||||||
|
match stmt.kind {
|
||||||
|
StatementKind::Assign(box (ref place, ref rvalue)) => {
|
||||||
|
let local = place.as_local()?;
|
||||||
|
match *rvalue {
|
||||||
|
Rvalue::Use(ref operand) => {
|
||||||
|
self.locals[local] = self.operand_to_node(operand)?;
|
||||||
|
}
|
||||||
|
Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
|
||||||
|
let lhs = self.operand_to_node(lhs)?;
|
||||||
|
let rhs = self.operand_to_node(rhs)?;
|
||||||
|
self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
|
||||||
|
if op.is_checkable() {
|
||||||
|
bug!("unexpected unchecked checkable binary operation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
|
||||||
|
let lhs = self.operand_to_node(lhs)?;
|
||||||
|
let rhs = self.operand_to_node(rhs)?;
|
||||||
|
self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
|
||||||
|
self.checked_op_locals.insert(local);
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_terminator(
|
||||||
|
&mut self,
|
||||||
|
terminator: &mir::Terminator<'tcx>,
|
||||||
|
) -> Option<Option<mir::BasicBlock>> {
|
||||||
|
debug!("AbstractConstBuilder: terminator={:?}", terminator);
|
||||||
|
match terminator.kind {
|
||||||
|
TerminatorKind::Goto { target } => Some(Some(target)),
|
||||||
|
TerminatorKind::Return => Some(None),
|
||||||
|
TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
|
||||||
|
let p = match cond {
|
||||||
|
mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
|
||||||
|
mir::Operand::Constant(_) => bug!("Unexpected assert"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
|
||||||
|
debug!("proj: {:?}", p.projection);
|
||||||
|
if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
|
||||||
|
// Only allow asserts checking the result of a checked operation.
|
||||||
|
if self.checked_op_locals.contains(p.local) {
|
||||||
|
return Some(Some(target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build(mut self) -> Option<&'tcx [Node<'tcx>]> {
|
fn build(mut self) -> Option<&'tcx [Node<'tcx>]> {
|
||||||
let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
|
let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
|
||||||
loop {
|
loop {
|
||||||
debug!("AbstractConstBuilder: block={:?}", block);
|
debug!("AbstractConstBuilder: block={:?}", block);
|
||||||
for stmt in block.statements.iter() {
|
for stmt in block.statements.iter() {
|
||||||
debug!("AbstractConstBuilder: stmt={:?}", stmt);
|
self.build_statement(stmt)?;
|
||||||
match stmt.kind {
|
|
||||||
StatementKind::Assign(box (ref place, ref rvalue)) => {
|
|
||||||
let local = place.as_local()?;
|
|
||||||
match *rvalue {
|
|
||||||
Rvalue::Use(ref operand) => {
|
|
||||||
self.locals[local] = self.operand_to_node(operand)?;
|
|
||||||
}
|
|
||||||
Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => {
|
|
||||||
let lhs = self.operand_to_node(lhs)?;
|
|
||||||
let rhs = self.operand_to_node(rhs)?;
|
|
||||||
self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
|
|
||||||
if op.is_checkable() {
|
|
||||||
bug!("unexpected unchecked checkable binary operation");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs)
|
|
||||||
if Self::check_binop(op) =>
|
|
||||||
{
|
|
||||||
let lhs = self.operand_to_node(lhs)?;
|
|
||||||
let rhs = self.operand_to_node(rhs)?;
|
|
||||||
self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs));
|
|
||||||
self.checked_op_locals.insert(local);
|
|
||||||
}
|
|
||||||
_ => return None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("AbstractConstBuilder: terminator={:?}", block.terminator());
|
if let Some(next) = self.build_terminator(block.terminator())? {
|
||||||
match block.terminator().kind {
|
block = &self.body.basic_blocks()[next];
|
||||||
TerminatorKind::Goto { target } => {
|
} else {
|
||||||
block = &self.body.basic_blocks()[target];
|
return Some(self.tcx.arena.alloc_from_iter(self.nodes));
|
||||||
}
|
|
||||||
TerminatorKind::Return => {
|
|
||||||
warn!(?self.nodes);
|
|
||||||
return { Some(self.tcx.arena.alloc_from_iter(self.nodes)) };
|
|
||||||
}
|
|
||||||
TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
|
|
||||||
let p = match cond {
|
|
||||||
mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
|
|
||||||
mir::Operand::Constant(_) => bug!("Unexpected assert"),
|
|
||||||
};
|
|
||||||
|
|
||||||
const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
|
|
||||||
debug!("proj: {:?}", p.projection);
|
|
||||||
if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
|
|
||||||
// Only allow asserts checking the result of a checked operation.
|
|
||||||
if self.checked_op_locals.contains(p.local) {
|
|
||||||
block = &self.body.basic_blocks()[target];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
_ => return None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,11 +270,11 @@ pub(super) fn mir_abstract_const<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def: ty::WithOptConstParam<LocalDefId>,
|
def: ty::WithOptConstParam<LocalDefId>,
|
||||||
) -> Option<&'tcx [Node<'tcx>]> {
|
) -> Option<&'tcx [Node<'tcx>]> {
|
||||||
if !tcx.features().const_evaluatable_checked {
|
if tcx.features().const_evaluatable_checked {
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let body = tcx.mir_const(def).borrow();
|
let body = tcx.mir_const(def).borrow();
|
||||||
AbstractConstBuilder::new(tcx, &body)?.build()
|
AbstractConstBuilder::new(tcx, &body)?.build()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user