diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a57689a45b67b..80dafbe4268a6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1563,7 +1563,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 d1d0bff8fe06b..f8d80375f6416 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1046,8 +1046,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - &Rvalue::NullaryOp(NullOp::ContractChecks, _) => {} - &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} + &Rvalue::NullaryOp(NullOp::ContractChecks | NullOp::UbChecks) => {} Rvalue::ShallowInitBox(_operand, ty) => { let trait_ref = @@ -1634,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 7d50548b40262..91b10b0fdd57b 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -829,40 +829,15 @@ 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::UbChecks => { - let val = fx.tcx.sess.ub_checks(); - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - return; - } - NullOp::ContractChecks => { - let val = fx.tcx.sess.contract_checks(); - 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::UbChecks => fx.tcx.sess.ub_checks(), + NullOp::ContractChecks => fx.tcx.sess.contract_checks(), }; 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 640f7211dc994..9cfbd7909cc2b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -607,17 +607,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::UbChecks => { let val = bx.tcx().sess.ub_checks(); 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 ca173fe26c2f6..203fedc468002 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -645,10 +645,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp( - NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, - _, - ) => {} + Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(op, operand) => { @@ -856,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 f0f06d469c1e6..e05fa13d6823a 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}; @@ -174,6 +174,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 58b90abf01295..dc23c4d0934e8 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()) - } UbChecks => ImmTy::from_bool(M::ub_checks(self)?, *self.tcx), ContractChecks => ImmTy::from_bool(M::contract_checks(self)?, *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 9f7f4c7583412..d8679c84f9d4c 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 a6659912e3fb9..42d5f86d7ad85 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::powf16 | sym::powf32 | sym::powf64 @@ -287,6 +288,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 2605aa18b91ee..091d726d80e25 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3837,10 +3837,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() { @@ -3928,7 +3926,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; @@ -3963,7 +3961,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; @@ -3984,7 +3982,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; @@ -3999,10 +3997,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 697029e55f7cb..65fc4f706d378 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -775,12 +775,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 533ab67053095..eef2fc0113aad 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 fab04df500a5c..e2a20ac7dec45 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::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)), + Rvalue::NullaryOp(NullOp::UbChecks) => Some((tcx.sess.ub_checks() 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 17d8eeee68bfd..d48fccaea6cfd 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1089,14 +1089,10 @@ 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::UbChecks => write!(fmt, "UbChecks()"), - NullOp::ContractChecks => write!(fmt, "ContractChecks()"), - } - } + NullaryOp(ref op) => match op { + NullOp::UbChecks => write!(fmt, "UbChecks()"), + NullOp::ContractChecks => write!(fmt, "ContractChecks()"), + }, 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 3cbb4b70b062a..ddc45011cdad7 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,9 +794,9 @@ 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::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => tcx.types.bool, + Rvalue::NullaryOp(NullOp::ContractChecks) | Rvalue::NullaryOp(NullOp::UbChecks) => { + 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 => { @@ -860,10 +860,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::UbChecks | NullOp::ContractChecks => tcx.types.bool, } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 9d99239546ae2..c9aafc2fdba89 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 UB-checking at runtime. /// See the `ub_checks` intrinsic docs for details. UbChecks, 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 1a3eb09491161..3b43ceb3c5ae9 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -950,7 +950,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>>, @@ -988,7 +987,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), @@ -2827,7 +2825,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>)), @@ -3230,14 +3227,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 eefb913a33fa4..71ba8195c00ce 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1383,37 +1383,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 d1fb700913d91..d093f0597070c 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -226,7 +226,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> { @@ -559,15 +559,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 5e7a57d51a9ca..d13d56ff95071 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -583,7 +583,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 195d45c2c4c49..3025f589af156 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 0b9bc018a09b3..237148284ad77 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: @@ -819,11 +825,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) => { @@ -1094,12 +1137,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 3929a97eed8f2..3c182b393cacc 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 dd65f0699e97e..5fc99833f1aed 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -451,10 +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::UbChecks | NullOp::ContractChecks, - _, - ) => {} + | Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks) => {} } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 8bcda77f4bc32..f76c0247d85ce 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -461,19 +461,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 - .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::UbChecks | NullOp::ContractChecks) => { + 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 8eae80e235ccd..d89249b18af2b 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,18 +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::UbChecks => return None, - NullOp::ContractChecks => return None, - }; - ImmTy::from_uint(val, ty).into() - } + NullaryOp(NullOp::UbChecks | NullOp::ContractChecks) => return None, UnaryOp(un_op, operand) => { let operand = self.eval_to_const(operand)?; let operand = self.ecx.read_immediate(operand).discard_err()?; @@ -1032,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 932744e4fa25c..b84823c9b79a4 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -169,7 +169,7 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { - let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue else { return }; + let Rvalue::NullaryOp(NullOp::UbChecks) = *rvalue else { return }; let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 131e3943689b8..6fb20c4266067 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -605,18 +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::UbChecks => return None, - NullOp::ContractChecks => return None, - }; - ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() - } + NullaryOp(NullOp::UbChecks | NullOp::ContractChecks) => 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 ad7c52064a8ef..2f55a349e3672 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -29,7 +29,7 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::NullaryOp(NullOp::UbChecks, tcx.types.bool), + Rvalue::NullaryOp(NullOp::UbChecks), ))), )); 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 9204c221515c9..c0407f3af0c65 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -449,11 +449,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(operand)?; } - Rvalue::NullaryOp(op, _) => match op { - NullOp::OffsetOf(_) => {} - NullOp::UbChecks => {} - NullOp::ContractChecks => {} - }, + Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks) => {} Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 5a9018a62c574..69df784b85b62 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1432,53 +1432,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::UbChecks | NullOp::ContractChecks, _) + | Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks) | Rvalue::Discriminant(_) => {} Rvalue::WrapUnsafeBinder(op, ty) => { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 877b5ad93bfca..6b678415b675d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -289,31 +289,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 1a939cbe8dba2..1955e77a5e473 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,9 +641,9 @@ 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::ContractChecks, _) - | Rvalue::NullaryOp(NullOp::UbChecks, _) => Ok(Ty::bool_ty()), + Rvalue::NullaryOp(NullOp::ContractChecks) | Rvalue::NullaryOp(NullOp::UbChecks) => { + 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( @@ -1022,8 +1022,6 @@ pub enum CastKind { #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] pub enum NullOp { - /// Returns the offset of a field. - OffsetOf(Vec<(VariantIdx, FieldIdx)>), /// cfg!(ub_checks), but at codegen time UbChecks, /// cfg!(contract_checks), but at codegen time 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 f850bc5f89b8a..96743070ae3c0 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,18 +312,15 @@ 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::*; match self { - OffsetOf(indices) => crate::mir::NullOp::OffsetOf( - indices.iter().map(|idx| idx.stable(tables, cx)).collect(), - ), UbChecks => crate::mir::NullOp::UbChecks, ContractChecks => crate::mir::NullOp::ContractChecks, } 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 c2da8a1a92096..ecddc7e947282 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2759,6 +2759,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 90ea2616890a4..822b5742f4d1e 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -194,7 +194,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::OffsetOf(_) | NullOp::UbChecks | NullOp::ContractChecks, _) + Rvalue::NullaryOp(NullOp::UbChecks | NullOp::ContractChecks) | 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 27cba6560300a..506a0b8416a1c 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -346,7 +346,7 @@ mod expressions { - { offset_of!(T, field) }; + const { offset_of!(T, field) }; } /// ExprKind::MacCall fn expr_mac_call() { "..."; "..."; "..."; }