From 6319bee585561a078de4a0f8d07d567ce69cf12c Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 16 Nov 2025 19:21:17 +0000 Subject: [PATCH] Introduce Operand::RuntimeChecks. --- .../src/diagnostics/explain_borrow.rs | 2 + compiler/rustc_borrowck/src/lib.rs | 4 +- .../src/polonius/legacy/loan_invalidations.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_codegen_cranelift/src/base.rs | 8 +++- .../rustc_codegen_cranelift/src/constant.rs | 9 ++--- compiler/rustc_codegen_ssa/src/mir/operand.rs | 19 +++++---- .../src/check_consts/qualifs.rs | 1 + .../src/const_eval/dummy_machine.rs | 7 ++++ .../src/const_eval/machine.rs | 10 +++++ .../rustc_const_eval/src/interpret/machine.rs | 12 +----- .../rustc_const_eval/src/interpret/operand.rs | 9 +++-- .../rustc_const_eval/src/interpret/step.rs | 2 +- compiler/rustc_middle/src/mir/consts.rs | 39 ++----------------- compiler/rustc_middle/src/mir/mod.rs | 7 ++-- compiler/rustc_middle/src/mir/pretty.rs | 3 +- compiler/rustc_middle/src/mir/statement.rs | 8 ++-- compiler/rustc_middle/src/mir/syntax.rs | 27 +++++++++++++ compiler/rustc_middle/src/mir/visit.rs | 1 + .../src/builder/custom/parse.rs | 1 + compiler/rustc_mir_build/src/builder/scope.rs | 4 +- .../src/move_paths/builder.rs | 5 ++- .../rustc_mir_transform/src/cost_checker.rs | 2 +- .../src/dataflow_const_prop.rs | 4 +- .../src/early_otherwise_branch.rs | 6 +-- .../src/function_item_references.rs | 7 +--- compiler/rustc_mir_transform/src/gvn.rs | 10 +++++ .../rustc_mir_transform/src/instsimplify.rs | 14 ++++--- .../rustc_mir_transform/src/jump_threading.rs | 1 + .../src/known_panics_lint.rs | 1 + compiler/rustc_mir_transform/src/lib.rs | 2 +- .../src/lower_intrinsics.rs | 9 +---- .../rustc_mir_transform/src/promote_consts.rs | 3 ++ .../src/simplify_branches.rs | 2 +- compiler/rustc_mir_transform/src/sroa.rs | 13 ++++--- compiler/rustc_public/src/alloc.rs | 1 - compiler/rustc_public/src/mir/body.rs | 12 ++++++ compiler/rustc_public/src/mir/pretty.rs | 1 + compiler/rustc_public/src/mir/visit.rs | 1 + compiler/rustc_public/src/ty.rs | 11 ------ .../src/unstable/convert/stable/mir.rs | 16 +++----- compiler/rustc_public/src/visitor.rs | 4 +- .../clippy_utils/src/mir/possible_borrower.rs | 4 +- .../clippy_utils/src/qualify_min_const_fn.rs | 1 + tests/codegen-llvm/slice-iter-len-eq-zero.rs | 8 ++-- 45 files changed, 167 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 8e18bf557758..743a28822eb9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -764,6 +764,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { { // Just point to the function, to reduce the chance of overlapping spans. let function_span = match func { + Operand::RuntimeChecks(_) => span, Operand::Constant(c) => c.span, Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { @@ -809,6 +810,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { { // Just point to the function, to reduce the chance of overlapping spans. let function_span = match func { + Operand::RuntimeChecks(_) => span, Operand::Constant(c) => c.span, Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d15983075af2..72956f245bf9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1696,7 +1696,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { _ => propagate_closure_used_mut_place(self, place), } } - Operand::Constant(..) => {} + Operand::Constant(..) | Operand::RuntimeChecks(_) => {} } } @@ -1747,7 +1747,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { state, ); } - Operand::Constant(_) => {} + Operand::Constant(_) | Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 85a08b7399e5..d2eae2c7e65a 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -247,7 +247,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { LocalMutationIsAllowed::Yes, ); } - Operand::Constant(_) => {} + Operand::Constant(_) | Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 3507a1f8503c..097416b4f280 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1023,7 +1023,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // element, so we require the `Copy` trait. if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) { match operand { - Operand::Copy(..) | Operand::Constant(..) => { + Operand::Copy(..) | Operand::Constant(..) | Operand::RuntimeChecks(_) => { // These are always okay: direct use of a const, or a value that can // evidently be copied. } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 4dbee7665eb8..79f65141e66f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -8,10 +8,10 @@ use rustc_ast::InlineAsmOptions; use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; -use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{ScalarInt, TypeVisitableExt}; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -1039,6 +1039,12 @@ pub(crate) fn codegen_operand<'tcx>( cplace.to_cvalue(fx) } Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_), + Operand::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); + let layout = fx.layout_of(fx.tcx.types.bool); + return CValue::const_val(fx, layout, int); + } } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 29c8e8ab1e52..c25034d4be22 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -215,11 +215,6 @@ pub(crate) fn codegen_const_value<'tcx>( CValue::by_val(val, layout) } }, - ConstValue::RuntimeChecks(checks) => { - let int = checks.value(fx.tcx.sess); - let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); - return CValue::const_val(fx, layout, int); - } ConstValue::Indirect { alloc_id, offset } => CValue::by_ref( Pointer::new(pointer_for_allocation(fx, alloc_id)) .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), @@ -545,6 +540,10 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option { match operand { + Operand::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + ScalarInt::try_from_uint(int, Size::from_bits(1)) + } Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(), // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // inside a temporary before being passed to the intrinsic requiring the const argument. diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 29108043feff..aa80812388af 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -165,14 +165,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); OperandValue::Immediate(llval) } - mir::ConstValue::RuntimeChecks(checks) => { - let BackendRepr::Scalar(scalar) = layout.backend_repr else { - bug!("from_const: invalid ByVal layout: {:#?}", layout); - }; - let x = Scalar::from_bool(checks.value(bx.tcx().sess)); - let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); - OperandValue::Immediate(llval) - } ConstValue::ZeroSized => return OperandRef::zero_sized(layout), ConstValue::Slice { alloc_id, meta } => { let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else { @@ -1060,6 +1052,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandRef { move_annotation, ..self.codegen_consume(bx, place.as_ref()) } } + mir::Operand::RuntimeChecks(checks) => { + let layout = bx.layout_of(bx.tcx().types.bool); + let BackendRepr::Scalar(scalar) = layout.backend_repr else { + bug!("from_const: invalid ByVal layout: {:#?}", layout); + }; + let x = Scalar::from_bool(checks.value(bx.tcx().sess)); + let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); + let val = OperandValue::Immediate(llval); + OperandRef { val, layout, move_annotation: None } + } + mir::Operand::Constant(ref constant) => { let constant_ty = self.monomorphize(constant.ty()); // Most SIMD vector constants should be passed as immediates. diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 49a477d8fdba..42943648ffdd 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -338,6 +338,7 @@ where Operand::Copy(place) | Operand::Move(place) => { return in_place::(cx, in_local, place.as_ref()); } + Operand::RuntimeChecks(_) => return Q::in_any_value_of_ty(cx, cx.tcx.types.bool), Operand::Constant(c) => c, }; diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 438aed41b8be..40acff416bb0 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -122,6 +122,13 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { unimplemented!() } + #[inline(always)] + fn runtime_checks(_ecx: &InterpCx<'tcx, Self>, r: RuntimeChecks) -> InterpResult<'tcx, bool> { + // We can't look at `tcx.sess` here as that can differ across crates, which can lead to + // unsound differences in evaluating the same constant at different instantiation sites. + panic!("compiletime machine evaluated {r:?}") + } + fn binary_ptr_op( ecx: &InterpCx<'tcx, Self>, bin_op: BinOp, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 0c677b34df7b..7538130e9d92 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -637,6 +637,16 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { Err(ConstEvalErrKind::AssertFailure(err)).into() } + #[inline(always)] + fn runtime_checks( + _ecx: &InterpCx<'tcx, Self>, + _r: mir::RuntimeChecks, + ) -> InterpResult<'tcx, bool> { + // We can't look at `tcx.sess` here as that can differ across crates, which can lead to + // unsound differences in evaluating the same constant at different instantiation sites. + interp_ok(true) + } + fn binary_ptr_op( _ecx: &InterpCx<'tcx, Self>, _bin_op: mir::BinOp, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 753b2dd3b8ea..62ca47d23b4c 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -298,7 +298,7 @@ pub trait Machine<'tcx>: Sized { interp_ok(()) } - /// Determines the result of a `NullaryOp::RuntimeChecks` invocation. + /// Determines the result of a `Operand::RuntimeChecks` invocation. fn runtime_checks( _ecx: &InterpCx<'tcx, Self>, r: mir::RuntimeChecks, @@ -680,16 +680,6 @@ pub macro compile_time_machine(<$tcx: lifetime>) { true } - #[inline(always)] - fn runtime_checks( - _ecx: &InterpCx<$tcx, Self>, - _r: mir::RuntimeChecks, - ) -> InterpResult<$tcx, bool> { - // We can't look at `tcx.sess` here as that can differ across crates, which can lead to - // unsound differences in evaluating the same constant at different instantiation sites. - interp_ok(true) - } - #[inline(always)] fn adjust_global_allocation<'b>( _ecx: &InterpCx<$tcx, Self>, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 32d08d064923..9a956259ba57 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -845,6 +845,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // FIXME: do some more logic on `move` to invalidate the old location &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?, + &RuntimeChecks(checks) => { + let val = M::runtime_checks(self, checks)?; + ImmTy::from_bool(val, self.tcx()).into() + } + Constant(constant) => { let c = self.instantiate_from_current_frame_and_normalize_erasing_regions( constant.const_, @@ -892,10 +897,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO); Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self) } - mir::ConstValue::RuntimeChecks(checks) => { - let val = M::runtime_checks(self, checks)?; - Scalar::from_bool(val).into() - } }; interp_ok(OpTy { op: Operand::Immediate(imm), layout }) } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 47e8e2a9ec51..0ef4e4d4ae3c 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -387,7 +387,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { move_definitely_disjoint: bool, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { interp_ok(match op { - mir::Operand::Copy(_) | mir::Operand::Constant(_) => { + mir::Operand::Copy(_) | mir::Operand::Constant(_) | mir::Operand::RuntimeChecks(_) => { // Make a regular copy. let op = self.eval_operand(op, None)?; FnArg::Copy(op) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 1b7d3ec9345f..fe352df3b9f0 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -68,10 +68,6 @@ pub enum ConstValue { /// Offset into `alloc` offset: Size, }, - - /// Special constants whose value depends on the evaluation context. Their value depends on a - /// flag on the crate being codegenned. - RuntimeChecks(RuntimeChecks), } #[cfg(target_pointer_width = "64")] @@ -81,10 +77,7 @@ impl ConstValue { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { - ConstValue::Indirect { .. } - | ConstValue::Slice { .. } - | ConstValue::ZeroSized - | ConstValue::RuntimeChecks(_) => None, + ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None, ConstValue::Scalar(val) => Some(val), } } @@ -140,7 +133,7 @@ impl ConstValue { tcx: TyCtxt<'tcx>, ) -> Option<&'tcx [u8]> { let (alloc_id, start, len) = match self { - ConstValue::Scalar(_) | ConstValue::ZeroSized | ConstValue::RuntimeChecks(_) => { + ConstValue::Scalar(_) | ConstValue::ZeroSized => { bug!("`try_get_slice_bytes` on non-slice constant") } &ConstValue::Slice { alloc_id, meta } => (alloc_id, 0, meta), @@ -192,9 +185,7 @@ impl ConstValue { /// Can return `true` even if there is no provenance. pub fn may_have_provenance(&self, tcx: TyCtxt<'_>, size: Size) -> bool { match *self { - ConstValue::ZeroSized - | ConstValue::Scalar(Scalar::Int(_)) - | ConstValue::RuntimeChecks(_) => return false, + ConstValue::ZeroSized | ConstValue::Scalar(Scalar::Int(_)) => return false, ConstValue::Scalar(Scalar::Ptr(..)) => return true, // It's hard to find out the part of the allocation we point to; // just conservatively check everything. @@ -233,29 +224,6 @@ impl ConstValue { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum RuntimeChecks { - /// Returns whether we should perform some UB-checking at runtime. - /// See the `ub_checks` intrinsic docs for details. - UbChecks, - /// Returns whether we should perform contract-checking at runtime. - /// See the `contract_checks` intrinsic docs for details. - ContractChecks, - /// Returns whether we should perform some overflow-checking at runtime. - /// See the `overflow_checks` intrinsic docs for details. - OverflowChecks, -} - -impl RuntimeChecks { - pub fn value(self, sess: &rustc_session::Session) -> bool { - match self { - Self::UbChecks => sess.ub_checks(), - Self::ContractChecks => sess.contract_checks(), - Self::OverflowChecks => sess.overflow_checks(), - } - } -} - /////////////////////////////////////////////////////////////////////////// /// Constants @@ -549,7 +517,6 @@ impl<'tcx> Const<'tcx> { ConstValue::Slice { .. } | ConstValue::ZeroSized | ConstValue::Scalar(_) - | ConstValue::RuntimeChecks(_) | ConstValue::Indirect { .. }, _, ) => true, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index bffff1b400d5..418cdea01660 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -607,9 +607,6 @@ impl<'tcx> Body<'tcx> { typing_env, crate::ty::EarlyBinder::bind(constant.const_), ); - if let Const::Val(ConstValue::RuntimeChecks(check), _) = mono_literal { - return Some(check.value(tcx.sess) as u128); - } mono_literal.try_eval_bits(tcx, typing_env) }; @@ -623,6 +620,10 @@ impl<'tcx> Body<'tcx> { let bits = eval_mono_const(constant)?; return Some((bits, targets)); } + Operand::RuntimeChecks(check) => { + let bits = check.value(tcx.sess) as u128; + return Some((bits, targets)); + } Operand::Move(place) | Operand::Copy(place) => place, }; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index e4f85a115096..1ac46fff1b4e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1255,6 +1255,7 @@ impl<'tcx> Debug for Operand<'tcx> { Constant(ref a) => write!(fmt, "{a:?}"), Copy(ref place) => write!(fmt, "copy {place:?}"), Move(ref place) => write!(fmt, "move {place:?}"), + RuntimeChecks(checks) => write!(fmt, "const {checks:?}"), } } } @@ -1518,7 +1519,6 @@ pub fn write_allocations<'tcx>( match val { ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()), ConstValue::Scalar(interpret::Scalar::Int { .. }) => None, - ConstValue::RuntimeChecks(_) => None, ConstValue::ZeroSized => None, ConstValue::Slice { alloc_id, .. } | ConstValue::Indirect { alloc_id, .. } => { // FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR. @@ -1969,7 +1969,6 @@ fn pretty_print_const_value_tcx<'tcx>( fmt.write_str(&p.into_buffer())?; return Ok(()); } - (ConstValue::RuntimeChecks(checks), _) => return write!(fmt, "{checks:?}"), (ConstValue::ZeroSized, ty::FnDef(d, s)) => { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 942eb727de67..372b3313e13f 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -642,7 +642,7 @@ impl<'tcx> Operand<'tcx> { pub fn to_copy(&self) -> Self { match *self { - Operand::Copy(_) | Operand::Constant(_) => self.clone(), + Operand::Copy(_) | Operand::Constant(_) | Operand::RuntimeChecks(_) => self.clone(), Operand::Move(place) => Operand::Copy(place), } } @@ -652,7 +652,7 @@ impl<'tcx> Operand<'tcx> { pub fn place(&self) -> Option> { match self { Operand::Copy(place) | Operand::Move(place) => Some(*place), - Operand::Constant(_) => None, + Operand::Constant(_) | Operand::RuntimeChecks(_) => None, } } @@ -661,7 +661,7 @@ impl<'tcx> Operand<'tcx> { pub fn constant(&self) -> Option<&ConstOperand<'tcx>> { match self { Operand::Constant(x) => Some(&**x), - Operand::Copy(_) | Operand::Move(_) => None, + Operand::Copy(_) | Operand::Move(_) | Operand::RuntimeChecks(_) => None, } } @@ -681,6 +681,7 @@ impl<'tcx> Operand<'tcx> { match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, Operand::Constant(c) => c.const_.ty(), + Operand::RuntimeChecks(_) => tcx.types.bool, } } @@ -693,6 +694,7 @@ impl<'tcx> Operand<'tcx> { local_decls.local_decls()[l.local].source_info.span } Operand::Constant(c) => c.span, + Operand::RuntimeChecks(_) => DUMMY_SP, } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index e96d6824c600..037caa8bfae1 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1327,6 +1327,10 @@ pub enum Operand<'tcx> { /// Constants are already semantically values, and remain unchanged. Constant(Box>), + + /// Special constants whose value depends on the evaluation context. Their value depends on a + /// flag on the crate being codegenned. + RuntimeChecks(RuntimeChecks), } #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -1558,6 +1562,29 @@ pub enum AggregateKind<'tcx> { RawPtr(Ty<'tcx>, Mutability), } +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum RuntimeChecks { + /// Returns whether we should perform some UB-checking at runtime. + /// See the `ub_checks` intrinsic docs for details. + UbChecks, + /// Returns whether we should perform contract-checking at runtime. + /// See the `contract_checks` intrinsic docs for details. + ContractChecks, + /// Returns whether we should perform some overflow-checking at runtime. + /// See the `overflow_checks` intrinsic docs for details. + OverflowChecks, +} + +impl RuntimeChecks { + pub fn value(self, sess: &rustc_session::Session) -> bool { + match self { + Self::UbChecks => sess.ub_checks(), + Self::ContractChecks => sess.contract_checks(), + Self::OverflowChecks => sess.overflow_checks(), + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum UnOp { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index da9b2b97235e..07a36aef4320 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -845,6 +845,7 @@ macro_rules! make_mir_visitor { Operand::Constant(constant) => { self.visit_const_operand(constant, location); } + Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index 10154461c339..c6ef362c6ea5 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -261,6 +261,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let value = match operand { Operand::Constant(c) => VarDebugInfoContents::Const(*c), Operand::Copy(p) | Operand::Move(p) => VarDebugInfoContents::Place(p), + Operand::RuntimeChecks(_) => unreachable!(), }; let dbginfo = VarDebugInfo { name, diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 966598736220..a176f3e49a50 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1099,7 +1099,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(DropData { source_info, local, kind: DropKind::Value }) } - Operand::Constant(_) => None, + Operand::Constant(_) | Operand::RuntimeChecks(_) => None, }) .collect(); @@ -1563,7 +1563,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // look for moves of a local variable, like `MOVE(_X)` let locals_moved = operands.iter().flat_map(|operand| match operand.node { - Operand::Copy(_) | Operand::Constant(_) => None, + Operand::Copy(_) | Operand::Constant(_) | Operand::RuntimeChecks(_) => None, Operand::Move(place) => place.as_local(), }); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index a90f3ef35444..ced9bd735ba2 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -546,9 +546,10 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { fn gather_operand(&mut self, operand: &Operand<'tcx>) { match *operand { - Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move + // not-a-move + Operand::Constant(..) | Operand::Copy(..) | Operand::RuntimeChecks(_) => {} + // a move Operand::Move(place) => { - // a move self.gather_move(place); } } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 8f975866d135..aaf735269b22 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -103,7 +103,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { self.penalty += CALL_PENALTY; } TerminatorKind::SwitchInt { discr, targets } => { - if discr.constant().is_some() { + if matches!(discr, Operand::Constant(_) | Operand::RuntimeChecks(_)) { // Not only will this become a `Goto`, but likely other // things will be removable as unreachable. self.bonus += CONST_SWITCH_BONUS; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 232f07d31adb..011c10b8bd1d 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -211,6 +211,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { state: &mut State>, ) -> ValueOrPlace> { match operand { + Operand::RuntimeChecks(_) => ValueOrPlace::TOP, Operand::Constant(box constant) => { ValueOrPlace::Value(self.handle_constant(constant, state)) } @@ -530,6 +531,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { operand: &Operand<'tcx>, ) { match operand { + Operand::RuntimeChecks(_) => {} Operand::Copy(rhs) | Operand::Move(rhs) => { if let Some(rhs) = self.map.find(rhs.as_ref()) { state.insert_place_idx(place, rhs, &self.map); @@ -1036,7 +1038,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> { self.super_operand(operand, location) } } - Operand::Constant(_) => {} + Operand::Constant(_) | Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index da88e5c698bf..47d735eed9b1 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -117,11 +117,7 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { unreachable!() }; // Always correct since we can only switch on `Copy` types - let parent_op = match parent_op { - Operand::Move(x) => Operand::Copy(*x), - Operand::Copy(x) => Operand::Copy(*x), - Operand::Constant(x) => Operand::Constant(x.clone()), - }; + let parent_op = parent_op.to_copy(); let parent_ty = parent_op.ty(body.local_decls(), tcx); let statements_before = bbs[parent].statements.len(); let parent_end = Location { block: parent, statement_index: statements_before }; diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 38b5ccdb32e7..2ae8f43cf6c8 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -136,12 +136,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { } fn nth_arg_span(&self, args: &[Spanned>], n: usize) -> Span { - match &args[n].node { - Operand::Copy(place) | Operand::Move(place) => { - self.body.local_decls[place.local].source_info.span - } - Operand::Constant(constant) => constant.span, - } + args[n].node.span(&self.body.local_decls) } fn emit_lint( diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index f6bf678af5ba..5a4774154504 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -248,6 +248,7 @@ enum Value<'a, 'tcx> { Discriminant(VnIndex), // Operations. + RuntimeChecks(RuntimeChecks), UnaryOp(UnOp, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex), Cast { @@ -569,6 +570,8 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { _ if ty.is_zst() => ImmTy::uninit(ty).into(), Opaque(_) => return None, + // Keep runtime check constants as symbolic. + RuntimeChecks(..) => return None, // In general, evaluating repeat expressions just consumes a lot of memory. // But in the special case that the element is just Immediate::Uninit, we can evaluate @@ -1005,11 +1008,16 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { location: Location, ) -> Option { match *operand { + Operand::RuntimeChecks(c) => { + Some(self.insert(self.tcx.types.bool, Value::RuntimeChecks(c))) + } Operand::Constant(ref constant) => Some(self.insert_constant(constant.const_)), Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; if let Some(const_) = self.try_as_constant(value) { *operand = Operand::Constant(Box::new(const_)); + } else if let Value::RuntimeChecks(c) = self.get(value) { + *operand = Operand::RuntimeChecks(c); } Some(value) } @@ -1777,6 +1785,8 @@ impl<'tcx> VnState<'_, '_, 'tcx> { fn try_as_operand(&mut self, index: VnIndex, location: Location) -> Option> { if let Some(const_) = self.try_as_constant(index) { Some(Operand::Constant(Box::new(const_))) + } else if let Value::RuntimeChecks(c) = self.get(index) { + Some(Operand::RuntimeChecks(c)) } else if let Some(place) = self.try_as_place(index, location, false) { self.reused_locals.insert(place.local); Some(Operand::Copy(place)) diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 7cb341818fab..fa9ceb018dd5 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -363,11 +363,15 @@ impl<'tcx> MutVisitor<'tcx> for SimplifyUbCheck<'tcx> { } fn visit_operand(&mut self, operand: &mut Operand<'tcx>, _: Location) { - if let Operand::Constant(c) = operand - && let Const::Val(c, _) = &mut c.const_ - && let ConstValue::RuntimeChecks(RuntimeChecks::UbChecks) = c - { - *c = ConstValue::from_bool(self.tcx.sess.ub_checks()); + if let Operand::RuntimeChecks(RuntimeChecks::UbChecks) = operand { + *operand = Operand::Constant(Box::new(ConstOperand { + span: rustc_span::DUMMY_SP, + user_ty: None, + const_: Const::Val( + ConstValue::from_bool(self.tcx.sess.ub_checks()), + self.tcx.types.bool, + ), + })); } } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index c021e7d4c3ae..e2959ca64bda 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -477,6 +477,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; self.process_copy(lhs, rhs, state) } + Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 53cb02d9c5b2..caaf300a88d6 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -282,6 +282,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { /// or `eval_place`, depending on the variant of `Operand` used. fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { match *op { + Operand::RuntimeChecks(_) => None, Operand::Constant(ref c) => self.eval_constant(c), Operand::Move(place) | Operand::Copy(place) => self.eval_place(place), } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 6415f3908499..701d7ff854a7 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -261,7 +261,7 @@ fn remap_mir_for_const_eval_select<'tcx>( if context == hir::Constness::Const { called_in_const } else { called_at_rt }; let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args.node { - Operand::Constant(_) => { + Operand::Constant(_) | Operand::RuntimeChecks(_) => { // There is no good way of extracting a tuple arg from a constant // (const generic stuff) so we just create a temporary and deconstruct // that. diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 6740aa97fc8b..dcee54c37108 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -35,14 +35,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::Use(Operand::Constant(Box::new(ConstOperand { - span: terminator.source_info.span, - user_ty: None, - const_: Const::Val( - ConstValue::RuntimeChecks(op), - tcx.types.bool, - ), - }))), + Rvalue::Use(Operand::RuntimeChecks(op)), ))), )); terminator.kind = TerminatorKind::Goto { target }; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 506cfb7abf92..faff0f23143a 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -360,6 +360,9 @@ impl<'tcx> Validator<'_, 'tcx> { match operand { Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()), + // Promoting a runtime check would transform a runtime error into a compile-time error. + Operand::RuntimeChecks(_) => Err(Unpromotable), + // The qualifs for a constant (e.g. `HasMutInterior`) are checked in // `validate_rvalue` upon access. Operand::Constant(c) => { diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index ba2286fd40a7..70ae3433353b 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -41,7 +41,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { { Some(const_operand) } - Operand::Copy(_) | Operand::Move(_) => None, + Operand::Copy(_) | Operand::Move(_) | Operand::RuntimeChecks(_) => None, } } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 801383493837..a6ed66c8427b 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -392,11 +392,14 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> { // a_1 = move? place.1 // ... // ``` - StatementKind::Assign(box (lhs, Rvalue::Use(ref op))) => { - let (rplace, copy) = match *op { - Operand::Copy(rplace) => (rplace, true), - Operand::Move(rplace) => (rplace, false), - Operand::Constant(_) => bug!(), + StatementKind::Assign(box ( + lhs, + Rvalue::Use(ref op @ (Operand::Copy(rplace) | Operand::Move(rplace))), + )) => { + let copy = match *op { + Operand::Copy(_) => true, + Operand::Move(_) => false, + Operand::Constant(_) | Operand::RuntimeChecks(_) => bug!(), }; if let Some(final_locals) = self.replacements.place_fragments(lhs) { for (field, ty, new_local) in final_locals { diff --git a/compiler/rustc_public/src/alloc.rs b/compiler/rustc_public/src/alloc.rs index 5ede5b2b2712..0c35b3b25dfc 100644 --- a/compiler/rustc_public/src/alloc.rs +++ b/compiler/rustc_public/src/alloc.rs @@ -53,7 +53,6 @@ pub(crate) fn try_new_allocation<'tcx>( ConstValue::Scalar(scalar) => { alloc::try_new_scalar(layout, scalar, cx).map(|alloc| alloc.stable(tables, cx)) } - ConstValue::RuntimeChecks(_) => todo!(), ConstValue::ZeroSized => Ok(new_empty_allocation(layout.align.abi)), ConstValue::Slice { alloc_id, meta } => { alloc::try_new_slice(layout, alloc_id, meta, cx).map(|alloc| alloc.stable(tables, cx)) diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 92882a001c47..e81b32ec9acf 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -673,6 +673,7 @@ pub enum Operand { Copy(Place), Move(Place), Constant(ConstOperand), + RuntimeChecks(RuntimeChecks), } #[derive(Clone, Eq, PartialEq, Hash, Serialize)] @@ -695,6 +696,16 @@ pub struct ConstOperand { pub const_: MirConst, } +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub enum RuntimeChecks { + /// cfg!(ub_checks), but at codegen time + UbChecks, + /// cfg!(contract_checks), but at codegen time + ContractChecks, + /// cfg!(overflow_checks), but at codegen time + OverflowChecks, +} + /// Debug information pertaining to a user variable. #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct VarDebugInfo { @@ -1025,6 +1036,7 @@ impl Operand { match self { Operand::Copy(place) | Operand::Move(place) => place.ty(locals), Operand::Constant(c) => Ok(c.ty()), + Operand::RuntimeChecks(_) => Ok(Ty::bool_ty()), } } } diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index d814947dc397..fec5bd57efdd 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -332,6 +332,7 @@ fn pretty_operand(operand: &Operand) -> String { format!("move {mv:?}") } Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), + Operand::RuntimeChecks(checks) => format!("const {checks:?}"), } } diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs index f0fdbe059383..678205171ecf 100644 --- a/compiler/rustc_public/src/mir/visit.rs +++ b/compiler/rustc_public/src/mir/visit.rs @@ -296,6 +296,7 @@ macro_rules! make_mir_visitor { Operand::Constant(constant) => { self.visit_const_operand(constant, location); } + Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index a87ac795da5c..14656a2e594a 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1357,7 +1357,6 @@ pub enum ConstantKind { Ty(TyConst), Allocated(Allocation), Unevaluated(UnevaluatedConst), - RuntimeChecks(RuntimeChecks), Param(ParamConst), /// Store ZST constants. /// We have to special handle these constants since its type might be generic. @@ -1377,16 +1376,6 @@ pub struct UnevaluatedConst { pub promoted: Option, } -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub enum RuntimeChecks { - /// cfg!(ub_checks), but at codegen time - UbChecks, - /// cfg!(contract_checks), but at codegen time - ContractChecks, - /// cfg!(overflow_checks), but at codegen time - OverflowChecks, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum TraitSpecializationKind { None, diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 31f41653d4a2..a77808cfb275 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -312,7 +312,7 @@ impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind { } impl<'tcx> Stable<'tcx> for mir::RuntimeChecks { - type T = crate::ty::RuntimeChecks; + type T = crate::mir::RuntimeChecks; fn stable<'cx>( &self, _: &mut Tables<'cx, BridgeTys>, @@ -320,9 +320,9 @@ impl<'tcx> Stable<'tcx> for mir::RuntimeChecks { ) -> Self::T { use rustc_middle::mir::RuntimeChecks::*; match self { - UbChecks => crate::ty::RuntimeChecks::UbChecks, - ContractChecks => crate::ty::RuntimeChecks::ContractChecks, - OverflowChecks => crate::ty::RuntimeChecks::OverflowChecks, + UbChecks => crate::mir::RuntimeChecks::UbChecks, + ContractChecks => crate::mir::RuntimeChecks::ContractChecks, + OverflowChecks => crate::mir::RuntimeChecks::OverflowChecks, } } } @@ -379,6 +379,7 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { Copy(place) => crate::mir::Operand::Copy(place.stable(tables, cx)), Move(place) => crate::mir::Operand::Move(place.stable(tables, cx)), Constant(c) => crate::mir::Operand::Constant(c.stable(tables, cx)), + RuntimeChecks(c) => crate::mir::Operand::RuntimeChecks(c.stable(tables, cx)), } } } @@ -886,13 +887,6 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { let ty = ty.stable(tables, cx); MirConst::new(ConstantKind::ZeroSized, ty, id) } - mir::Const::Val(mir::ConstValue::RuntimeChecks(checks), ty) => { - let ty = cx.lift(ty).unwrap(); - let checks = cx.lift(checks).unwrap(); - let ty = ty.stable(tables, cx); - let kind = ConstantKind::RuntimeChecks(checks.stable(tables, cx)); - MirConst::new(kind, ty, id) - } mir::Const::Val(val, ty) => { let ty = cx.lift(ty).unwrap(); let val = cx.lift(val).unwrap(); diff --git a/compiler/rustc_public/src/visitor.rs b/compiler/rustc_public/src/visitor.rs index 2ebd73a43e90..acc333476961 100644 --- a/compiler/rustc_public/src/visitor.rs +++ b/compiler/rustc_public/src/visitor.rs @@ -68,9 +68,7 @@ impl Visitable for MirConst { super::ty::ConstantKind::Ty(ct) => ct.visit(visitor)?, super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, - super::ty::ConstantKind::RuntimeChecks(_) - | super::ty::ConstantKind::Param(_) - | super::ty::ConstantKind::ZeroSized => {} + super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {} } self.ty().visit(visitor) } diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index f2bffc8156af..0ead5944b4b3 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -110,7 +110,7 @@ impl<'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'_, '_, 'tcx> { immutable_borrowers.push(p.local); } }, - mir::Operand::Constant(..) => (), + mir::Operand::Constant(..) | mir::Operand::RuntimeChecks(..) => (), } } @@ -151,7 +151,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { let mut visit_op = |op: &mir::Operand<'_>| match op { mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local), - mir::Operand::Constant(..) => (), + mir::Operand::Constant(..) | mir::Operand::RuntimeChecks(..) => (), }; match rvalue { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index c1d00fc8d371..06220f91c745 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -277,6 +277,7 @@ fn check_operand<'tcx>( Some(_) => Err((span, "cannot access `static` items in const fn".into())), None => Ok(()), }, + Operand::RuntimeChecks(..) => Ok(()), } } diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs index ae1bdb1d58b9..6998d98e498c 100644 --- a/tests/codegen-llvm/slice-iter-len-eq-zero.rs +++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs @@ -8,10 +8,8 @@ type Demo = [u8; 3]; #[no_mangle] pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { // CHECK-NOT: sub - // CHECK: %2 = icmp ne ptr %1, null - // CHECK-NEXT: tail call void @llvm.assume(i1 %2) - // CHECK-NEXT: %[[RET:.+]] = icmp eq ptr {{%0, %1|%1, %0}} - // CHECK-NEXT: ret i1 %[[RET]] + // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} + // CHECK: ret i1 %[[RET]] y.len() == 0 } @@ -33,7 +31,7 @@ struct MyZST; // CHECK-LABEL: @slice_zst_iter_len_eq_zero #[no_mangle] pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool { - // CHECK: %[[RET:.+]] = icmp eq ptr %1, null + // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null // CHECK: ret i1 %[[RET]] y.len() == 0 }