diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d1d0bff8fe06..46f39ea8f250 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1046,8 +1046,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(NullOp::ContractChecks, _) => {} - &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} + &Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => {} Rvalue::ShallowInitBox(_operand, ty) => { let trait_ref = diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 7d50548b4026..6a1217a6a49b 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -841,17 +841,8 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: fields.iter(), ) .bytes(), - NullOp::UbChecks => { - let val = fx.tcx.sess.ub_checks(); - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - return; - } - NullOp::ContractChecks => { - let val = fx.tcx.sess.contract_checks(); + NullOp::RuntimeChecks(kind) => { + let val = kind.value(fx.tcx.sess); let val = CValue::by_val( fx.bcx.ins().iconst(types::I8, i64::from(val)), fx.layout_of(fx.tcx.types.bool), diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 640f7211dc99..9f7eb9bc51bb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -618,12 +618,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { .bytes(); bx.cx().const_usize(val) } - mir::NullOp::UbChecks => { - let val = bx.tcx().sess.ub_checks(); - bx.cx().const_bool(val) - } - mir::NullOp::ContractChecks => { - let val = bx.tcx().sess.contract_checks(); + mir::NullOp::RuntimeChecks(kind) => { + let val = kind.value(bx.tcx().sess); bx.cx().const_bool(val) } }; diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index ca173fe26c2f..c0a9bd187c14 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -646,7 +646,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} Rvalue::NullaryOp( - NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, + NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _, ) => {} Rvalue::ShallowInitBox(_, _) => {} diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 1725635e0b47..27b1ca01514c 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -298,11 +298,11 @@ pub trait Machine<'tcx>: Sized { interp_ok(()) } - /// Determines the result of a `NullaryOp::UbChecks` invocation. - fn ub_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>; - - /// Determines the result of a `NullaryOp::ContractChecks` invocation. - fn contract_checks(_ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool>; + /// Determines the result of a `NullaryOp::RuntimeChecks` invocation. + fn runtime_checks( + _ecx: &InterpCx<'tcx, Self>, + r: mir::RuntimeChecks, + ) -> InterpResult<'tcx, bool>; /// Called when the interpreter encounters a `StatementKind::ConstEvalCounter` instruction. /// You can use this to detect long or endlessly running programs. @@ -681,14 +681,10 @@ pub macro compile_time_machine(<$tcx: lifetime>) { } #[inline(always)] - fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> 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 contract_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { + 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) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 58b90abf0129..feba23769209 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -522,8 +522,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes(); ImmTy::from_uint(val, usize_layout()) } - UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx), - ContractChecks => ImmTy::from_bool(M::contract_checks(self)?, *self.tcx), + RuntimeChecks(r) => ImmTy::from_bool(M::runtime_checks(self, r)?, *self.tcx), }) } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index fab04df500a5..802adceb063e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -649,7 +649,9 @@ impl<'tcx> Body<'tcx> { } match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)), + Rvalue::NullaryOp(NullOp::RuntimeChecks(kind), _) => { + Some((kind.value(tcx.sess) as u128, targets)) + } Rvalue::Use(Operand::Constant(constant)) => { let bits = eval_mono_const(constant)?; Some((bits, targets)) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 17d8eeee68bf..a7941290de2e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1093,8 +1093,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { let t = with_no_trimmed_paths!(format!("{}", t)); match op { NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"), - NullOp::UbChecks => write!(fmt, "UbChecks()"), - NullOp::ContractChecks => write!(fmt, "ContractChecks()"), + NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"), + NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { + write!(fmt, "ContractChecks()") + } } } ThreadLocalRef(did) => ty::tls::with(|tcx| { diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 3cbb4b70b062..a1f5ffb0b277 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -795,8 +795,7 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => tcx.types.usize, - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, + Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => tcx.types.bool, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), AggregateKind::Tuple => { @@ -864,7 +863,7 @@ impl<'tcx> NullOp<'tcx> { pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { NullOp::OffsetOf(_) => tcx.types.usize, - NullOp::UbChecks | NullOp::ContractChecks => tcx.types.bool, + NullOp::RuntimeChecks(_) => tcx.types.bool, } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 9d99239546ae..865b91817b3c 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1565,6 +1565,12 @@ pub enum AggregateKind<'tcx> { pub enum NullOp<'tcx> { /// Returns the offset of a field OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>), + /// Returns whether we should perform some checking at runtime. + RuntimeChecks(RuntimeChecks), +} + +#[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, @@ -1573,6 +1579,15 @@ pub enum NullOp<'tcx> { ContractChecks, } +impl RuntimeChecks { + pub fn value(self, sess: &rustc_session::Session) -> bool { + match self { + Self::UbChecks => sess.ub_checks(), + Self::ContractChecks => sess.contract_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/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 9308570d89d1..7f6c7376501f 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -293,9 +293,9 @@ pub fn reverse_postorder<'a, 'tcx>( /// reachable. /// /// Such a traversal is mostly useful because it lets us skip lowering the `false` side -/// of `if ::CONST`, as well as [`NullOp::UbChecks`]. +/// of `if ::CONST`, as well as [`NullOp::RuntimeChecks`]. /// -/// [`NullOp::UbChecks`]: rustc_middle::mir::NullOp::UbChecks +/// [`NullOp::RuntimeChecks`]: rustc_middle::mir::NullOp::RuntimeChecks pub fn mono_reachable<'a, 'tcx>( body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index dd65f0699e97..8801fa8d9fd3 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -452,7 +452,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) | Rvalue::NullaryOp( - NullOp::OffsetOf(..) | NullOp::UbChecks | NullOp::ContractChecks, + NullOp::OffsetOf(..) | NullOp::RuntimeChecks(_), _, ) => {} } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 00a8293966b0..1a9af0e22bbe 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -75,7 +75,8 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) { match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, ..) + // FIXME: Should we do the same for `OverflowChecks`? + Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), ..) if !self .tcx .sess diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8eae80e235cc..e19a88d519a4 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -675,8 +675,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { .tcx .offset_of_subfield(self.typing_env(), arg_layout, fields.iter()) .bytes(), - NullOp::UbChecks => return None, - NullOp::ContractChecks => return None, + NullOp::RuntimeChecks(_) => return None, }; ImmTy::from_uint(val, ty).into() } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 932744e4fa25..51e18516534a 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -169,7 +169,10 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { - let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue else { return }; + // FIXME: Should we do the same for overflow checks? + let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), _) = *rvalue else { + return; + }; let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 131e3943689b..dab2267eea69 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -612,8 +612,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { .tcx .offset_of_subfield(self.typing_env, op_layout, fields.iter()) .bytes(), - NullOp::UbChecks => return None, - NullOp::ContractChecks => return None, + NullOp::RuntimeChecks(_) => return None, }; ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index ad7c52064a8e..e6fa30a72b9b 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -23,13 +23,18 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { sym::unreachable => { terminator.kind = TerminatorKind::Unreachable; } - sym::ub_checks => { + sym::ub_checks | sym::contract_checks => { + let op = match intrinsic.name { + sym::ub_checks => RuntimeChecks::UbChecks, + sym::contract_checks => RuntimeChecks::ContractChecks, + _ => unreachable!(), + }; let target = target.unwrap(); block.statements.push(Statement::new( terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool), + Rvalue::NullaryOp(NullOp::RuntimeChecks(op), tcx.types.bool), ))), )); 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 9204c221515c..da5814c6b4cc 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -451,8 +451,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::NullaryOp(op, _) => match op { NullOp::OffsetOf(_) => {} - NullOp::UbChecks => {} - NullOp::ContractChecks => {} + NullOp::RuntimeChecks(_) => {} }, Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 5a9018a62c57..0e71e396c144 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1478,7 +1478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) - | Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks, _) + | Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) | Rvalue::Discriminant(_) => {} Rvalue::WrapUnsafeBinder(op, ty) => { diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 1a939cbe8dba..551f666023b0 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -642,8 +642,7 @@ impl Rvalue { .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) } Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => Ok(Ty::usize_ty()), - Rvalue::NullaryOp(NullOp::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()), + Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => Ok(Ty::bool_ty()), Rvalue::Aggregate(ak, ops) => match *ak { AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), AggregateKind::Tuple => Ok(Ty::new_tuple( @@ -1024,6 +1023,12 @@ pub enum CastKind { pub enum NullOp { /// Returns the offset of a field. OffsetOf(Vec<(VariantIdx, FieldIdx)>), + /// Codegen conditions for runtime checks. + RuntimeChecks(RuntimeChecks), +} + +#[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 diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index f850bc5f89b8..1de5a2b32779 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -322,12 +322,15 @@ impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { use rustc_middle::mir::NullOp::*; + use rustc_middle::mir::RuntimeChecks::*; match self { OffsetOf(indices) => crate::mir::NullOp::OffsetOf( indices.iter().map(|idx| idx.stable(tables, cx)).collect(), ), - UbChecks => crate::mir::NullOp::UbChecks, - ContractChecks => crate::mir::NullOp::ContractChecks, + RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op { + UbChecks => crate::mir::RuntimeChecks::UbChecks, + ContractChecks => crate::mir::RuntimeChecks::ContractChecks, + }), } } } 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 90ea2616890a..0cf1ad348953 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 @@ -194,7 +194,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, _) + Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, cx.tcx); diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index fadbdf5cea99..393895fe1a46 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1329,13 +1329,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { } #[inline(always)] - fn ub_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { - interp_ok(ecx.tcx.sess.ub_checks()) - } - - #[inline(always)] - fn contract_checks(ecx: &InterpCx<'tcx, Self>) -> InterpResult<'tcx, bool> { - interp_ok(ecx.tcx.sess.contract_checks()) + fn runtime_checks(ecx: &InterpCx<'tcx, Self>, r: mir::RuntimeChecks) -> InterpResult<'tcx, bool> { + interp_ok(r.value(&ecx.tcx.sess)) } #[inline(always)]