Skip to content

Commit

Permalink
Cleanup const_prop() some
Browse files Browse the repository at this point in the history
  • Loading branch information
wesleywiser committed Sep 30, 2019
1 parent b3234a3 commit 5804c3b
Showing 1 changed file with 75 additions and 72 deletions.
147 changes: 75 additions & 72 deletions src/librustc_mir/transform/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
struct ConstPropMachine;

impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
type MemoryKinds= !;
type MemoryKinds = !;
type PointerTag = ();
type ExtraFnVal = !;

Expand Down Expand Up @@ -460,79 +460,80 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let span = source_info.span;

// perform any special checking for specific Rvalue types
if let Rvalue::UnaryOp(op, arg) = rvalue {
trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
let overflow_check = self.tcx.sess.overflow_checks();

self.use_ecx(source_info, |this| {
// We check overflow in debug mode already
// so should only check in release mode.
if *op == UnOp::Neg && !overflow_check {
let ty = arg.ty(&this.local_decls, this.tcx);

if ty.is_integral() {
let arg = this.ecx.eval_operand(arg, None)?;
let prim = this.ecx.read_immediate(arg)?;
// Need to do overflow check here: For actual CTFE, MIR
// generation emits code that does this before calling the op.
if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
throw_panic!(OverflowNeg)
match rvalue {
Rvalue::UnaryOp(UnOp::Neg, arg) => {
trace!("checking UnaryOp(op = Neg, arg = {:?})", arg);
let overflow_check = self.tcx.sess.overflow_checks();

self.use_ecx(source_info, |this| {
// We check overflow in debug mode already
// so should only check in release mode.
if !overflow_check {
let ty = arg.ty(&this.local_decls, this.tcx);

if ty.is_integral() {
let arg = this.ecx.eval_operand(arg, None)?;
let prim = this.ecx.read_immediate(arg)?;
// Need to do overflow check here: For actual CTFE, MIR
// generation emits code that does this before calling the op.
if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
throw_panic!(OverflowNeg)
}
}
}
}

Ok(())
})?;
} else if let Rvalue::BinaryOp(op, left, right) = rvalue {
trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);

let r = self.use_ecx(source_info, |this| {
this.ecx.read_immediate(this.ecx.eval_operand(right, None)?)
})?;
if *op == BinOp::Shr || *op == BinOp::Shl {
let left_bits = place_layout.size.bits();
let right_size = r.layout.size;
let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
if r_bits.ok().map_or(false, |b| b >= left_bits as u128) {
let source_scope_local_data = match self.source_scope_local_data {
ClearCrossCrate::Set(ref data) => data,
ClearCrossCrate::Clear => return None,
};
let dir = if *op == BinOp::Shr {
"right"
} else {
"left"
};
let hir_id = source_scope_local_data[source_info.scope].lint_root;
self.tcx.lint_hir(
::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
hir_id,
span,
&format!("attempt to shift {} with overflow", dir));
return None;
}
Ok(())
})?;
}
self.use_ecx(source_info, |this| {
let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?;

// We check overflow in debug mode already
// so should only check in release mode.
if !this.tcx.sess.overflow_checks() && overflow {
let err = err_panic!(Overflow(*op)).into();
return Err(err);

Rvalue::BinaryOp(op, left, right) => {
trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);

let r = self.use_ecx(source_info, |this| {
this.ecx.read_immediate(this.ecx.eval_operand(right, None)?)
})?;
if *op == BinOp::Shr || *op == BinOp::Shl {
let left_bits = place_layout.size.bits();
let right_size = r.layout.size;
let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
if r_bits.ok().map_or(false, |b| b >= left_bits as u128) {
let source_scope_local_data = match self.source_scope_local_data {
ClearCrossCrate::Set(ref data) => data,
ClearCrossCrate::Clear => return None,
};
let dir = if *op == BinOp::Shr {
"right"
} else {
"left"
};
let hir_id = source_scope_local_data[source_info.scope].lint_root;
self.tcx.lint_hir(
::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
hir_id,
span,
&format!("attempt to shift {} with overflow", dir));
return None;
}
}
self.use_ecx(source_info, |this| {
let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?;

// We check overflow in debug mode already
// so should only check in release mode.
if !this.tcx.sess.overflow_checks() && overflow {
let err = err_panic!(Overflow(*op)).into();
return Err(err);
}

Ok(())
})?;
} else if let Rvalue::Ref(_, _, place) = rvalue {
trace!("checking Ref({:?})", place);
// FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
// from a function argument that hasn't been assigned to in this function.
if let Place {
base: PlaceBase::Local(local),
projection: box []
} = place {
Ok(())
})?;
}

Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => {
trace!("checking Ref({:?})", place);
// FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
// from a function argument that hasn't been assigned to in this function.
let alive =
if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value {
true
Expand All @@ -543,12 +544,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}
}
} else if let Rvalue::Aggregate(_, operands) = rvalue {
// FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that
// `SimplifyLocals` doesn't know it can remove.
if operands.len() == 0 {

Rvalue::Aggregate(_, operands) if operands.len() == 0 => {
// FIXME(wesleywiser): const eval will turn this into a `const Scalar(<ZST>)` that
// `SimplifyLocals` doesn't know it can remove.
return None;
}

_ => { }
}

self.use_ecx(source_info, |this| {
Expand Down

0 comments on commit 5804c3b

Please sign in to comment.