From 5594d3f3284cb55a5bc3941f6808b9d10604868b Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 25 Oct 2025 04:15:43 +0000 Subject: [PATCH 1/5] Replace OffsetOf by an actual sum. --- compiler/rustc_borrowck/src/lib.rs | 2 +- .../src/polonius/legacy/loan_invalidations.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 5 +- compiler/rustc_codegen_cranelift/src/base.rs | 25 +--- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 11 +- .../src/check_consts/check.rs | 6 +- .../src/interpret/intrinsics.rs | 17 ++- .../src/interpret/operator.rs | 17 +-- .../rustc_const_eval/src/interpret/step.rs | 5 +- compiler/rustc_hir/src/lang_items.rs | 1 + .../rustc_hir_analysis/src/check/intrinsic.rs | 2 + compiler/rustc_hir_typeck/src/expr.rs | 15 +-- compiler/rustc_hir_typeck/src/writeback.rs | 11 +- compiler/rustc_lint/src/unused.rs | 12 ++ compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 20 ++- compiler/rustc_middle/src/mir/statement.rs | 10 +- compiler/rustc_middle/src/mir/syntax.rs | 6 +- compiler/rustc_middle/src/mir/visit.rs | 4 +- compiler/rustc_middle/src/thir.rs | 7 +- compiler/rustc_middle/src/thir/visit.rs | 1 - compiler/rustc_middle/src/ty/codec.rs | 11 +- compiler/rustc_middle/src/ty/context.rs | 11 -- compiler/rustc_middle/src/ty/layout.rs | 34 ------ .../rustc_middle/src/ty/structural_impls.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 8 +- .../src/builder/expr/as_place.rs | 1 - .../src/builder/expr/as_rvalue.rs | 4 - .../src/builder/expr/category.rs | 1 - .../rustc_mir_build/src/builder/expr/into.rs | 1 - .../rustc_mir_build/src/check_unsafety.rs | 1 - compiler/rustc_mir_build/src/thir/cx/expr.rs | 62 ++++++++-- .../src/thir/pattern/check_match.rs | 1 - compiler/rustc_mir_build/src/thir/print.rs | 13 -- .../src/move_paths/builder.rs | 2 +- .../src/dataflow_const_prop.rs | 16 +-- compiler/rustc_mir_transform/src/gvn.rs | 16 +-- .../rustc_mir_transform/src/instsimplify.rs | 2 +- .../src/known_panics_lint.rs | 12 +- .../src/lower_intrinsics.rs | 2 +- .../rustc_mir_transform/src/promote_consts.rs | 3 +- compiler/rustc_mir_transform/src/validate.rs | 45 +------ compiler/rustc_passes/src/dead.rs | 26 ++-- compiler/rustc_public/src/mir/body.rs | 7 +- compiler/rustc_public/src/mir/pretty.rs | 4 +- compiler/rustc_public/src/mir/visit.rs | 4 +- .../src/unstable/convert/stable/mir.rs | 13 +- compiler/rustc_ty_utils/src/consts.rs | 2 - library/core/src/intrinsics/mod.rs | 17 +++ library/core/src/mem/mod.rs | 4 +- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- tests/crashes/123959.rs | 5 - tests/crashes/125680.rs | 15 --- tests/crashes/129425.rs | 6 - tests/crashes/136175-2.rs | 13 -- tests/mir-opt/building/offset_of.rs | 115 ++++++++++++++++++ .../offset_of.concrete.GVN.panic-abort.diff | 14 +-- .../offset_of.concrete.GVN.panic-unwind.diff | 14 +-- .../offset_of.generic.GVN.panic-abort.diff | 14 +-- .../offset_of.generic.GVN.panic-unwind.diff | 14 +-- ...oncrete.DataflowConstProp.panic-abort.diff | 44 ------- ...ncrete.DataflowConstProp.panic-unwind.diff | 44 ------- ...generic.DataflowConstProp.panic-abort.diff | 42 ------- ...eneric.DataflowConstProp.panic-unwind.diff | 42 ------- .../mir-opt/dataflow-const-prop/offset_of.rs | 75 ------------ tests/ui/offset-of/inside-array-length.rs | 23 ++++ tests/ui/offset-of/inside-array-length.stderr | 90 ++++++++++++++ .../ui/offset-of/offset-of-output-type.stderr | 3 - tests/ui/offset-of/offset-of-unsized.rs | 45 ++++++- tests/ui/unpretty/exhaustive.expanded.stdout | 2 +- tests/ui/unpretty/exhaustive.hir.stdout | 2 +- 71 files changed, 479 insertions(+), 651 deletions(-) delete mode 100644 tests/crashes/123959.rs delete mode 100644 tests/crashes/125680.rs delete mode 100644 tests/crashes/129425.rs delete mode 100644 tests/crashes/136175-2.rs create mode 100644 tests/mir-opt/building/offset_of.rs delete mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff delete mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff delete mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff delete mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff delete mode 100644 tests/mir-opt/dataflow-const-prop/offset_of.rs create mode 100644 tests/ui/offset-of/inside-array-length.rs create mode 100644 tests/ui/offset-of/inside-array-length.stderr diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 0ac3baaa197f0..20411fcc16fbb 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1559,7 +1559,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self.consume_operand(location, (operand2, span), state); } - Rvalue::NullaryOp(_op, _ty) => { + Rvalue::NullaryOp(_op) => { // nullary ops take no dynamic input; no borrowck effect. } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 722b59f145d9d..de479a7d74c8e 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -314,7 +314,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { self.consume_operand(location, operand2); } - Rvalue::NullaryOp(_op, _ty) => {} + Rvalue::NullaryOp(_op) => {} Rvalue::Aggregate(_, operands) => { for operand in operands { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 46f39ea8f2507..5f86e8646c03f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1046,7 +1046,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => {} + &Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} Rvalue::ShallowInitBox(_operand, ty) => { let trait_ref = @@ -1633,8 +1633,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | Rvalue::BinaryOp(..) | Rvalue::RawPtr(..) | Rvalue::ThreadLocalRef(..) - | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {} + | Rvalue::Discriminant(..) => {} } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 3bd2e4ea7343b..e445f9457477d 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -853,31 +853,14 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: fx.bcx.ins().nop(); } } - Rvalue::NullaryOp(ref null_op, ty) => { + Rvalue::NullaryOp(ref null_op) => { assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); - let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { - NullOp::OffsetOf(fields) => fx - .tcx - .offset_of_subfield( - ty::TypingEnv::fully_monomorphized(), - layout, - fields.iter(), - ) - .bytes(), - 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), - ); - lval.write_cvalue(fx, val); - return; - } + NullOp::RuntimeChecks(kind) => kind.value(fx.tcx.sess), }; let val = CValue::by_val( - fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()), - fx.layout_of(fx.tcx.types.usize), + fx.bcx.ins().iconst(types::I8, i64::from(val)), + fx.layout_of(fx.tcx.types.bool), ); lval.write_cvalue(fx, val); } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 827dc6e167afd..96a9fab252464 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -613,17 +613,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - mir::Rvalue::NullaryOp(ref null_op, ty) => { - let ty = self.monomorphize(ty); - let layout = bx.cx().layout_of(ty); + mir::Rvalue::NullaryOp(ref null_op) => { let val = match null_op { - mir::NullOp::OffsetOf(fields) => { - let val = bx - .tcx() - .offset_of_subfield(bx.typing_env(), layout, fields.iter()) - .bytes(); - bx.cx().const_usize(val) - } 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 f515f5d751bc6..4110317adcf48 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -645,7 +645,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::RuntimeChecks(_), _) => {} + Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(op, operand) => { @@ -853,7 +853,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } // Intrinsics are language primitives, not regular calls, so treat them separately. - if let Some(intrinsic) = tcx.intrinsic(callee) { + if let Some(intrinsic) = tcx.intrinsic(callee) + && intrinsic.name != sym::offset_of + { if !tcx.is_const_fn(callee) { // Non-const intrinsic. self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 58d7f8ef8c637..d97200aceaf99 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -6,7 +6,7 @@ mod simd; use std::assert_matches::assert_matches; -use rustc_abi::{FieldIdx, HasDataLayout, Size}; +use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; @@ -203,6 +203,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let val = layout.align.bytes(); self.write_scalar(Scalar::from_target_usize(val, self), dest)?; } + sym::offset_of => { + let tp_ty = instance.args.type_at(0); + + let u32_layout = self.layout_of(self.tcx.types.u32)?; + let variant = self.read_scalar(&args[0])?.to_bits(u32_layout.size)? as u32; + let field = self.read_scalar(&args[1])?.to_bits(u32_layout.size)? as usize; + + let layout = self.layout_of(tp_ty)?; + let cx = ty::layout::LayoutCx::new(*self.tcx, self.typing_env); + + let layout = layout.for_variant(&cx, VariantIdx::from_u32(variant)); + let offset = layout.fields.offset(field).bytes(); + + self.write_scalar(Scalar::from_target_usize(offset, self), dest)?; + } sym::variant_count => { let tp_ty = instance.args.type_at(0); let ty = match tp_ty.kind() { diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index feba237692090..8548b774ddb4e 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -4,7 +4,7 @@ use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::NullOp; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::layout::TyAndLayout; -use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty}; +use rustc_middle::ty::{self, FloatTy, ScalarInt}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::sym; use tracing::trace; @@ -506,22 +506,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - pub fn nullary_op( - &self, - null_op: NullOp<'tcx>, - arg_ty: Ty<'tcx>, - ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { + pub fn nullary_op(&self, null_op: NullOp) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { use rustc_middle::mir::NullOp::*; - - let layout = self.layout_of(arg_ty)?; - let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap(); - interp_ok(match null_op { - OffsetOf(fields) => { - let val = - self.tcx.offset_of_subfield(self.typing_env, layout, fields.iter()).bytes(); - ImmTy::from_uint(val, usize_layout()) - } RuntimeChecks(r) => ImmTy::from_bool(M::runtime_checks(self, r)?, *self.tcx), }) } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 1766bbe92480a..88a1160947583 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -203,9 +203,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_immediate(*result, &dest)?; } - NullaryOp(null_op, ty) => { - let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?; - let val = self.nullary_op(null_op, ty)?; + NullaryOp(null_op) => { + let val = self.nullary_op(null_op)?; self.write_immediate(*val, &dest)?; } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index e454ed58699c9..45a9f2d4e0f8e 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -170,6 +170,7 @@ language_item_table! { Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); AlignOf, sym::mem_align_const, align_const, Target::AssocConst, GenericRequirement::Exact(0); SizeOf, sym::mem_size_const, size_const, Target::AssocConst, GenericRequirement::Exact(0); + OffsetOf, sym::offset_of, offset_of, Target::Fn, GenericRequirement::Exact(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None; Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index d87a154b0f1bb..8a505668d0dad 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -163,6 +163,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::minnumf128 | sym::mul_with_overflow | sym::needs_drop + | sym::offset_of | sym::overflow_checks | sym::powf16 | sym::powf32 @@ -288,6 +289,7 @@ pub(crate) fn check_intrinsic_type( sym::size_of_val | sym::align_of_val => { (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } + sym::offset_of => (1, 0, vec![tcx.types.u32, tcx.types.u32], tcx.types.usize), sym::rustc_peek => (1, 0, vec![param(0)], param(0)), sym::caller_location => (0, 0, vec![], tcx.caller_location_ty()), sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid => { diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index e533ee78cc824..a47df3bba7578 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3884,10 +3884,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &[Ident], expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { - let container = self.lower_ty(container).normalized; - + let mut current_container = self.lower_ty(container).normalized; let mut field_indices = Vec::with_capacity(fields.len()); - let mut current_container = container; let mut fields = fields.into_iter(); while let Some(&field) = fields.next() { @@ -3975,7 +3973,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Save the index of all fields regardless of their visibility in case // of error recovery. - field_indices.push((index, subindex)); + field_indices.push((current_container, index, subindex)); current_container = field_ty; continue; @@ -4010,7 +4008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Save the index of all fields regardless of their visibility in case // of error recovery. - field_indices.push((FIRST_VARIANT, index)); + field_indices.push((current_container, FIRST_VARIANT, index)); current_container = field_ty; continue; @@ -4031,7 +4029,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - field_indices.push((FIRST_VARIANT, index.into())); + field_indices.push((current_container, FIRST_VARIANT, index.into())); current_container = field_ty; continue; @@ -4046,10 +4044,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { break; } - self.typeck_results - .borrow_mut() - .offset_of_data_mut() - .insert(expr.hir_id, (container, field_indices)); + self.typeck_results.borrow_mut().offset_of_data_mut().insert(expr.hir_id, field_indices); self.tcx.types.usize } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 3235aa396df4f..22a6d53c5c099 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -773,12 +773,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); let common_hir_owner = fcx_typeck_results.hir_owner; - for (local_id, &(container, ref indices)) in - fcx_typeck_results.offset_of_data().items_in_stable_order() - { + for (local_id, indices) in fcx_typeck_results.offset_of_data().items_in_stable_order() { let hir_id = HirId { owner: common_hir_owner, local_id }; - let container = self.resolve(container, &hir_id); - self.typeck_results.offset_of_data_mut().insert(hir_id, (container, indices.clone())); + let indices = indices + .iter() + .map(|&(ty, variant, field)| (self.resolve(ty, &hir_id), variant, field)) + .collect(); + self.typeck_results.offset_of_data_mut().insert(hir_id, indices); } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 40df5ecb0f3c4..610f6f389e685 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -179,6 +179,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { hir::ExprKind::AddrOf(..) => Some("borrow"), hir::ExprKind::OffsetOf(..) => Some("`offset_of` call"), hir::ExprKind::Unary(..) => Some("unary operation"), + // The `offset_of` macro wraps its contents inside a `const` block. + hir::ExprKind::ConstBlock(block) => { + let body = cx.tcx.hir_body(block.body); + if let hir::ExprKind::Block(block, _) = body.value.kind + && let Some(expr) = block.expr + && let hir::ExprKind::OffsetOf(..) = expr.kind + { + Some("`offset_of` call") + } else { + None + } + } _ => None, }; diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 802adceb063ea..44b1c0047b7e5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -649,7 +649,7 @@ impl<'tcx> Body<'tcx> { } match rvalue { - Rvalue::NullaryOp(NullOp::RuntimeChecks(kind), _) => { + Rvalue::NullaryOp(NullOp::RuntimeChecks(kind)) => { Some((kind.value(tcx.sess) as u128, targets)) } Rvalue::Use(Operand::Constant(constant)) => { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index e31b110ab2650..924d2f4ee0152 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1097,19 +1097,15 @@ impl<'tcx> Debug for Rvalue<'tcx> { BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"), UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"), Discriminant(ref place) => write!(fmt, "discriminant({place:?})"), - NullaryOp(ref op, ref t) => { - let t = with_no_trimmed_paths!(format!("{}", t)); - match op { - NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({t}, {fields:?})"), - NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"), - NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { - write!(fmt, "ContractChecks()") - } - NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => { - write!(fmt, "OverflowChecks()") - } + NullaryOp(ref op) => match op { + NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"), + NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { + write!(fmt, "ContractChecks()") } - } + NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => { + write!(fmt, "OverflowChecks()") + } + }, ThreadLocalRef(did) => ty::tls::with(|tcx| { let muta = tcx.static_mutability(did).unwrap().prefix_str(); write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index a1f5ffb0b2774..bd4188dd0ff49 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -756,7 +756,7 @@ impl<'tcx> Rvalue<'tcx> { _, ) | Rvalue::BinaryOp(_, _) - | Rvalue::NullaryOp(_, _) + | Rvalue::NullaryOp(_) | Rvalue::UnaryOp(_, _) | Rvalue::Discriminant(_) | Rvalue::Aggregate(_, _) @@ -794,8 +794,7 @@ impl<'tcx> Rvalue<'tcx> { op.ty(tcx, arg_ty) } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => tcx.types.usize, - Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => 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 => { @@ -859,10 +858,9 @@ impl BorrowKind { } } -impl<'tcx> NullOp<'tcx> { - pub fn ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { +impl NullOp { + pub fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match self { - NullOp::OffsetOf(_) => tcx.types.usize, NullOp::RuntimeChecks(_) => tcx.types.bool, } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 3b48a68df1262..204ad4815147b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1419,7 +1419,7 @@ pub enum Rvalue<'tcx> { BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), /// Computes a value as described by the operation. - NullaryOp(NullOp<'tcx>, Ty<'tcx>), + NullaryOp(NullOp), /// Exactly like `BinaryOp`, but less operands. /// @@ -1562,9 +1562,7 @@ pub enum AggregateKind<'tcx> { } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum NullOp<'tcx> { - /// Returns the offset of a field - OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>), +pub enum NullOp { /// Returns whether we should perform some checking at runtime. RuntimeChecks(RuntimeChecks), } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 36e508f16ae2c..6d251988cbbd8 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -775,9 +775,7 @@ macro_rules! make_mir_visitor { ); } - Rvalue::NullaryOp(_op, ty) => { - self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); - } + Rvalue::NullaryOp(_op) => {} Rvalue::Aggregate(kind, operands) => { let kind = &$($mutability)? **kind; diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index e72ed78d07e6a..c6950fac041cc 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -32,7 +32,7 @@ use crate::thir::visit::for_each_immediate_subpat; use crate::ty::adjustment::PointerCoercion; use crate::ty::layout::IntegerExt; use crate::ty::{ - self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, List, Ty, + self, AdtDef, CanonicalUserType, CanonicalUserTypeAnnotation, FnSig, GenericArgsRef, Ty, TyCtxt, UpvarArgs, }; @@ -560,11 +560,6 @@ pub enum ExprKind<'tcx> { }, /// Inline assembly, i.e. `asm!()`. InlineAsm(Box>), - /// Field offset (`offset_of!`) - OffsetOf { - container: Ty<'tcx>, - fields: &'tcx List<(VariantIdx, FieldIdx)>, - }, /// An expression taking a reference to a thread local. ThreadLocalRef(DefId), /// A `yield` expression. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index dcfa6c4db3274..755dee13a2f17 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -188,7 +188,6 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } } } - OffsetOf { container: _, fields: _ } => {} ThreadLocalRef(_) => {} Yield { value } => visitor.visit_expr(&visitor.thir()[value]), } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 3d6320be3af81..75b1317e022bd 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -10,7 +10,7 @@ use std::hash::Hash; use std::intrinsics; use std::marker::{DiscriminantKind, PointeeSized}; -use rustc_abi::{FieldIdx, VariantIdx}; +use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; use rustc_serialize::{Decodable, Encodable}; @@ -489,15 +489,6 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable for &'tcx ty::List { } } -impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<(VariantIdx, FieldIdx)> { - fn decode(decoder: &mut D) -> &'tcx Self { - let len = decoder.read_usize(); - decoder.interner().mk_offset_of_from_iter( - (0..len).map::<(VariantIdx, FieldIdx), _>(|_| Decodable::decode(decoder)), - ) - } -} - impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ae83e98f37d27..525698c3c4409 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -953,7 +953,6 @@ pub struct CtxtInterners<'tcx> { fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, - offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, patterns: InternedSet<'tcx, List>>, outlives: InternedSet<'tcx, List>>, @@ -991,7 +990,6 @@ impl<'tcx> CtxtInterners<'tcx> { fields: InternedSet::with_capacity(N * 4), local_def_ids: InternedSet::with_capacity(N), captures: InternedSet::with_capacity(N), - offset_of: InternedSet::with_capacity(N), valtree: InternedSet::with_capacity(N), patterns: InternedSet::with_capacity(N), outlives: InternedSet::with_capacity(N), @@ -2830,7 +2828,6 @@ slice_interners!( fields: pub mk_fields(FieldIdx), local_def_ids: intern_local_def_ids(LocalDefId), captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), - offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), patterns: pub mk_patterns(Pattern<'tcx>), outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>), predefined_opaques_in_body: pub mk_predefined_opaques_in_body((ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)), @@ -3233,14 +3230,6 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_fields(xs)) } - pub fn mk_offset_of_from_iter(self, iter: I) -> T::Output - where - I: Iterator, - T: CollectAndApply<(VariantIdx, FieldIdx), &'tcx List<(VariantIdx, FieldIdx)>>, - { - T::collect_and_apply(iter, |xs| self.mk_offset_of(xs)) - } - pub fn mk_args_trait( self, self_ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 621d5c31e685e..d0fd2f02a336a 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1392,37 +1392,3 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { } impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} - -impl<'tcx> TyCtxt<'tcx> { - pub fn offset_of_subfield( - self, - typing_env: ty::TypingEnv<'tcx>, - mut layout: TyAndLayout<'tcx>, - indices: I, - ) -> Size - where - I: Iterator, - { - let cx = LayoutCx::new(self, typing_env); - let mut offset = Size::ZERO; - - for (variant, field) in indices { - layout = layout.for_variant(&cx, variant); - let index = field.index(); - offset += layout.fields.offset(index); - layout = layout.field(&cx, index); - if !layout.is_sized() { - // If it is not sized, then the tail must still have at least a known static alignment. - let tail = self.struct_tail_for_codegen(layout.ty, typing_env); - if !matches!(tail.kind(), ty::Slice(..)) { - bug!( - "offset of not-statically-aligned field (type {:?}) cannot be computed statically", - layout.ty - ); - } - } - } - - offset - } -} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 8dc4dfd677ba8..cff415e9036ad 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -253,7 +253,7 @@ TrivialTypeTraversalImpls! { crate::mir::FakeReadCause, crate::mir::Local, crate::mir::MirPhase, - crate::mir::NullOp<'tcx>, + crate::mir::NullOp, crate::mir::Promoted, crate::mir::RawPtrKind, crate::mir::RetagKind, diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 5300be58f04e6..6386e6c85ddd0 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -227,7 +227,7 @@ pub struct TypeckResults<'tcx> { pub transmutes_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, HirId)>, /// Container types and field indices of `offset_of!` expressions - offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>, + offset_of_data: ItemLocalMap, VariantIdx, FieldIdx)>>, } impl<'tcx> TypeckResults<'tcx> { @@ -560,15 +560,13 @@ impl<'tcx> TypeckResults<'tcx> { &self.coercion_casts } - pub fn offset_of_data( - &self, - ) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> { + pub fn offset_of_data(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, VariantIdx, FieldIdx)>> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data } } pub fn offset_of_data_mut( &mut self, - ) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> { + ) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, VariantIdx, FieldIdx)>> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data } } } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 1b143f37a585f..94c580dbda9b8 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -582,7 +582,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ConstBlock { .. } | ExprKind::StaticRef { .. } | ExprKind::InlineAsm { .. } - | ExprKind::OffsetOf { .. } | ExprKind::Yield { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::Call { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 552f8c66784ed..e909c6a88b660 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -411,10 +411,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { })))) } - ExprKind::OffsetOf { container, fields } => { - block.and(Rvalue::NullaryOp(NullOp::OffsetOf(fields), container)) - } - ExprKind::Literal { .. } | ExprKind::NamedConst { .. } | ExprKind::NonHirLiteral { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs index 5e4219dbf5bc9..1464b5e560bf5 100644 --- a/compiler/rustc_mir_build/src/builder/expr/category.rs +++ b/compiler/rustc_mir_build/src/builder/expr/category.rs @@ -71,7 +71,6 @@ impl Category { | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } | ExprKind::ThreadLocalRef(_) - | ExprKind::OffsetOf { .. } | ExprKind::WrapUnsafeBinder { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), ExprKind::ConstBlock { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index bb65ef28bdc8c..651b107b73d80 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -784,7 +784,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::ConstParam { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::StaticRef { .. } - | ExprKind::OffsetOf { .. } | ExprKind::WrapUnsafeBinder { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { // should be handled above diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 18e9543407764..a06c030b103b2 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -477,7 +477,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::Box { .. } | ExprKind::If { .. } | ExprKind::InlineAsm { .. } - | ExprKind::OffsetOf { .. } | ExprKind::LogicalOp { .. } | ExprKind::Use { .. } => { // We don't need to save the old value and restore it diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 8ce0b73e47e36..6870bb510264e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,11 +1,11 @@ use itertools::Itertools; -use rustc_abi::{FIRST_VARIANT, FieldIdx}; +use rustc_abi::{FIRST_VARIANT, FieldIdx, Size, VariantIdx}; use rustc_ast::UnsafeBinderCastKind; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; -use rustc_hir::find_attr; +use rustc_hir::{LangItem, find_attr}; use rustc_index::Idx; use rustc_middle::hir::place::{ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind, @@ -338,6 +338,12 @@ impl<'tcx> ThirBuildCx<'tcx> { let expr_ty = self.typeck_results.expr_ty(expr); let (temp_lifetime, backwards_incompatible) = self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id); + let mk_expr = |kind, ty| Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + span: expr.span, + ty, + kind, + }; let kind = match expr.kind { // Here comes the interesting stuff: @@ -818,11 +824,48 @@ impl<'tcx> ThirBuildCx<'tcx> { })), hir::ExprKind::OffsetOf(_, _) => { - let data = self.typeck_results.offset_of_data(); - let &(container, ref indices) = data.get(expr.hir_id).unwrap(); - let fields = tcx.mk_offset_of_from_iter(indices.iter().copied()); + let offset_of_intrinsic = tcx.require_lang_item(LangItem::OffsetOf, expr.span); + let mk_u32_kind = |val: u32| ExprKind::NonHirLiteral { + lit: ScalarInt::try_from_uint(val, Size::from_bits(32)).unwrap(), + user_ty: None, + }; + let mk_call = + |thir: &mut Thir<'tcx>, ty: Ty<'tcx>, variant: VariantIdx, field: FieldIdx| { + let fun_ty = + Ty::new_fn_def(tcx, offset_of_intrinsic, [ty::GenericArg::from(ty)]); + let fun = thir + .exprs + .push(mk_expr(ExprKind::ZstLiteral { user_ty: None }, fun_ty)); + let variant = + thir.exprs.push(mk_expr(mk_u32_kind(variant.as_u32()), tcx.types.u32)); + let field = + thir.exprs.push(mk_expr(mk_u32_kind(field.as_u32()), tcx.types.u32)); + let args = Box::new([variant, field]); + ExprKind::Call { + ty: fun_ty, + fun, + args, + from_hir_call: false, + fn_span: expr.span, + } + }; + + let indices = self.typeck_results.offset_of_data().get(expr.hir_id).unwrap(); + let mut expr = None::>; + + for &(container, variant, field) in indices.iter() { + let next = mk_call(&mut self.thir, container, variant, field); + expr = Some(match expr.take() { + None => next, + Some(last) => { + let last = self.thir.exprs.push(mk_expr(last, tcx.types.usize)); + let next = self.thir.exprs.push(mk_expr(next, tcx.types.usize)); + ExprKind::Binary { op: BinOp::Add, lhs: last, rhs: next } + } + }); + } - ExprKind::OffsetOf { container, fields } + expr.unwrap_or(mk_u32_kind(0)) } hir::ExprKind::ConstBlock(ref anon_const) => { @@ -1093,12 +1136,7 @@ impl<'tcx> ThirBuildCx<'tcx> { hir::ExprKind::Err(_) => unreachable!("cannot lower a `hir::ExprKind::Err` to THIR"), }; - Expr { - temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, - ty: expr_ty, - span: expr.span, - kind, - } + mk_expr(kind, expr_ty) } fn user_args_applied_to_res( diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 2400d297c89cf..c4479c402ab2f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -367,7 +367,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { | Match { .. } | NamedConst { .. } | NonHirLiteral { .. } - | OffsetOf { .. } | Repeat { .. } | StaticRef { .. } | ThreadLocalRef { .. } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index e0a5c18a2eedb..e7ba04af9159c 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -575,19 +575,6 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_inline_asm_expr(&**expr, depth_lvl + 2); print_indented!(self, "}", depth_lvl); } - OffsetOf { container, fields } => { - print_indented!(self, "OffsetOf {", depth_lvl); - print_indented!(self, format!("container: {:?}", container), depth_lvl + 1); - print_indented!(self, "fields: [", depth_lvl + 1); - - for field in fields.iter() { - print_indented!(self, format!("{:?}", field), depth_lvl + 2); - print_indented!(self, ",", depth_lvl + 1); - } - - print_indented!(self, "]", depth_lvl + 1); - print_indented!(self, "}", depth_lvl); - } ThreadLocalRef(def_id) => { print_indented!(self, "ThreadLocalRef {", depth_lvl); print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index b4ffeb782b596..0cd3405d1e61b 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -451,7 +451,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { Rvalue::Ref(..) | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(NullOp::OffsetOf(..) | NullOp::RuntimeChecks(_), _) => {} + | Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 8532e1e9d7cc9..bccdd526ab7fd 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -463,20 +463,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Top => FlatSet::Top, } } - Rvalue::NullaryOp(null_op, ty) => { - let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { - return ValueOrPlace::Value(FlatSet::Top); - }; - let val = match null_op { - NullOp::OffsetOf(fields) => self - .ecx - .borrow() - .tcx - .offset_of_subfield(self.typing_env, layout, fields.iter()) - .bytes(), - _ => return ValueOrPlace::Value(FlatSet::Top), - }; - FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx)) + Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => { + return ValueOrPlace::TOP; } Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), Rvalue::Use(operand) => return self.handle_operand(operand, state), diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index a20e04371b987..8295e4ae58dd3 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -248,7 +248,7 @@ enum Value<'a, 'tcx> { Discriminant(VnIndex), // Operations. - NullaryOp(NullOp<'tcx>, Ty<'tcx>), + NullaryOp(NullOp), UnaryOp(UnOp, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex), Cast { @@ -668,17 +668,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?; discr_value.into() } - NullaryOp(null_op, arg_ty) => { - let arg_layout = self.ecx.layout_of(arg_ty).ok()?; - let val = match null_op { - NullOp::OffsetOf(fields) => self - .tcx - .offset_of_subfield(self.typing_env(), arg_layout, fields.iter()) - .bytes(), - NullOp::RuntimeChecks(_) => return None, - }; - ImmTy::from_uint(val, ty).into() - } + NullaryOp(NullOp::RuntimeChecks(_)) => return None, UnaryOp(un_op, operand) => { let operand = self.eval_to_const(operand)?; let operand = self.ecx.read_immediate(operand).discard_err()?; @@ -1031,7 +1021,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { let op = self.simplify_operand(op, location)?; Value::Repeat(op, amount) } - Rvalue::NullaryOp(op, ty) => Value::NullaryOp(op, ty), + Rvalue::NullaryOp(op) => Value::NullaryOp(op), Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location), Rvalue::Ref(_, borrow_kind, ref mut place) => { self.simplify_place_projection(place, location); diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 51e18516534ad..4922d74743c9a 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -170,7 +170,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { // FIXME: Should we do the same for overflow checks? - let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), _) = *rvalue else { + let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks)) = *rvalue else { return; }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index dab2267eea690..1f5d31932f1a2 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -605,17 +605,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Ref(..) | RawPtr(..) => return None, - NullaryOp(ref null_op, ty) => { - let op_layout = self.ecx.layout_of(ty).ok()?; - let val = match null_op { - NullOp::OffsetOf(fields) => self - .tcx - .offset_of_subfield(self.typing_env, op_layout, fields.iter()) - .bytes(), - NullOp::RuntimeChecks(_) => return None, - }; - ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() - } + NullaryOp(NullOp::RuntimeChecks(_)) => return None, ShallowInitBox(..) => return None, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 1e874300e25ea..f25874fbbcb89 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -35,7 +35,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::NullaryOp(NullOp::RuntimeChecks(op), tcx.types.bool), + Rvalue::NullaryOp(NullOp::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 da5814c6b4cce..6b0c331ff5415 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -449,8 +449,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(operand)?; } - Rvalue::NullaryOp(op, _) => match op { - NullOp::OffsetOf(_) => {} + Rvalue::NullaryOp(op) => match op { NullOp::RuntimeChecks(_) => {} }, diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 1f0490a120152..91617be085c31 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1436,53 +1436,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } - Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => { - let fail_out_of_bounds = |this: &mut Self, location, field, ty| { - this.fail(location, format!("Out of bounds field {field:?} for {ty}")); - }; - - let mut current_ty = *container; - - for (variant, field) in indices.iter() { - match current_ty.kind() { - ty::Tuple(fields) => { - if variant != FIRST_VARIANT { - self.fail( - location, - format!("tried to get variant {variant:?} of tuple"), - ); - return; - } - let Some(&f_ty) = fields.get(field.as_usize()) else { - fail_out_of_bounds(self, location, field, current_ty); - return; - }; - - current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty); - } - ty::Adt(adt_def, args) => { - let Some(field) = adt_def.variant(variant).fields.get(field) else { - fail_out_of_bounds(self, location, field, current_ty); - return; - }; - - let f_ty = field.ty(self.tcx, args); - current_ty = self.tcx.normalize_erasing_regions(self.typing_env, f_ty); - } - _ => { - self.fail( - location, - format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty}"), - ); - return; - } - } - } - } Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) - | Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) + | Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) | Rvalue::Discriminant(_) => {} Rvalue::WrapUnsafeBinder(op, ty) => { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 6d34587684bb3..705d1b9e38408 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -298,31 +298,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) { - let data = self.typeck_results().offset_of_data(); - let &(container, ref indices) = - data.get(expr.hir_id).expect("no offset_of_data for offset_of"); - - let body_did = self.typeck_results().hir_owner.to_def_id(); - let typing_env = ty::TypingEnv::non_body_analysis(self.tcx, body_did); - - let mut current_ty = container; + let indices = self + .typeck_results() + .offset_of_data() + .get(expr.hir_id) + .expect("no offset_of_data for offset_of"); - for &(variant, field) in indices { + for &(current_ty, variant, field) in indices { match current_ty.kind() { - ty::Adt(def, args) => { + ty::Adt(def, _) => { let field = &def.variant(variant).fields[field]; - self.insert_def_id(field.did); - let field_ty = field.ty(self.tcx, args); - - current_ty = self.tcx.normalize_erasing_regions(typing_env, field_ty); } // we don't need to mark tuple fields as live, // but we may need to mark subfields - ty::Tuple(tys) => { - current_ty = - self.tcx.normalize_erasing_regions(typing_env, tys[field.as_usize()]); - } + ty::Tuple(_) => {} _ => span_bug!(expr.span, "named field access on non-ADT"), } } diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 5f41b1063280e..fde4d40bea10a 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -588,7 +588,7 @@ pub enum Rvalue { ThreadLocalRef(crate::CrateItem), /// Computes a value as described by the operation. - NullaryOp(NullOp, Ty), + NullaryOp(NullOp), /// Exactly like `BinaryOp`, but less operands. /// @@ -641,8 +641,7 @@ impl Rvalue { .discriminant_ty() .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) } - Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => Ok(Ty::usize_ty()), - Rvalue::NullaryOp(NullOp::RuntimeChecks(_), _) => 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( @@ -1021,8 +1020,6 @@ pub enum CastKind { #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum NullOp { - /// Returns the offset of a field. - OffsetOf(Vec<(VariantIdx, FieldIdx)>), /// Codegen conditions for runtime checks. RuntimeChecks(RuntimeChecks), } diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index 8904870f29e32..d80e227f5a9ce 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -386,8 +386,8 @@ fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { Rvalue::ThreadLocalRef(item) => { write!(writer, "thread_local_ref{item:?}") } - Rvalue::NullaryOp(nul, ty) => { - write!(writer, "{nul:?}::<{ty}>() \" \"") + Rvalue::NullaryOp(nul) => { + write!(writer, "{nul:?}() \" \"") } Rvalue::UnaryOp(un, op) => { write!(writer, "{:?}({})", un, pretty_operand(op)) diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs index 775237c8b3220..35af39c43a277 100644 --- a/compiler/rustc_public/src/mir/visit.rs +++ b/compiler/rustc_public/src/mir/visit.rs @@ -282,9 +282,7 @@ macro_rules! make_mir_visitor { self.visit_operand(op, location) } Rvalue::ThreadLocalRef(_) => {} - Rvalue::NullaryOp(_, ty) => { - self.visit_ty(ty, location); - } + Rvalue::NullaryOp(_) => {} Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { self.visit_operand(op, location); } diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index d5896474d0093..e7a1c8218ce4e 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -232,9 +232,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { ) } } - NullaryOp(null_op, ty) => { - crate::mir::Rvalue::NullaryOp(null_op.stable(tables, cx), ty.stable(tables, cx)) - } + NullaryOp(null_op) => crate::mir::Rvalue::NullaryOp(null_op.stable(tables, cx)), UnaryOp(un_op, op) => { crate::mir::Rvalue::UnaryOp(un_op.stable(tables, cx), op.stable(tables, cx)) } @@ -314,19 +312,16 @@ impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind { } } -impl<'tcx> Stable<'tcx> for mir::NullOp<'tcx> { +impl<'tcx> Stable<'tcx> for mir::NullOp { type T = crate::mir::NullOp; fn stable<'cx>( &self, - tables: &mut Tables<'cx, BridgeTys>, - cx: &CompilerCtxt<'cx, BridgeTys>, + _: &mut Tables<'cx, BridgeTys>, + _: &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(), - ), RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op { UbChecks => crate::mir::RuntimeChecks::UbChecks, ContractChecks => crate::mir::RuntimeChecks::ContractChecks, diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index eb751da7c7363..4b19d0f16d78a 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -264,7 +264,6 @@ fn recurse_build<'tcx>( ExprKind::VarRef { .. } | ExprKind::UpvarRef { .. } | ExprKind::StaticRef { .. } - | ExprKind::OffsetOf { .. } | ExprKind::ThreadLocalRef(_) => { error(GenericConstantTooComplexSub::OperationNotSupported(node.span))? } @@ -364,7 +363,6 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::ZstLiteral { .. } | thir::ExprKind::StaticRef { .. } | thir::ExprKind::InlineAsm(_) - | thir::ExprKind::OffsetOf { .. } | thir::ExprKind::ThreadLocalRef(_) | thir::ExprKind::Yield { .. } => false, } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4f6a425a09839..f853618c39bd6 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2781,6 +2781,23 @@ pub const fn size_of() -> usize; #[rustc_intrinsic] pub const fn align_of() -> usize; +/// The offset of a field inside a type. +/// +/// Note that, unlike most intrinsics, this is safe to call; +/// it does not require an `unsafe` block. +/// Therefore, implementations must not require the user to uphold +/// any safety invariants. +/// +/// The stabilized version of this intrinsic is [`core::mem::offset_of`]. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_stable_indirect] +#[rustc_intrinsic_const_stable_indirect] +#[rustc_intrinsic] +#[lang = "offset_of"] +pub const fn offset_of(variant: u32, field: u32) -> usize; + /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. /// diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 619e8a263db40..a75bedeb5194b 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1418,10 +1418,10 @@ impl SizedTypeProperties for T {} /// [`offset_of_enum`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-enum.html /// [`offset_of_slice`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-slice.html #[stable(feature = "offset_of", since = "1.77.0")] -#[allow_internal_unstable(builtin_syntax)] +#[allow_internal_unstable(builtin_syntax, core_intrinsics)] pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { // The `{}` is for better error messages - {builtin # offset_of($Container, $($fields)+)} + const {builtin # offset_of($Container, $($fields)+)} } /// Create a fresh instance of the inhabited ZST type `T`. 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 0cf1ad348953b..c4a0acda779ce 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::RuntimeChecks(_), _) + Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, cx.tcx); diff --git a/tests/crashes/123959.rs b/tests/crashes/123959.rs deleted file mode 100644 index fe22c0225ed1c..0000000000000 --- a/tests/crashes/123959.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #123959 -#![feature(generic_const_exprs)] -fn foo(_: [(); std::mem::offset_of!((T,), 0)]) {} - -pub fn main() {} diff --git a/tests/crashes/125680.rs b/tests/crashes/125680.rs deleted file mode 100644 index 09f4f318bdddf..0000000000000 --- a/tests/crashes/125680.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: rust-lang/rust#125680 -//@ edition:2021 - -#![feature(generic_const_exprs)] - -use core::fmt::Debug; - -struct Inline -where - [(); std::mem::offset_of!((T,), 0)]:, -{} - -fn main() { - let dst = Inline::::new(0); // BANG! -} diff --git a/tests/crashes/129425.rs b/tests/crashes/129425.rs deleted file mode 100644 index ac7dc0078474d..0000000000000 --- a/tests/crashes/129425.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: rust-lang/rust#129425 - -//@compile-flags: --crate-type=lib - -#![feature(generic_const_exprs)] -fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} diff --git a/tests/crashes/136175-2.rs b/tests/crashes/136175-2.rs deleted file mode 100644 index 28f8ff7fd1cd9..0000000000000 --- a/tests/crashes/136175-2.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: #136175 -#![feature(generic_const_exprs)] -#![allow(incomplete_features)] - -trait Trait {} - -struct A(T) -where - [(); std::mem::offset_of!((T,), 0)]:; - -fn main() { - let x: A; -} diff --git a/tests/mir-opt/building/offset_of.rs b/tests/mir-opt/building/offset_of.rs new file mode 100644 index 0000000000000..e848c57b57c83 --- /dev/null +++ b/tests/mir-opt/building/offset_of.rs @@ -0,0 +1,115 @@ +//@ compile-flags: -Zmir-opt-level=0 +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(offset_of_enum)] + +use std::marker::PhantomData; +use std::mem::offset_of; + +struct Alpha { + x: u8, + y: u16, + z: Beta, +} + +struct Beta(u8, u8); + +struct Gamma { + x: u8, + y: u16, + _t: T, +} + +#[repr(C)] +struct Delta { + _phantom: PhantomData, + x: u8, + y: u16, +} + +enum Blah { + A, + B { x: u8, y: usize }, +} + +// CHECK-LABEL: fn concrete( +fn concrete() { + // CHECK: debug x => [[x:_.*]]; + // CHECK: debug y => [[y:_.*]]; + // CHECK: debug h => [[h:_.*]]; + // CHECK: debug z0 => [[z0:_.*]]; + // CHECK: debug z1 => [[z1:_.*]]; + + // CHECK: [[x]] = const concrete::[[const_x:.*]]; + let x = offset_of!(Alpha, x); + + // CHECK: [[y]] = const concrete::[[const_y:.*]]; + let y = offset_of!(Alpha, y); + + // CHECK: [[h]] = const concrete::[[const_h:.*]]; + let h = offset_of!(Blah, B.y); + + // CHECK: [[z0]] = const concrete::[[const_z0:.*]]; + let z0 = offset_of!(Alpha, z.0); + + // CHECK: [[z1]] = const concrete::[[const_z1:.*]]; + let z1 = offset_of!(Alpha, z.1); +} + +// CHECK: concrete::[[const_x]]: usize +// CHECK: _0 = offset_of::(const 0_u32, const 0_u32) + +// CHECK: concrete::[[const_y]]: usize +// CHECK: _0 = offset_of::(const 0_u32, const 1_u32) + +// CHECK: concrete::[[const_h]]: usize +// CHECK: _0 = offset_of::(const 1_u32, const 1_u32) + +// CHECK: concrete::[[const_z0]]: usize +// CHECK: [[z:_.*]] = offset_of::(const 0_u32, const 2_u32) +// CHECK: [[z0:_.*]] = offset_of::(const 0_u32, const 0_u32) +// CHECK: [[sum:_.*]] = AddWithOverflow(copy [[z]], copy [[z0]]); +// CHECK: _0 = move ([[sum]].0: usize); + +// CHECK: concrete::[[const_z1]]: usize +// CHECK: [[z:_.*]] = offset_of::(const 0_u32, const 2_u32) +// CHECK: [[z1:_.*]] = offset_of::(const 0_u32, const 1_u32) +// CHECK: [[sum:_.*]] = AddWithOverflow(copy [[z]], copy [[z1]]); +// CHECK: _0 = move ([[sum]].0: usize); + +// CHECK-LABEL: fn generic( +fn generic() { + // CHECK: debug gx => [[gx:_.*]]; + // CHECK: debug gy => [[gy:_.*]]; + // CHECK: debug dx => [[dx:_.*]]; + // CHECK: debug dy => [[dy:_.*]]; + + // CHECK: [[gx]] = const generic::::[[const_gx:.*]]; + let gx = offset_of!(Gamma, x); + + // CHECK: [[gy]] = const generic::::[[const_gy:.*]]; + let gy = offset_of!(Gamma, y); + + // CHECK: [[dx]] = const generic::::[[const_dx:.*]]; + let dx = offset_of!(Delta, x); + + // CHECK: [[dy]] = const generic::::[[const_dy:.*]]; + let dy = offset_of!(Delta, y); +} + +// CHECK: generic::[[const_gx]]: usize +// CHECK: _0 = offset_of::>(const 0_u32, const 0_u32) + +// CHECK: generic::[[const_gy]]: usize +// CHECK: _0 = offset_of::>(const 0_u32, const 1_u32) + +// CHECK: generic::[[const_dx]]: usize +// CHECK: _0 = offset_of::>(const 0_u32, const 1_u32) + +// CHECK: generic::[[const_dy]]: usize +// CHECK: _0 = offset_of::>(const 0_u32, const 2_u32) + +fn main() { + concrete(); + generic::<()>(); +} diff --git a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff index 77a2c5bcccc72..cbe701b81b331 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-abort.diff @@ -34,25 +34,25 @@ bb0: { StorageLive(_1); -- _1 = OffsetOf(Alpha, [(0, 0)]); +- _1 = const concrete::{constant#0}; + _1 = const 4_usize; StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 1)]); +- _2 = const concrete::{constant#1}; + _2 = const 0_usize; StorageLive(_3); -- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); +- _3 = const concrete::{constant#2}; + _3 = const 2_usize; StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); +- _4 = const concrete::{constant#3}; + _4 = const 3_usize; StorageLive(_5); -- _5 = OffsetOf(Epsilon, [(0, 0)]); +- _5 = const concrete::{constant#4}; + _5 = const 1_usize; StorageLive(_6); -- _6 = OffsetOf(Epsilon, [(0, 1)]); +- _6 = const concrete::{constant#5}; + _6 = const 2_usize; StorageLive(_7); -- _7 = OffsetOf(Epsilon, [(2, 0)]); +- _7 = const concrete::{constant#6}; + _7 = const 4_usize; _0 = const (); StorageDead(_7); diff --git a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff index 77a2c5bcccc72..cbe701b81b331 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.GVN.panic-unwind.diff @@ -34,25 +34,25 @@ bb0: { StorageLive(_1); -- _1 = OffsetOf(Alpha, [(0, 0)]); +- _1 = const concrete::{constant#0}; + _1 = const 4_usize; StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 1)]); +- _2 = const concrete::{constant#1}; + _2 = const 0_usize; StorageLive(_3); -- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); +- _3 = const concrete::{constant#2}; + _3 = const 2_usize; StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); +- _4 = const concrete::{constant#3}; + _4 = const 3_usize; StorageLive(_5); -- _5 = OffsetOf(Epsilon, [(0, 0)]); +- _5 = const concrete::{constant#4}; + _5 = const 1_usize; StorageLive(_6); -- _6 = OffsetOf(Epsilon, [(0, 1)]); +- _6 = const concrete::{constant#5}; + _6 = const 2_usize; StorageLive(_7); -- _7 = OffsetOf(Epsilon, [(2, 0)]); +- _7 = const concrete::{constant#6}; + _7 = const 4_usize; _0 = const (); StorageDead(_7); diff --git a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff index 130c31eff8ccc..6bcebeb8a3b9c 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-abort.diff @@ -34,21 +34,21 @@ bb0: { StorageLive(_1); - _1 = OffsetOf(Gamma, [(0, 0)]); + _1 = const generic::::{constant#0}; StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 1)]); + _2 = const generic::::{constant#1}; StorageLive(_3); -- _3 = OffsetOf(Delta, [(0, 1)]); +- _3 = const generic::::{constant#2}; + _3 = const 0_usize; StorageLive(_4); -- _4 = OffsetOf(Delta, [(0, 2)]); +- _4 = const generic::::{constant#3}; + _4 = const 2_usize; StorageLive(_5); - _5 = OffsetOf(Zeta, [(0, 0)]); + _5 = const generic::::{constant#4}; StorageLive(_6); - _6 = OffsetOf(Zeta, [(0, 1)]); + _6 = const generic::::{constant#5}; StorageLive(_7); - _7 = OffsetOf(Zeta, [(1, 0)]); + _7 = const generic::::{constant#6}; _0 = const (); StorageDead(_7); StorageDead(_6); diff --git a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff index 130c31eff8ccc..6bcebeb8a3b9c 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.GVN.panic-unwind.diff @@ -34,21 +34,21 @@ bb0: { StorageLive(_1); - _1 = OffsetOf(Gamma, [(0, 0)]); + _1 = const generic::::{constant#0}; StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 1)]); + _2 = const generic::::{constant#1}; StorageLive(_3); -- _3 = OffsetOf(Delta, [(0, 1)]); +- _3 = const generic::::{constant#2}; + _3 = const 0_usize; StorageLive(_4); -- _4 = OffsetOf(Delta, [(0, 2)]); +- _4 = const generic::::{constant#3}; + _4 = const 2_usize; StorageLive(_5); - _5 = OffsetOf(Zeta, [(0, 0)]); + _5 = const generic::::{constant#4}; StorageLive(_6); - _6 = OffsetOf(Zeta, [(0, 1)]); + _6 = const generic::::{constant#5}; StorageLive(_7); - _7 = OffsetOf(Zeta, [(1, 0)]); + _7 = const generic::::{constant#6}; _0 = const (); StorageDead(_7); StorageDead(_6); diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff deleted file mode 100644 index 92691d0f80703..0000000000000 --- a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-abort.diff +++ /dev/null @@ -1,44 +0,0 @@ -- // MIR for `concrete` before DataflowConstProp -+ // MIR for `concrete` after DataflowConstProp - - fn concrete() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug x => _1; - let _2: usize; - scope 2 { - debug y => _2; - let _3: usize; - scope 3 { - debug z0 => _3; - let _4: usize; - scope 4 { - debug z1 => _4; - } - } - } - } - - bb0: { - StorageLive(_1); -- _1 = OffsetOf(Alpha, [(0, 0)]); -+ _1 = const 4_usize; - StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 1)]); -+ _2 = const 0_usize; - StorageLive(_3); -- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); -+ _3 = const 2_usize; - StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); -+ _4 = const 3_usize; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff deleted file mode 100644 index 92691d0f80703..0000000000000 --- a/tests/mir-opt/dataflow-const-prop/offset_of.concrete.DataflowConstProp.panic-unwind.diff +++ /dev/null @@ -1,44 +0,0 @@ -- // MIR for `concrete` before DataflowConstProp -+ // MIR for `concrete` after DataflowConstProp - - fn concrete() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug x => _1; - let _2: usize; - scope 2 { - debug y => _2; - let _3: usize; - scope 3 { - debug z0 => _3; - let _4: usize; - scope 4 { - debug z1 => _4; - } - } - } - } - - bb0: { - StorageLive(_1); -- _1 = OffsetOf(Alpha, [(0, 0)]); -+ _1 = const 4_usize; - StorageLive(_2); -- _2 = OffsetOf(Alpha, [(0, 1)]); -+ _2 = const 0_usize; - StorageLive(_3); -- _3 = OffsetOf(Alpha, [(0, 2), (0, 0)]); -+ _3 = const 2_usize; - StorageLive(_4); -- _4 = OffsetOf(Alpha, [(0, 2), (0, 1)]); -+ _4 = const 3_usize; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff deleted file mode 100644 index c6908166defb8..0000000000000 --- a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-abort.diff +++ /dev/null @@ -1,42 +0,0 @@ -- // MIR for `generic` before DataflowConstProp -+ // MIR for `generic` after DataflowConstProp - - fn generic() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug gx => _1; - let _2: usize; - scope 2 { - debug gy => _2; - let _3: usize; - scope 3 { - debug dx => _3; - let _4: usize; - scope 4 { - debug dy => _4; - } - } - } - } - - bb0: { - StorageLive(_1); - _1 = OffsetOf(Gamma, [(0, 0)]); - StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 1)]); - StorageLive(_3); -- _3 = OffsetOf(Delta, [(0, 1)]); -+ _3 = const 0_usize; - StorageLive(_4); -- _4 = OffsetOf(Delta, [(0, 2)]); -+ _4 = const 2_usize; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff deleted file mode 100644 index c6908166defb8..0000000000000 --- a/tests/mir-opt/dataflow-const-prop/offset_of.generic.DataflowConstProp.panic-unwind.diff +++ /dev/null @@ -1,42 +0,0 @@ -- // MIR for `generic` before DataflowConstProp -+ // MIR for `generic` after DataflowConstProp - - fn generic() -> () { - let mut _0: (); - let _1: usize; - scope 1 { - debug gx => _1; - let _2: usize; - scope 2 { - debug gy => _2; - let _3: usize; - scope 3 { - debug dx => _3; - let _4: usize; - scope 4 { - debug dy => _4; - } - } - } - } - - bb0: { - StorageLive(_1); - _1 = OffsetOf(Gamma, [(0, 0)]); - StorageLive(_2); - _2 = OffsetOf(Gamma, [(0, 1)]); - StorageLive(_3); -- _3 = OffsetOf(Delta, [(0, 1)]); -+ _3 = const 0_usize; - StorageLive(_4); -- _4 = OffsetOf(Delta, [(0, 2)]); -+ _4 = const 2_usize; - _0 = const (); - StorageDead(_4); - StorageDead(_3); - StorageDead(_2); - StorageDead(_1); - return; - } - } - diff --git a/tests/mir-opt/dataflow-const-prop/offset_of.rs b/tests/mir-opt/dataflow-const-prop/offset_of.rs deleted file mode 100644 index bb4a74d3712a0..0000000000000 --- a/tests/mir-opt/dataflow-const-prop/offset_of.rs +++ /dev/null @@ -1,75 +0,0 @@ -//@ test-mir-pass: DataflowConstProp -// EMIT_MIR_FOR_EACH_PANIC_STRATEGY - -use std::marker::PhantomData; -use std::mem::offset_of; - -struct Alpha { - x: u8, - y: u16, - z: Beta, -} - -struct Beta(u8, u8); - -struct Gamma { - x: u8, - y: u16, - _t: T, -} - -#[repr(C)] -struct Delta { - _phantom: PhantomData, - x: u8, - y: u16, -} - -// EMIT_MIR offset_of.concrete.DataflowConstProp.diff - -// CHECK-LABEL: fn concrete( -fn concrete() { - // CHECK: debug x => [[x:_.*]]; - // CHECK: debug y => [[y:_.*]]; - // CHECK: debug z0 => [[z0:_.*]]; - // CHECK: debug z1 => [[z1:_.*]]; - - // CHECK: [[x]] = const 4_usize - let x = offset_of!(Alpha, x); - - // CHECK: [[y]] = const 0_usize - let y = offset_of!(Alpha, y); - - // CHECK: [[z0]] = const 2_usize - let z0 = offset_of!(Alpha, z.0); - - // CHECK: [[z1]] = const 3_usize - let z1 = offset_of!(Alpha, z.1); -} - -// EMIT_MIR offset_of.generic.DataflowConstProp.diff - -// CHECK-LABEL: fn generic( -fn generic() { - // CHECK: debug gx => [[gx:_.*]]; - // CHECK: debug gy => [[gy:_.*]]; - // CHECK: debug dx => [[dx:_.*]]; - // CHECK: debug dy => [[dy:_.*]]; - - // CHECK: [[gx]] = OffsetOf(Gamma, [(0, 0)]); - let gx = offset_of!(Gamma, x); - - // CHECK: [[gy]] = OffsetOf(Gamma, [(0, 1)]); - let gy = offset_of!(Gamma, y); - - // CHECK: [[dx]] = const 0_usize - let dx = offset_of!(Delta, x); - - // CHECK: [[dy]] = const 2_usize - let dy = offset_of!(Delta, y); -} - -fn main() { - concrete(); - generic::<()>(); -} diff --git a/tests/ui/offset-of/inside-array-length.rs b/tests/ui/offset-of/inside-array-length.rs new file mode 100644 index 0000000000000..9a2aec18e524c --- /dev/null +++ b/tests/ui/offset-of/inside-array-length.rs @@ -0,0 +1,23 @@ +//! Regression test for ICEs #123959, #125680, #129425 and #136175. +//@ edition:2021 + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait Trait {} + +fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} +//~^ ERROR overly complex generic constant +//~| ERROR cycle detected when evaluating type-level constant + +struct Inline +//~^ ERROR type parameter `T` is never used +where + [(); std::mem::offset_of!((T,), 0)]:, + //~^ ERROR overly complex generic constant +{} + +fn main() { + let dst: Inline; + //~^ ERROR the size for values of type `dyn Trait` cannot be known at compilation time +} diff --git a/tests/ui/offset-of/inside-array-length.stderr b/tests/ui/offset-of/inside-array-length.stderr new file mode 100644 index 0000000000000..de110939d4aad --- /dev/null +++ b/tests/ui/offset-of/inside-array-length.stderr @@ -0,0 +1,90 @@ +error: overly complex generic constant + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constants + | + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future + = note: this error originates in the macro `std::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0392]: type parameter `T` is never used + --> $DIR/inside-array-length.rs:13:15 + | +LL | struct Inline + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: overly complex generic constant + --> $DIR/inside-array-length.rs:16:10 + | +LL | [(); std::mem::offset_of!((T,), 0)]:, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const blocks are not supported in generic constants + | + = help: consider moving this anonymous constant into a `const` function + = note: this operation may be supported in the future + = note: this error originates in the macro `std::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0391]: cycle detected when evaluating type-level constant + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: ...which requires const-evaluating + checking `foo::{constant#0}`... + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires caching mir of `foo::{constant#0}` for CTFE... + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires elaborating drops for `foo::{constant#0}`... + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires borrow-checking `foo::{constant#0}`... + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires normalizing `Binder { value: ConstEvaluatable(UnevaluatedConst { def: DefId(0:7 ~ inside_array_length[07d6]::foo::{constant#0}), args: ['^c_1, T/#1] }), bound_vars: [] }`... + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires evaluating type-level constant, completing the cycle +note: cycle used when normalizing `inside_array_length::::foo::{constant#0}` + --> $DIR/inside-array-length.rs:9:27 + | +LL | fn foo<'a, T: 'a>(_: [(); std::mem::offset_of!((T,), 0)]) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + = note: this error originates in the macro `std::mem::offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time + --> $DIR/inside-array-length.rs:21:14 + | +LL | let dst: Inline; + | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Trait` +note: required by an implicit `Sized` bound in `Inline` + --> $DIR/inside-array-length.rs:13:15 + | +LL | struct Inline + | ^ required by the implicit `Sized` requirement on this type parameter in `Inline` +help: consider relaxing the implicit `Sized` restriction + | +LL | struct Inline + | ++++++++ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0391, E0392. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr index 34ad931d0caac..60b2b14cade3e 100644 --- a/tests/ui/offset-of/offset-of-output-type.stderr +++ b/tests/ui/offset-of/offset-of-output-type.stderr @@ -41,9 +41,6 @@ LL | let _: isize = offset_of!(S, v); error[E0308]: mismatched types --> $DIR/offset-of-output-type.rs:17:5 | -LL | fn main() { - | - expected `()` because of default return type -... LL | offset_of!(S, v) | ^^^^^^^^^^^^^^^^ expected `()`, found `usize` | diff --git a/tests/ui/offset-of/offset-of-unsized.rs b/tests/ui/offset-of/offset-of-unsized.rs index 5a84adcb9e511..3014cca283834 100644 --- a/tests/ui/offset-of/offset-of-unsized.rs +++ b/tests/ui/offset-of/offset-of-unsized.rs @@ -2,13 +2,52 @@ // regression test for #112051, not in `offset-of-dst` as the issue is in codegen, // and isn't triggered in the presence of typeck errors +#![feature(extern_types)] + +use std::mem::offset_of; + +#[repr(C)] +struct Alpha { + x: u8, + y: u16, + z: [u8], +} + +trait Trait {} + +#[repr(C)] +struct Beta { + x: u8, + y: u16, + z: dyn Trait, +} + +unsafe extern "C" { + type Extern; +} + +#[repr(C)] +struct Gamma { + x: u8, + y: u16, + z: Extern, +} + struct S { a: u64, b: T, } -trait Tr {} fn main() { - let _a = core::mem::offset_of!(S, a); - let _b = core::mem::offset_of!((u64, dyn Tr), 0); + let _ = offset_of!(Alpha, x); + let _ = offset_of!(Alpha, y); + + let _ = offset_of!(Beta, x); + let _ = offset_of!(Beta, y); + + let _ = offset_of!(Gamma, x); + let _ = offset_of!(Gamma, y); + + let _ = offset_of!(S, a); + let _ = offset_of!((u64, dyn Trait), 0); } diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index a12ea0786f910..9e6797c727f03 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -312,7 +312,7 @@ mod expressions { - { builtin # offset_of(T, field) }; + const { builtin # offset_of(T, field) }; } /// ExprKind::MacCall fn expr_mac_call() { "..."; "..."; "..."; } diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index ee22c3aeba9df..2dc30298e9b6a 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -343,7 +343,7 @@ mod expressions { - { offset_of!(T, field) }; + const { offset_of!(T, field) }; } /// ExprKind::MacCall fn expr_mac_call() { "..."; "..."; "..."; } From a1e15b216cb93b5acc44bb23d9ff3f31e09baf7b Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 1 Nov 2025 23:18:21 +0000 Subject: [PATCH 2/5] Honor allow_internal_unstable for const intrinsics. --- compiler/rustc_const_eval/src/check_consts/check.rs | 13 ++++++++++--- library/core/src/intrinsics/mod.rs | 1 - 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 4110317adcf48..66a2afa0aa7d0 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -853,9 +853,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } // Intrinsics are language primitives, not regular calls, so treat them separately. - if let Some(intrinsic) = tcx.intrinsic(callee) - && intrinsic.name != sym::offset_of - { + if let Some(intrinsic) = tcx.intrinsic(callee) { if !tcx.is_const_fn(callee) { // Non-const intrinsic. self.check_op(ops::IntrinsicNonConst { name: intrinsic.name }); @@ -888,6 +886,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { feature, .. }) => { + // We only honor `span.allows_unstable` aka `#[allow_internal_unstable]` + // if the callee is safe to expose, to avoid bypassing recursive stability. + // This is not ideal since it means the user sees an error, not the macro + // author, but that's also the case if one forgets to set + // `#[allow_internal_unstable]` in the first place. + if self.span.allows_unstable(feature) && is_const_stable { + return; + } + self.check_op(ops::IntrinsicUnstable { name: intrinsic.name, feature, diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index f853618c39bd6..4142700bce15e 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2792,7 +2792,6 @@ pub const fn align_of() -> usize; #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_stable_indirect] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] #[lang = "offset_of"] From 72349923ea4b5197b17f61898d27d814b85522a6 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 6 Nov 2025 23:45:42 +0000 Subject: [PATCH 3/5] Simplify implementation. --- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d97200aceaf99..057cd3668cfe0 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -206,9 +206,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { sym::offset_of => { let tp_ty = instance.args.type_at(0); - let u32_layout = self.layout_of(self.tcx.types.u32)?; - let variant = self.read_scalar(&args[0])?.to_bits(u32_layout.size)? as u32; - let field = self.read_scalar(&args[1])?.to_bits(u32_layout.size)? as usize; + let variant = self.read_scalar(&args[0])?.to_u32()?; + let field = self.read_scalar(&args[1])?.to_u32()? as usize; let layout = self.layout_of(tp_ty)?; let cx = ty::layout::LayoutCx::new(*self.tcx, self.typing_env); From d65ccdd0cb5230ce74f4b01e9bf85643e1da12e3 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 6 Nov 2025 23:48:12 +0000 Subject: [PATCH 4/5] Complete doc. --- library/core/src/intrinsics/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4142700bce15e..e05a194344908 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2788,7 +2788,11 @@ pub const fn align_of() -> usize; /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// +/// This intrinsic can only be evaluated at compile-time, and should appear +/// constants or inline const blocks. +/// /// The stabilized version of this intrinsic is [`core::mem::offset_of`]. +/// This intrinsic is also a lang item so `offset_of!` can desugar to calls to it. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_const_unstable(feature = "core_intrinsics", issue = "none")] From dcf09166f5b9c9c61e38824cf227d4432cb27975 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 9 Nov 2025 02:57:31 +0000 Subject: [PATCH 5/5] Replace Rvalue::NullaryOp by a variant in mir::ConstValue. --- compiler/rustc_borrowck/src/lib.rs | 4 -- .../src/polonius/legacy/loan_invalidations.rs | 2 - compiler/rustc_borrowck/src/type_check/mod.rs | 3 - compiler/rustc_codegen_cranelift/src/base.rs | 13 +---- .../rustc_codegen_cranelift/src/constant.rs | 5 ++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 8 +++ compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 15 ----- .../src/check_consts/check.rs | 1 - .../src/check_consts/qualifs.rs | 4 +- .../src/check_consts/resolver.rs | 1 - .../rustc_const_eval/src/interpret/operand.rs | 4 ++ .../src/interpret/operator.rs | 8 --- .../rustc_const_eval/src/interpret/step.rs | 5 -- compiler/rustc_middle/src/mir/consts.rs | 39 ++++++++++++- compiler/rustc_middle/src/mir/mod.rs | 6 +- compiler/rustc_middle/src/mir/pretty.rs | 11 +--- compiler/rustc_middle/src/mir/statement.rs | 10 ---- compiler/rustc_middle/src/mir/syntax.rs | 32 ---------- compiler/rustc_middle/src/mir/traversal.rs | 4 +- compiler/rustc_middle/src/mir/visit.rs | 7 +-- .../rustc_middle/src/ty/structural_impls.rs | 2 +- .../src/impls/borrowed_locals.rs | 1 - .../src/move_paths/builder.rs | 5 +- .../rustc_mir_transform/src/cost_checker.rs | 29 +--------- .../src/dataflow_const_prop.rs | 3 - compiler/rustc_mir_transform/src/gvn.rs | 3 - .../rustc_mir_transform/src/instsimplify.rs | 43 ++++++++------ .../src/known_panics_lint.rs | 3 - compiler/rustc_mir_transform/src/lint.rs | 1 - .../src/lower_intrinsics.rs | 9 ++- .../rustc_mir_transform/src/promote_consts.rs | 4 -- compiler/rustc_mir_transform/src/validate.rs | 1 - compiler/rustc_public/src/alloc.rs | 1 + compiler/rustc_public/src/mir/body.rs | 20 ------- compiler/rustc_public/src/mir/pretty.rs | 3 - compiler/rustc_public/src/mir/visit.rs | 1 - compiler/rustc_public/src/ty.rs | 11 ++++ .../src/unstable/convert/stable/mir.rs | 21 ++++--- compiler/rustc_public/src/visitor.rs | 4 +- library/core/src/ub_checks.rs | 21 ++++--- .../clippy_utils/src/qualify_min_const_fn.rs | 5 +- tests/codegen-llvm/slice-iter-len-eq-zero.rs | 8 ++- ...ifyConstCondition-after-inst-simplify.diff | 5 +- ...ng_operand.test.GVN.32bit.panic-abort.diff | 58 +++++++++---------- ...ng_operand.test.GVN.64bit.panic-abort.diff | 58 +++++++++---------- ...l_unsigned_smaller.Inline.panic-abort.diff | 6 +- ..._unsigned_smaller.Inline.panic-unwind.diff | 6 +- ..._shr_signed_bigger.Inline.panic-abort.diff | 6 +- ...shr_signed_bigger.Inline.panic-unwind.diff | 6 +- ...d.unwrap_unchecked.Inline.panic-abort.diff | 5 +- ....unwrap_unchecked.Inline.panic-unwind.diff | 5 +- tests/mir-opt/instsimplify/ub_check.rs | 3 +- ...hecked.InstSimplify-after-simplifycfg.diff | 7 +-- 53 files changed, 210 insertions(+), 336 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 20411fcc16fbb..e457b7942a82f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1559,10 +1559,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { self.consume_operand(location, (operand2, span), state); } - Rvalue::NullaryOp(_op) => { - // nullary ops take no dynamic input; no borrowck effect. - } - Rvalue::Aggregate(aggregate_kind, operands) => { // We need to report back the list of mutable upvars that were // moved into the closure and subsequently used by the closure, diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index de479a7d74c8e..85a08b7399e56 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -314,8 +314,6 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { self.consume_operand(location, operand2); } - Rvalue::NullaryOp(_op) => {} - Rvalue::Aggregate(_, operands) => { for operand in operands { self.consume_operand(location, operand); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5f86e8646c03f..e3fccc45ad301 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1046,8 +1046,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} - Rvalue::ShallowInitBox(_operand, ty) => { let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]); @@ -2201,7 +2199,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::BinaryOp(..) - | Rvalue::NullaryOp(..) | Rvalue::CopyForDeref(..) | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e445f9457477d..c6c12cbdf8742 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -10,7 +10,7 @@ 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, HasTypingEnv}; +use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -853,17 +853,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: fx.bcx.ins().nop(); } } - Rvalue::NullaryOp(ref null_op) => { - assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); - let val = match null_op { - NullOp::RuntimeChecks(kind) => 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), - ); - lval.write_cvalue(fx, val); - } Rvalue::Aggregate(ref kind, ref operands) if matches!(**kind, AggregateKind::RawPtr(..)) => { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 2b65b82906818..29c8e8ab1e522 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -215,6 +215,11 @@ 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()), diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 5a139702f81d9..29108043feffe 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -165,6 +165,14 @@ 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 { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 96a9fab252464..48bd6881cc7ec 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -613,21 +613,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - mir::Rvalue::NullaryOp(ref null_op) => { - let val = match null_op { - mir::NullOp::RuntimeChecks(kind) => { - let val = kind.value(bx.tcx().sess); - bx.cx().const_bool(val) - } - }; - let tcx = self.cx.tcx(); - OperandRef { - val: OperandValue::Immediate(val), - layout: self.cx.layout_of(null_op.ty(tcx)), - move_annotation: None, - } - } - mir::Rvalue::ThreadLocalRef(def_id) => { assert!(bx.cx().tcx().is_static(def_id)); let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id, bx.typing_env())); diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 66a2afa0aa7d0..e7627fd3326de 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -645,7 +645,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(op, operand) => { diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index f50c6af53bf13..49a477d8fdbae 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -230,9 +230,7 @@ where F: FnMut(Local) -> bool, { match rvalue { - Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(..) => { - Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) - } + Rvalue::ThreadLocalRef(_) => Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)), Rvalue::Discriminant(place) => in_place::(cx, in_local, place.as_ref()), diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index e6e3948305af7..d4cc21996aea8 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -198,7 +198,6 @@ where | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) | mir::Rvalue::BinaryOp(..) - | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) | mir::Rvalue::Aggregate(..) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 560b0e1ae4e63..1b972d8a2f427 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -888,6 +888,10 @@ 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/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 8548b774ddb4e..ca8c096d3ab41 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,7 +1,6 @@ use either::Either; use rustc_abi::Size; use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir::NullOp; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, FloatTy, ScalarInt}; @@ -505,11 +504,4 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } } - - pub fn nullary_op(&self, null_op: NullOp) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - use rustc_middle::mir::NullOp::*; - interp_ok(match null_op { - RuntimeChecks(r) => ImmTy::from_bool(M::runtime_checks(self, r)?, *self.tcx), - }) - } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 88a1160947583..47e8e2a9ec512 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -203,11 +203,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_immediate(*result, &dest)?; } - NullaryOp(null_op) => { - let val = self.nullary_op(null_op)?; - self.write_immediate(*val, &dest)?; - } - Aggregate(box ref kind, ref operands) => { self.write_aggregate(kind, operands, &dest)?; } diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 5764a9c84eeaf..104f50c56fd6f 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -70,6 +70,10 @@ 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")] @@ -79,7 +83,10 @@ impl ConstValue { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { - ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None, + ConstValue::Indirect { .. } + | ConstValue::Slice { .. } + | ConstValue::ZeroSized + | ConstValue::RuntimeChecks(_) => None, ConstValue::Scalar(val) => Some(val), } } @@ -135,7 +142,7 @@ impl ConstValue { tcx: TyCtxt<'tcx>, ) -> Option<&'tcx [u8]> { let (alloc_id, start, len) = match self { - ConstValue::Scalar(_) | ConstValue::ZeroSized => { + ConstValue::Scalar(_) | ConstValue::ZeroSized | ConstValue::RuntimeChecks(_) => { bug!("`try_get_slice_bytes` on non-slice constant") } &ConstValue::Slice { alloc_id, meta } => (alloc_id, 0, meta), @@ -187,7 +194,9 @@ 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(_)) => return false, + ConstValue::ZeroSized + | ConstValue::Scalar(Scalar::Int(_)) + | ConstValue::RuntimeChecks(_) => 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. @@ -226,6 +235,29 @@ 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 @@ -519,6 +551,7 @@ 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 44b1c0047b7e5..d008c6fb2d4d1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -607,6 +607,9 @@ 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) }; @@ -649,9 +652,6 @@ impl<'tcx> Body<'tcx> { } match rvalue { - 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 924d2f4ee0152..a56ab94f1f95f 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1097,15 +1097,6 @@ impl<'tcx> Debug for Rvalue<'tcx> { BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"), UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"), Discriminant(ref place) => write!(fmt, "discriminant({place:?})"), - NullaryOp(ref op) => match op { - NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"), - NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { - write!(fmt, "ContractChecks()") - } - NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => { - write!(fmt, "OverflowChecks()") - } - }, ThreadLocalRef(did) => ty::tls::with(|tcx| { let muta = tcx.static_mutability(did).unwrap().prefix_str(); write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) @@ -1527,6 +1518,7 @@ 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,6 +1961,7 @@ 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 bd4188dd0ff49..942eb727de676 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -756,7 +756,6 @@ impl<'tcx> Rvalue<'tcx> { _, ) | Rvalue::BinaryOp(_, _) - | Rvalue::NullaryOp(_) | Rvalue::UnaryOp(_, _) | Rvalue::Discriminant(_) | Rvalue::Aggregate(_, _) @@ -794,7 +793,6 @@ impl<'tcx> Rvalue<'tcx> { op.ty(tcx, arg_ty) } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - 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 => { @@ -858,14 +856,6 @@ impl BorrowKind { } } -impl NullOp { - pub fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self { - NullOp::RuntimeChecks(_) => tcx.types.bool, - } - } -} - impl<'tcx> UnOp { pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { match self { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 204ad4815147b..e96d6824c6008 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1418,9 +1418,6 @@ pub enum Rvalue<'tcx> { /// matching types and return a value of that type. BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), - /// Computes a value as described by the operation. - NullaryOp(NullOp), - /// Exactly like `BinaryOp`, but less operands. /// /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; @@ -1561,35 +1558,6 @@ pub enum AggregateKind<'tcx> { RawPtr(Ty<'tcx>, Mutability), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum NullOp { - /// 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, - /// 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/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 7f6c7376501fa..4f599aea02545 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::RuntimeChecks`]. +/// of `if ::CONST`, as well as [`ConstValue::RuntimeChecks`]. /// -/// [`NullOp::RuntimeChecks`]: rustc_middle::mir::NullOp::RuntimeChecks +/// [`ConstValue::RuntimeChecks`]: rustc_middle::mir::ConstValue::RuntimeChecks pub fn mono_reachable<'a, 'tcx>( body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 6d251988cbbd8..da9b2b97235eb 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -775,8 +775,6 @@ macro_rules! make_mir_visitor { ); } - Rvalue::NullaryOp(_op) => {} - Rvalue::Aggregate(kind, operands) => { let kind = &$($mutability)? **kind; match kind { @@ -972,10 +970,7 @@ macro_rules! make_mir_visitor { self.visit_span($(& $mutability)? *span); match const_ { Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location), - Const::Val(_, ty) => { - self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); - } - Const::Unevaluated(_, ty) => { + Const::Val(_, ty) | Const::Unevaluated(_, ty) => { self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index cff415e9036ad..92f81c46ba0d1 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -253,7 +253,6 @@ TrivialTypeTraversalImpls! { crate::mir::FakeReadCause, crate::mir::Local, crate::mir::MirPhase, - crate::mir::NullOp, crate::mir::Promoted, crate::mir::RawPtrKind, crate::mir::RetagKind, @@ -294,6 +293,7 @@ TrivialTypeTraversalImpls! { // interners). TrivialTypeTraversalAndLiftImpls! { // tidy-alphabetical-start + crate::mir::RuntimeChecks, crate::ty::ParamTy, crate::ty::PlaceholderType, crate::ty::instance::ReifyReason, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 331e41bd126b7..4b2c52ad7999d 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -91,7 +91,6 @@ where | Rvalue::ThreadLocalRef(..) | Rvalue::Repeat(..) | Rvalue::BinaryOp(..) - | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) | Rvalue::Aggregate(..) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 0cd3405d1e61b..a90f3ef354440 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -448,10 +448,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { } } Rvalue::CopyForDeref(..) => unreachable!(), - Rvalue::Ref(..) - | Rvalue::RawPtr(..) - | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} + Rvalue::Ref(..) | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) => {} } } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 1a9af0e22bbe2..8f975866d1352 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -60,7 +60,7 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> { } impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { // Most costs are in rvalues and terminators, not in statements. match statement.kind { StatementKind::Intrinsic(ref ndi) => { @@ -69,31 +69,8 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { NonDivergingIntrinsic::CopyNonOverlapping(..) => CALL_PENALTY, }; } - _ => self.super_statement(statement, location), - } - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) { - match rvalue { - // FIXME: Should we do the same for `OverflowChecks`? - Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), ..) - if !self - .tcx - .sess - .opts - .unstable_opts - .inline_mir_preserve_debug - .unwrap_or(self.tcx.sess.ub_checks()) => - { - // If this is in optimized MIR it's because it's used later, - // so if we don't need UB checks this session, give a bonus - // here to offset the cost of the call later. - self.bonus += CALL_PENALTY; - } - // These are essentially constants that didn't end up in an Operand, - // so treat them as also being free. - Rvalue::NullaryOp(..) => {} - _ => self.penalty += INSTR_COST, + StatementKind::Assign(..) => self.penalty += INSTR_COST, + _ => {} } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index bccdd526ab7fd..232f07d31adbd 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -463,9 +463,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { FlatSet::Top => FlatSet::Top, } } - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => { - return ValueOrPlace::TOP; - } Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), Rvalue::Use(operand) => return self.handle_operand(operand, state), Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 8295e4ae58dd3..f6a9bec97d790 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -248,7 +248,6 @@ enum Value<'a, 'tcx> { Discriminant(VnIndex), // Operations. - NullaryOp(NullOp), UnaryOp(UnOp, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex), Cast { @@ -668,7 +667,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?; discr_value.into() } - NullaryOp(NullOp::RuntimeChecks(_)) => return None, UnaryOp(un_op, operand) => { let operand = self.eval_to_const(operand)?; let operand = self.ecx.read_immediate(operand).discard_err()?; @@ -1021,7 +1019,6 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { let op = self.simplify_operand(op, location)?; Value::Repeat(op, amount) } - Rvalue::NullaryOp(op) => Value::NullaryOp(op), Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location), Rvalue::Ref(_, borrow_kind, ref mut place) => { self.simplify_place_projection(place, location); diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 4922d74743c9a..7cb341818fab9 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -4,10 +4,11 @@ use rustc_abi::ExternAbi; use rustc_ast::attr; use rustc_hir::LangItem; use rustc_middle::bug; +use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout}; -use rustc_span::{DUMMY_SP, Symbol, sym}; +use rustc_span::{Symbol, sym}; use crate::simplify::simplify_duplicate_switch_targets; @@ -29,22 +30,22 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let preserve_ub_checks = + attr::contains_name(tcx.hir_krate_attrs(), sym::rustc_preserve_ub_checks); + if !preserve_ub_checks { + SimplifyUbCheck { tcx }.visit_body(body); + } let ctx = InstSimplifyContext { tcx, local_decls: &body.local_decls, typing_env: body.typing_env(tcx), }; - let preserve_ub_checks = - attr::contains_name(tcx.hir_krate_attrs(), sym::rustc_preserve_ub_checks); for block in body.basic_blocks.as_mut() { for statement in block.statements.iter_mut() { let StatementKind::Assign(box (.., rvalue)) = &mut statement.kind else { continue; }; - if !preserve_ub_checks { - ctx.simplify_ub_check(rvalue); - } ctx.simplify_bool_cmp(rvalue); ctx.simplify_ref_deref(rvalue); ctx.simplify_ptr_aggregate(rvalue); @@ -168,17 +169,6 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } } - fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { - // 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 }; - *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); - } - fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) { let Rvalue::Cast(kind, operand, cast_ty) = rvalue else { return }; @@ -362,3 +352,22 @@ fn resolve_rust_intrinsic<'tcx>( let intrinsic = tcx.intrinsic(def_id)?; Some((intrinsic.name, args)) } + +struct SimplifyUbCheck<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for SimplifyUbCheck<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.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()); + } + } +} diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 1f5d31932f1a2..53cb02d9c5b25 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -444,7 +444,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(..) | Rvalue::WrapUnsafeBinder(..) => {} } @@ -605,8 +604,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Ref(..) | RawPtr(..) => return None, - NullaryOp(NullOp::RuntimeChecks(_)) => return None, - ShallowInitBox(..) => return None, Cast(ref kind, ref value, to) => match kind { diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 2ab49645dc44f..88297a4efef7e 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -88,7 +88,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Lint<'a, 'tcx> { | Rvalue::ShallowInitBox(..) | Rvalue::WrapUnsafeBinder(..) => true, Rvalue::ThreadLocalRef(..) - | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) | Rvalue::BinaryOp(..) | Rvalue::Ref(..) diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index f25874fbbcb89..6740aa97fc8bd 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -35,7 +35,14 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::NullaryOp(NullOp::RuntimeChecks(op)), + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { + span: terminator.source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::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 6b0c331ff5415..2119448a5d813 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -449,10 +449,6 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(operand)?; } - Rvalue::NullaryOp(op) => match op { - NullOp::RuntimeChecks(_) => {} - }, - Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), Rvalue::UnaryOp(op, operand) => { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 91617be085c31..35d07f4352a24 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1439,7 +1439,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) - | Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) | Rvalue::Discriminant(_) => {} Rvalue::WrapUnsafeBinder(op, ty) => { diff --git a/compiler/rustc_public/src/alloc.rs b/compiler/rustc_public/src/alloc.rs index 0c35b3b25dfc0..5ede5b2b2712e 100644 --- a/compiler/rustc_public/src/alloc.rs +++ b/compiler/rustc_public/src/alloc.rs @@ -53,6 +53,7 @@ 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 fde4d40bea10a..9255a2f56317e 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -587,9 +587,6 @@ pub enum Rvalue { /// nature of this operation? ThreadLocalRef(crate::CrateItem), - /// Computes a value as described by the operation. - NullaryOp(NullOp), - /// Exactly like `BinaryOp`, but less operands. /// /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; @@ -641,7 +638,6 @@ impl Rvalue { .discriminant_ty() .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_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( @@ -1018,22 +1014,6 @@ pub enum CastKind { Subtype, } -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub enum NullOp { - /// 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 - ContractChecks, - /// cfg!(overflow_checks), but at codegen time - OverflowChecks, -} - impl Operand { /// Get the type of an operand relative to the local declaration. /// diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index d80e227f5a9ce..a03016bef884d 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -386,9 +386,6 @@ fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { Rvalue::ThreadLocalRef(item) => { write!(writer, "thread_local_ref{item:?}") } - Rvalue::NullaryOp(nul) => { - write!(writer, "{nul:?}() \" \"") - } Rvalue::UnaryOp(un, op) => { write!(writer, "{:?}({})", un, pretty_operand(op)) } diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs index 35af39c43a277..f0fdbe059383e 100644 --- a/compiler/rustc_public/src/mir/visit.rs +++ b/compiler/rustc_public/src/mir/visit.rs @@ -282,7 +282,6 @@ macro_rules! make_mir_visitor { self.visit_operand(op, location) } Rvalue::ThreadLocalRef(_) => {} - Rvalue::NullaryOp(_) => {} Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { self.visit_operand(op, location); } diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index 0afb94c18d7b9..b2e7a004c73d0 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1354,6 +1354,7 @@ 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. @@ -1373,6 +1374,16 @@ 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 e7a1c8218ce4e..31f41653d4a23 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -232,7 +232,6 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { ) } } - NullaryOp(null_op) => crate::mir::Rvalue::NullaryOp(null_op.stable(tables, cx)), UnaryOp(un_op, op) => { crate::mir::Rvalue::UnaryOp(un_op.stable(tables, cx), op.stable(tables, cx)) } @@ -312,21 +311,18 @@ impl<'tcx> Stable<'tcx> for mir::FakeBorrowKind { } } -impl<'tcx> Stable<'tcx> for mir::NullOp { - type T = crate::mir::NullOp; +impl<'tcx> Stable<'tcx> for mir::RuntimeChecks { + type T = crate::ty::RuntimeChecks; fn stable<'cx>( &self, _: &mut Tables<'cx, BridgeTys>, _: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - use rustc_middle::mir::NullOp::*; use rustc_middle::mir::RuntimeChecks::*; match self { - RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op { - UbChecks => crate::mir::RuntimeChecks::UbChecks, - ContractChecks => crate::mir::RuntimeChecks::ContractChecks, - OverflowChecks => crate::mir::RuntimeChecks::OverflowChecks, - }), + UbChecks => crate::ty::RuntimeChecks::UbChecks, + ContractChecks => crate::ty::RuntimeChecks::ContractChecks, + OverflowChecks => crate::ty::RuntimeChecks::OverflowChecks, } } } @@ -890,6 +886,13 @@ 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 acc3334769613..2ebd73a43e90d 100644 --- a/compiler/rustc_public/src/visitor.rs +++ b/compiler/rustc_public/src/visitor.rs @@ -68,7 +68,9 @@ 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::Param(_) | super::ty::ConstantKind::ZeroSized => {} + super::ty::ConstantKind::RuntimeChecks(_) + | super::ty::ConstantKind::Param(_) + | super::ty::ConstantKind::ZeroSized => {} } self.ty().visit(visitor) } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 514ff93c9820e..ea2cc0231ab8c 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -95,17 +95,16 @@ pub use intrinsics::ub_checks as check_library_ub; #[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn check_language_ub() -> bool { // Only used for UB checks so we may const_eval_select. - intrinsics::ub_checks() - && const_eval_select!( - @capture { } -> bool: - if const { - // Always disable UB checks. - false - } else { - // Disable UB checks in Miri. - !cfg!(miri) - } - ) + const_eval_select!( + @capture { } -> bool: + if const { + // Always disable UB checks. + false + } else { + // Disable UB checks in Miri. + !cfg!(miri) + } + ) && intrinsics::ub_checks() } /// Checks whether `ptr` is properly aligned with respect to the given alignment, and 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 c4a0acda779ce..5ec8aa71eb9c7 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 @@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; use rustc_lint::LateContext; use rustc_middle::mir::{ - Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, + Body, CastKind, NonDivergingIntrinsic, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; @@ -194,8 +194,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) - | Rvalue::ShallowInitBox(_, _) => Ok(()), + Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, cx.tcx); if ty.is_integral() || ty.is_bool() { diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs index 6998d98e498c9..ae1bdb1d58b90 100644 --- a/tests/codegen-llvm/slice-iter-len-eq-zero.rs +++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs @@ -8,8 +8,10 @@ type Demo = [u8; 3]; #[no_mangle] pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { // CHECK-NOT: sub - // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} - // CHECK: ret i1 %[[RET]] + // 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]] y.len() == 0 } @@ -31,7 +33,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 %y.1, null + // CHECK: %[[RET:.+]] = icmp eq ptr %1, null // CHECK: ret i1 %[[RET]] y.len() == 0 } diff --git a/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff index d14c42a330eb7..4714e159396e3 100644 --- a/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff +++ b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff @@ -16,7 +16,6 @@ scope 4 (inlined #[track_caller] unreachable_unchecked) { let _5: (); scope 5 (inlined core::ub_checks::check_language_ub) { - let mut _6: bool; scope 6 (inlined core::ub_checks::check_language_ub::runtime) { } } @@ -38,9 +37,7 @@ } bb2: { -- StorageLive(_6); -- _6 = const false; -- assume(copy _6); +- assume(const false); - _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + unreachable; } diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 38beb81e1ead2..ae2b8e5743031 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _11: *const (); let mut _16: usize; let mut _17: usize; - let mut _27: usize; + let mut _26: usize; scope 1 { debug vp_ctx => _1; let _5: *const (); @@ -27,7 +27,7 @@ debug _x => _8; } scope 18 (inlined foo) { - let mut _28: *const [()]; + let mut _27: *const [()]; } } scope 16 (inlined slice_from_raw_parts::<()>) { @@ -52,7 +52,7 @@ scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { scope 13 (inlined NonNull::<[u8]>::cast::) { - let mut _26: *mut [u8]; + let mut _25: *mut [u8]; scope 14 (inlined NonNull::<[u8]>::as_ptr) { } } @@ -65,9 +65,8 @@ } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _23: bool; - let _24: (); - let mut _25: std::ptr::Alignment; + let _23: (); + let mut _24: std::ptr::Alignment; } } } @@ -94,10 +93,8 @@ StorageLive(_20); StorageLive(_21); StorageLive(_22); - StorageLive(_24); StorageLive(_23); - _23 = UbChecks(); - switchInt(move _23) -> [0: bb6, otherwise: bb5]; + switchInt(const UbChecks) -> [0: bb6, otherwise: bb5]; } bb1: { @@ -117,14 +114,14 @@ bb4: { _21 = copy ((_19 as Ok).0: std::ptr::NonNull<[u8]>); -- StorageLive(_26); +- StorageLive(_25); + nop; - _26 = copy _21 as *mut [u8] (Transmute); - _12 = copy _26 as *mut u8 (PtrToPtr); -- StorageDead(_26); + _25 = copy _21 as *mut [u8] (Transmute); + _12 = copy _25 as *mut u8 (PtrToPtr); +- StorageDead(_25); + nop; StorageDead(_19); - StorageDead(_24); + StorageDead(_23); StorageDead(_22); StorageDead(_21); StorageDead(_20); @@ -132,7 +129,7 @@ StorageDead(_17); StorageDead(_16); - _13 = copy _12 as *const () (PtrToPtr); -+ _13 = copy _26 as *const () (PtrToPtr); ++ _13 = copy _25 as *const () (PtrToPtr); _14 = NonNull::<()> { pointer: copy _13 }; _15 = Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; _3 = Box::<()>(move _15, const std::alloc::Global); @@ -157,21 +154,21 @@ + nop; StorageLive(_7); _7 = copy _5; - StorageLive(_27); - _27 = const 1_usize; -- _6 = *const [()] from (copy _7, copy _27); + StorageLive(_26); + _26 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _26); + _6 = *const [()] from (copy _5, const 1_usize); - StorageDead(_27); + StorageDead(_26); StorageDead(_7); StorageLive(_8); StorageLive(_9); _9 = copy _6; - StorageLive(_28); -- _28 = copy _9; + StorageLive(_27); +- _27 = copy _9; - _8 = copy _9 as *mut () (PtrToPtr); -+ _28 = copy _6; ++ _27 = copy _6; + _8 = copy _5 as *mut () (PtrToPtr); - StorageDead(_28); + StorageDead(_27); StorageDead(_9); _0 = const (); StorageDead(_8); @@ -183,18 +180,17 @@ } bb5: { -- _24 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; -+ _24 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; +- _23 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; ++ _23 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_23); - StorageLive(_25); -- _25 = copy _17 as std::ptr::Alignment (Transmute); -- _18 = Layout { size: copy _16, align: move _25 }; -+ _25 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + StorageLive(_24); +- _24 = copy _17 as std::ptr::Alignment (Transmute); +- _18 = Layout { size: copy _16, align: move _24 }; ++ _24 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; - StorageDead(_25); + StorageDead(_24); StorageLive(_19); - _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; + _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 047579cdb5094..164aeb2d90379 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _11: *const (); let mut _16: usize; let mut _17: usize; - let mut _27: usize; + let mut _26: usize; scope 1 { debug vp_ctx => _1; let _5: *const (); @@ -27,7 +27,7 @@ debug _x => _8; } scope 18 (inlined foo) { - let mut _28: *const [()]; + let mut _27: *const [()]; } } scope 16 (inlined slice_from_raw_parts::<()>) { @@ -52,7 +52,7 @@ scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { scope 13 (inlined NonNull::<[u8]>::cast::) { - let mut _26: *mut [u8]; + let mut _25: *mut [u8]; scope 14 (inlined NonNull::<[u8]>::as_ptr) { } } @@ -65,9 +65,8 @@ } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _23: bool; - let _24: (); - let mut _25: std::ptr::Alignment; + let _23: (); + let mut _24: std::ptr::Alignment; } } } @@ -94,10 +93,8 @@ StorageLive(_20); StorageLive(_21); StorageLive(_22); - StorageLive(_24); StorageLive(_23); - _23 = UbChecks(); - switchInt(move _23) -> [0: bb6, otherwise: bb5]; + switchInt(const UbChecks) -> [0: bb6, otherwise: bb5]; } bb1: { @@ -117,14 +114,14 @@ bb4: { _21 = copy ((_19 as Ok).0: std::ptr::NonNull<[u8]>); -- StorageLive(_26); +- StorageLive(_25); + nop; - _26 = copy _21 as *mut [u8] (Transmute); - _12 = copy _26 as *mut u8 (PtrToPtr); -- StorageDead(_26); + _25 = copy _21 as *mut [u8] (Transmute); + _12 = copy _25 as *mut u8 (PtrToPtr); +- StorageDead(_25); + nop; StorageDead(_19); - StorageDead(_24); + StorageDead(_23); StorageDead(_22); StorageDead(_21); StorageDead(_20); @@ -132,7 +129,7 @@ StorageDead(_17); StorageDead(_16); - _13 = copy _12 as *const () (PtrToPtr); -+ _13 = copy _26 as *const () (PtrToPtr); ++ _13 = copy _25 as *const () (PtrToPtr); _14 = NonNull::<()> { pointer: copy _13 }; _15 = Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; _3 = Box::<()>(move _15, const std::alloc::Global); @@ -157,21 +154,21 @@ + nop; StorageLive(_7); _7 = copy _5; - StorageLive(_27); - _27 = const 1_usize; -- _6 = *const [()] from (copy _7, copy _27); + StorageLive(_26); + _26 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _26); + _6 = *const [()] from (copy _5, const 1_usize); - StorageDead(_27); + StorageDead(_26); StorageDead(_7); StorageLive(_8); StorageLive(_9); _9 = copy _6; - StorageLive(_28); -- _28 = copy _9; + StorageLive(_27); +- _27 = copy _9; - _8 = copy _9 as *mut () (PtrToPtr); -+ _28 = copy _6; ++ _27 = copy _6; + _8 = copy _5 as *mut () (PtrToPtr); - StorageDead(_28); + StorageDead(_27); StorageDead(_9); _0 = const (); StorageDead(_8); @@ -183,18 +180,17 @@ } bb5: { -- _24 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; -+ _24 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; +- _23 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; ++ _23 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_23); - StorageLive(_25); -- _25 = copy _17 as std::ptr::Alignment (Transmute); -- _18 = Layout { size: copy _16, align: move _25 }; -+ _25 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + StorageLive(_24); +- _24 = copy _17 as std::ptr::Alignment (Transmute); +- _18 = Layout { size: copy _16, align: move _24 }; ++ _24 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; - StorageDead(_25); + StorageDead(_24); StorageLive(_19); - _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; + _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index 813796657b247..153e314fb6f47 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShlUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index 61fdb69f74b70..fd9f5838efc33 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShlUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff index 5ea99e8301b80..5b12c1853359d 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShrUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff index b13531ab148f2..e8474898b9951 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShrUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index 0119dd799704d..7bd93b804e7f3 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -12,7 +12,6 @@ + scope 3 (inlined #[track_caller] unreachable_unchecked) { + let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { -+ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -34,9 +33,7 @@ + } + + bb2: { -+ StorageLive(_5); -+ _5 = UbChecks(); -+ assume(copy _5); ++ assume(const UbChecks); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index d6a5eab1d6e93..ae194db56cc9b 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -12,7 +12,6 @@ + scope 3 (inlined #[track_caller] unreachable_unchecked) { + let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { -+ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -38,9 +37,7 @@ - bb2 (cleanup): { - resume; + bb2: { -+ StorageLive(_5); -+ _5 = UbChecks(); -+ assume(copy _5); ++ assume(const UbChecks); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + diff --git a/tests/mir-opt/instsimplify/ub_check.rs b/tests/mir-opt/instsimplify/ub_check.rs index b513f60dc7b94..db890c1840798 100644 --- a/tests/mir-opt/instsimplify/ub_check.rs +++ b/tests/mir-opt/instsimplify/ub_check.rs @@ -5,8 +5,7 @@ pub fn unwrap_unchecked(x: Option) -> i32 { // CHECK-LABEL: fn unwrap_unchecked( // CHECK-NOT: UbChecks() - // CHECK: [[assume:_.*]] = const false; - // CHECK-NEXT: assume(copy [[assume]]); + // CHECK: assume(const false); // CHECK-NEXT: unreachable_unchecked::precondition_check unsafe { x.unwrap_unchecked() } } diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff index 2c9071e6e2079..890c878804416 100644 --- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff +++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff @@ -12,7 +12,6 @@ scope 3 (inlined #[track_caller] unreachable_unchecked) { let _4: (); scope 4 (inlined core::ub_checks::check_language_ub) { - let mut _5: bool; scope 5 (inlined core::ub_checks::check_language_ub::runtime) { } } @@ -33,10 +32,8 @@ } bb2: { - StorageLive(_5); -- _5 = UbChecks(); -+ _5 = const false; - assume(copy _5); +- assume(const UbChecks); ++ assume(const false); _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; }