pub struct ConstProp;
impl<'tcx> MirPass<'tcx> for ConstProp {
+ fn is_enabled(&self, _sess: &rustc_session::Session) -> bool {
+ // FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it
+ // runs even when MIR optimizations are disabled. We should separate the lint out from the
+ // transform and move the lint as early in the pipeline as possible.
+ true
+ }
+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// will be evaluated by miri and produce its errors there
if body.source.promoted.is_some() {
can_const_prop: IndexVec<Local, ConstPropMode>,
}
-impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
+impl ConstPropMachine<'_, '_> {
fn new(
only_propagate_inside_block_locals: BitSet<Local>,
can_const_prop: IndexVec<Local, ConstPropMode>,
_args: &[OpTy<'tcx>],
_ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
_unwind: StackPopUnwind,
- ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
+ ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
Ok(None)
}
throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
}
- fn box_alloc(
- _ecx: &mut InterpCx<'mir, 'tcx, Self>,
- _dest: &PlaceTy<'tcx>,
- ) -> InterpResult<'tcx> {
- throw_machine_stop_str!("can't const prop heap allocations")
- }
-
fn access_local(
_ecx: &InterpCx<'mir, 'tcx, Self>,
frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
}
#[inline(always)]
- fn stack(
+ fn stack<'a>(
ecx: &'a InterpCx<'mir, 'tcx, Self>,
) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
&ecx.machine.stack
}
#[inline(always)]
- fn stack_mut(
+ fn stack_mut<'a>(
ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
&mut ecx.machine.stack
source_info: Option<SourceInfo>,
}
-impl<'mir, 'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
#[inline]
}
}
-impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> {
+impl HasDataLayout for ConstPropagator<'_, '_> {
#[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}
-impl<'mir, 'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'_, 'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
}
-impl<'mir, 'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
#[inline]
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
Instance::new(def_id, substs),
dummy_body,
ret.as_ref(),
- StackPopCleanup::None { cleanup: false },
+ StackPopCleanup::Root { cleanup: false },
)
.expect("failed to push initial stack frame");
rvalue: &Rvalue<'tcx>,
place: Place<'tcx>,
) -> Option<()> {
- self.use_ecx(|this| {
- match rvalue {
- Rvalue::BinaryOp(op, box (left, right))
- | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
- let l = this.ecx.eval_operand(left, None);
- let r = this.ecx.eval_operand(right, None);
-
- let const_arg = match (l, r) {
- (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
- (Err(e), Err(_)) => return Err(e),
- (Ok(_), Ok(_)) => {
- this.ecx.eval_rvalue_into_place(rvalue, place)?;
- return Ok(());
- }
- };
-
- let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
- let dest = this.ecx.eval_place(place)?;
-
- match op {
- BinOp::BitAnd => {
- if arg_value == 0 {
- this.ecx.write_immediate(*const_arg, &dest)?;
- }
- }
- BinOp::BitOr => {
- if arg_value == const_arg.layout.size.truncate(u128::MAX)
- || (const_arg.layout.ty.is_bool() && arg_value == 1)
- {
- this.ecx.write_immediate(*const_arg, &dest)?;
- }
- }
- BinOp::Mul => {
- if const_arg.layout.ty.is_integral() && arg_value == 0 {
- if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
- let val = Immediate::ScalarPair(
- const_arg.to_scalar()?.into(),
- Scalar::from_bool(false).into(),
- );
- this.ecx.write_immediate(val, &dest)?;
- } else {
- this.ecx.write_immediate(*const_arg, &dest)?;
- }
- }
- }
- _ => {
- this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ self.use_ecx(|this| match rvalue {
+ Rvalue::BinaryOp(op, box (left, right))
+ | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
+ let l = this.ecx.eval_operand(left, None);
+ let r = this.ecx.eval_operand(right, None);
+
+ let const_arg = match (l, r) {
+ (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
+ (Err(e), Err(_)) => return Err(e),
+ (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
+ };
+
+ let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
+ let dest = this.ecx.eval_place(place)?;
+
+ match op {
+ BinOp::BitAnd if arg_value == 0 => this.ecx.write_immediate(*const_arg, &dest),
+ BinOp::BitOr
+ if arg_value == const_arg.layout.size.truncate(u128::MAX)
+ || (const_arg.layout.ty.is_bool() && arg_value == 1) =>
+ {
+ this.ecx.write_immediate(*const_arg, &dest)
+ }
+ BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
+ if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
+ let val = Immediate::ScalarPair(
+ const_arg.to_scalar()?.into(),
+ Scalar::from_bool(false).into(),
+ );
+ this.ecx.write_immediate(val, &dest)
+ } else {
+ this.ecx.write_immediate(*const_arg, &dest)
}
}
- }
- _ => {
- this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ _ => this.ecx.eval_rvalue_into_place(rvalue, place),
}
}
-
- Ok(())
+ _ => this.ecx.eval_rvalue_into_place(rvalue, place),
})
}
impl CanConstProp {
/// Returns true if `local` can be propagated
- fn check(
+ fn check<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
body: &Body<'tcx>,
}
}
-impl<'tcx> Visitor<'tcx> for CanConstProp {
+impl Visitor<'_> for CanConstProp {
fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
use rustc_middle::mir::visit::PlaceContext::*;
match context {
// These are just stores, where the storing is not propagatable, but there may be later
// mutations of the same local via `Store`
| MutatingUse(MutatingUseContext::Call)
+ | MutatingUse(MutatingUseContext::AsmOutput)
// Actual store that can possibly even propagate a value
| MutatingUse(MutatingUseContext::Store) => {
if !self.found_assignment.insert(local) {
// These could be propagated with a smarter analysis or just some careful thinking about
// whether they'd be fine right now.
- MutatingUse(MutatingUseContext::AsmOutput)
+ MutatingUse(MutatingUseContext::LlvmAsmOutput)
| MutatingUse(MutatingUseContext::Yield)
| MutatingUse(MutatingUseContext::Drop)
| MutatingUse(MutatingUseContext::Retag)
}
}
-impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}