From e936416a8d3cfb501504f00d7250d5b595fed244 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 15 Aug 2023 20:10:45 +0100 Subject: [PATCH 1/4] Support enum variants in offset_of! --- compiler/rustc_abi/src/lib.rs | 33 ++++++++++ compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../rustc_const_eval/src/interpret/step.rs | 2 +- .../src/transform/validate.rs | 33 ++++++---- compiler/rustc_error_codes/src/error_codes.rs | 1 + .../src/error_codes/E0795.md | 28 +++++++++ compiler/rustc_hir_typeck/src/expr.rs | 60 +++++++++++++++++-- compiler/rustc_middle/src/mir/syntax.rs | 4 +- compiler/rustc_middle/src/thir.rs | 5 +- compiler/rustc_middle/src/ty/codec.rs | 12 +++- compiler/rustc_middle/src/ty/context.rs | 13 +++- .../rustc_middle/src/ty/typeck_results.rs | 10 ++-- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- .../src/dataflow_const_prop.rs | 2 +- compiler/rustc_passes/src/dead.rs | 29 ++++++--- compiler/rustc_smir/src/rustc_smir/mod.rs | 12 +++- compiler/rustc_target/src/abi/mod.rs | 24 +++++--- ...set_of.concrete.ConstProp.panic-abort.diff | 56 +++++++++++++++-- ...et_of.concrete.ConstProp.panic-unwind.diff | 56 +++++++++++++++-- ...fset_of.generic.ConstProp.panic-abort.diff | 50 ++++++++++++++-- ...set_of.generic.ConstProp.panic-unwind.diff | 50 ++++++++++++++-- tests/mir-opt/const_prop/offset_of.rs | 17 ++++++ tests/ui/offset-of/offset-of-enum.rs | 3 +- tests/ui/offset-of/offset-of-enum.stderr | 8 +-- tests/ui/offset-of/offset-of-private.rs | 11 ++++ tests/ui/offset-of/offset-of-private.stderr | 22 ++++--- 27 files changed, 472 insertions(+), 75 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0795.md diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 8e7aa59ee341e..0654bfd11c5e5 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1107,6 +1107,39 @@ impl Scalar { } // NOTE: This struct is generic over the FieldIdx for rust-analyzer usage. +rustc_index::newtype_index! { + /// The *source-order* index of a field in a variant. + /// + /// This is how most code after type checking refers to fields, rather than + /// using names (as names have hygiene complications and more complex lookup). + /// + /// Particularly for `repr(Rust)` types, this may not be the same as *layout* order. + /// (It is for `repr(C)` `struct`s, however.) + /// + /// For example, in the following types, + /// ```rust + /// # enum Never {} + /// # #[repr(u16)] + /// enum Demo1 { + /// Variant0 { a: Never, b: i32 } = 100, + /// Variant1 { c: u8, d: u64 } = 10, + /// } + /// struct Demo2 { e: u8, f: u16, g: u8 } + /// ``` + /// `b` is `FieldIdx(1)` in `VariantIdx(0)`, + /// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and + /// `f` is `FieldIdx(1)` in `VariantIdx(0)`. + #[derive(HashStable_Generic)] + pub struct FieldIdx {} +} + +/// `offset_of` can traverse fields and enum variants and should keep track of which is which. +#[derive(Copy, Clone, Debug, Eq, Hash, HashStable_Generic, PartialEq, Encodable, Decodable)] +pub enum OffsetOfIdx { + Field(FieldIdx), + Variant(VariantIdx), +} + /// Describes how the fields of a type are located in memory. #[derive(PartialEq, Eq, Hash, Clone, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 80e7c5bd9edbc..91b1547cb6ea6 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -766,7 +766,7 @@ fn codegen_stmt<'tcx>( NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(fx, fields.iter().map(|f| f.index())).bytes() + layout.offset_of_subfield(fx, fields.iter()).bytes() } }; let val = CValue::by_val( diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index f591afaaaf427..b0f757898e326 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -680,7 +680,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { layout.align.abi.bytes() } mir::NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(bx.cx(), fields.iter().map(|f| f.index())).bytes() + layout.offset_of_subfield(bx.cx(), fields.iter()).bytes() } }; let val = bx.cx().const_usize(val); diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 8c34d05042b1d..b6993d939c585 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -275,7 +275,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), mir::NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(self, fields.iter().map(|f| f.index())).bytes() + layout.offset_of_subfield(self, fields.iter()).bytes() } }; self.write_scalar(Scalar::from_target_usize(val, self), &dest)?; diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b70a342aa15e6..bdccd9b0edb53 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1056,16 +1056,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } - Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => { + 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; + let mut indices = indices.into_iter(); - for field in fields.iter() { - match current_ty.kind() { - ty::Tuple(fields) => { + use rustc_target::abi::OffsetOfIdx::*; + + while let Some(index) = indices.next() { + match (current_ty.kind(), index) { + (ty::Tuple(fields), Field(field)) => { let Some(&f_ty) = fields.get(field.as_usize()) else { fail_out_of_bounds(self, location, field, current_ty); return; @@ -1073,16 +1076,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); } - ty::Adt(adt_def, args) => { - if adt_def.is_enum() { + (ty::Adt(adt_def, args), Field(field)) if !adt_def.is_enum() => { + let Some(field) = adt_def.non_enum_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.param_env, f_ty); + } + (ty::Adt(adt_def, args), Variant(variant)) if adt_def.is_enum() => { + let Some(Field(field)) = indices.next() else { self.fail( location, - format!("Cannot get field offset from enum {current_ty:?}"), + format!("enum variant must be followed by field index in offset_of; in {current_ty:?}"), ); return; - } - - let Some(field) = adt_def.non_enum_variant().fields.get(field) else { + }; + let Some(field) = adt_def.variant(variant).fields.get(field) else { fail_out_of_bounds(self, location, field, current_ty); return; }; @@ -1093,7 +1104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { _ => { self.fail( location, - format!("Cannot get field offset from non-adt type {current_ty:?}"), + format!("Cannot get offset {index:?} from type {current_ty:?}"), ); return; } diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 89c44c6ec8a90..6680e8875c3e3 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -514,6 +514,7 @@ E0791: include_str!("./error_codes/E0791.md"), E0792: include_str!("./error_codes/E0792.md"), E0793: include_str!("./error_codes/E0793.md"), E0794: include_str!("./error_codes/E0794.md"), +E0795: include_str!("./error_codes/E0795.md"), } // Undocumented removed error codes. Note that many removed error codes are kept in the list above diff --git a/compiler/rustc_error_codes/src/error_codes/E0795.md b/compiler/rustc_error_codes/src/error_codes/E0795.md new file mode 100644 index 0000000000000..8b4b2dc87fd71 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0795.md @@ -0,0 +1,28 @@ +Invalid argument for the `offset_of!` macro. + +Erroneous code example: + +```compile_fail,E0795 +#![feature(offset_of)] + +let x = std::mem::offset_of!(Option, Some); +``` + +The `offset_of!` macro gives the offset of a field within a type. It can +navigate through enum variants, but the final component of its second argument +must be a field and not a variant. + +The offset of the contained `u8` in the `Option` can be found by specifying +the field name `0`: + +``` +#![feature(offset_of)] + +let x: usize = std::mem::offset_of!(Option, Some.0); +``` + +The discriminant of an enumeration may be read with `core::mem::discriminant`, +but this is not always a value physically present within the enum. + +Further information about enum layout may be found at +https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html. diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index b1d6e4f0523b6..394a9033765ac 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3103,16 +3103,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &[Ident], expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { + use rustc_target::abi::OffsetOfIdx::*; + let container = self.to_ty(container).normalized; let mut field_indices = Vec::with_capacity(fields.len()); let mut current_container = container; + let mut fields = fields.into_iter(); - for &field in fields { + while let Some(&field) = fields.next() { let container = self.structurally_resolve_type(expr.span, current_container); match container.kind() { - ty::Adt(container_def, args) if !container_def.is_enum() => { + ty::Adt(container_def, args) if container_def.is_enum() => { + let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let (ident, _def_scope) = + self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); + + if let Some((index, variant)) = container_def.variants() + .iter_enumerated() + .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) + { + let Some(&subfield) = fields.next() else { + let mut err = type_error_struct!( + self.tcx().sess, + ident.span, + container, + E0795, + "`{ident}` is an enum variant; expected field at end of `offset_of`", + ); + err.span_label(field.span, "enum variant"); + err.emit(); + break; + }; + let (subident, sub_def_scope) = + self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block); + + if let Some((subindex, field)) = variant.fields + .iter_enumerated() + .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) + { + let field_ty = self.field_ty(expr.span, field, args); + + // FIXME: DSTs with static alignment should be allowed + self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation); + + if field.vis.is_accessible_from(sub_def_scope, self.tcx) { + self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); + } else { + self.private_field_err(ident, container_def.did()).emit(); + } + + // Save the index of all fields regardless of their visibility in case + // of error recovery. + field_indices.push(Variant(index)); + field_indices.push(Field(subindex)); + current_container = field_ty; + + continue; + } + } + } + ty::Adt(container_def, args) => { let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); @@ -3135,7 +3187,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); + field_indices.push(Field(index)); current_container = field_ty; continue; @@ -3149,7 +3201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(ty, expr.span, traits::MiscObligation); } if let Some(&field_ty) = tys.get(index) { - field_indices.push(index.into()); + field_indices.push(Field(index.into())); current_container = field_ty; continue; diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index b89c7bc512e1e..d0094a81634de 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -17,7 +17,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{self as hir}; use rustc_hir::{self, CoroutineKind}; use rustc_index::IndexVec; -use rustc_target::abi::{FieldIdx, VariantIdx}; +use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx}; use rustc_ast::Mutability; use rustc_span::def_id::LocalDefId; @@ -1354,7 +1354,7 @@ pub enum NullOp<'tcx> { /// Returns the minimum alignment of a type AlignOf, /// Returns the offset of a field - OffsetOf(&'tcx List), + OffsetOf(&'tcx List), } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index f1747356139dc..2ee726c76bf0c 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -25,7 +25,8 @@ use rustc_middle::ty::{ }; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, VariantIdx}; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; @@ -490,7 +491,7 @@ pub enum ExprKind<'tcx> { /// Field offset (`offset_of!`) OffsetOf { container: Ty<'tcx>, - fields: &'tcx List, + fields: &'tcx List, }, /// An expression taking a reference to a thread local. ThreadLocalRef(DefId), diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index d52a717b6b09b..ce5198ee3baf8 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; use rustc_serialize::{Decodable, Encodable}; use rustc_span::Span; -use rustc_target::abi::FieldIdx; +use rustc_target::abi::{FieldIdx, OffsetOfIdx}; pub use rustc_type_ir::{TyDecoder, TyEncoder}; use std::hash::Hash; use std::intrinsics; @@ -414,6 +414,15 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List>> RefDecodable<'tcx, D> for ty::List { + fn decode(decoder: &mut D) -> &'tcx Self { + let len = decoder.read_usize(); + decoder + .interner() + .mk_offset_of_from_iter((0..len).map::(|_| Decodable::decode(decoder))) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, @@ -426,6 +435,7 @@ impl_decodable_via_ref! { &'tcx ty::List, &'tcx ty::List>, &'tcx ty::List, + &'tcx ty::List, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0b3b6700cec1b..c89ae1e661ed6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -63,7 +63,7 @@ use rustc_session::{Limit, MetadataKind, Session}; use rustc_span::def_id::{DefPathHash, StableCrateId}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; +use rustc_target::abi::{FieldIdx, Layout, LayoutS, OffsetOfIdx, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; @@ -163,6 +163,7 @@ pub struct CtxtInterners<'tcx> { predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, + offset_of: InternedSet<'tcx, List>, } impl<'tcx> CtxtInterners<'tcx> { @@ -189,6 +190,7 @@ impl<'tcx> CtxtInterners<'tcx> { predefined_opaques_in_body: Default::default(), fields: Default::default(), local_def_ids: Default::default(), + offset_of: Default::default(), } } @@ -1587,6 +1589,7 @@ slice_interners!( bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), fields: pub mk_fields(FieldIdx), local_def_ids: intern_local_def_ids(LocalDefId), + offset_of: pub mk_offset_of(OffsetOfIdx), ); impl<'tcx> TyCtxt<'tcx> { @@ -1914,6 +1917,14 @@ 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>, + { + 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/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 58ad1eb900fd5..623d8d61d2d5f 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -24,7 +24,7 @@ use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; -use rustc_target::abi::FieldIdx; +use rustc_target::abi::{FieldIdx, OffsetOfIdx}; use std::{collections::hash_map::Entry, hash::Hash, iter}; use super::RvalueScopes; @@ -205,7 +205,7 @@ pub struct TypeckResults<'tcx> { pub closure_size_eval: LocalDefIdMap>, /// Container types and field indices of `offset_of!` expressions - offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec)>, + offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec)>, } impl<'tcx> TypeckResults<'tcx> { @@ -464,11 +464,13 @@ impl<'tcx> TypeckResults<'tcx> { &self.coercion_casts } - pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec)> { + pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec)> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data } } - pub fn offset_of_data_mut(&mut self) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec)> { + pub fn offset_of_data_mut( + &mut self, + ) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec)> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 6c3564a20f6bf..dfd39b512e241 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -670,7 +670,7 @@ impl<'tcx> Cx<'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_fields_from_iter(indices.iter().copied()); + let fields = tcx.mk_offset_of_from_iter(indices.iter().copied()); ExprKind::OffsetOf { container, fields } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index fd067cb234bdb..ca10dc48eb805 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -287,7 +287,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), NullOp::OffsetOf(fields) => layout - .offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index())) + .offset_of_subfield(&self.ecx, fields.iter()) .bytes(), _ => return ValueOrPlace::Value(FlatSet::Top), }; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 87d4850b475bd..3b4f6a618c8b6 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -248,6 +248,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) { + use rustc_target::abi::OffsetOfIdx::*; + 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"); @@ -256,11 +258,23 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { let param_env = self.tcx.param_env(body_did); let mut current_ty = container; + let mut indices = indices.into_iter(); + + while let Some(&index) = indices.next() { + match (current_ty.kind(), index) { + (ty::Adt(def, subst), Field(field)) if !def.is_enum() => { + let field = &def.non_enum_variant().fields[field]; - for &index in indices { - match current_ty.kind() { - ty::Adt(def, subst) => { - let field = &def.non_enum_variant().fields[index]; + self.insert_def_id(field.did); + let field_ty = field.ty(self.tcx, subst); + + current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty); + } + (ty::Adt(def, subst), Variant(variant)) if def.is_enum() => { + let Some(&Field(field)) = indices.next() else { + span_bug!(expr.span, "variant must be followed by field in offset_of") + }; + let field = &def.variant(variant).fields[field]; self.insert_def_id(field.did); let field_ty = field.ty(self.tcx, subst); @@ -269,11 +283,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } // we don't need to mark tuple fields as live, // but we may need to mark subfields - ty::Tuple(tys) => { + (ty::Tuple(tys), Field(field)) => { current_ty = - self.tcx.normalize_erasing_regions(param_env, tys[index.as_usize()]); + self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]); } - _ => span_bug!(expr.span, "named field access on non-ADT"), + (_, Field(_)) => span_bug!(expr.span, "named field access on non-ADT"), + (_, Variant(_)) => span_bug!(expr.span, "enum variant access on non-enum"), } } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 5ab5a048ffafa..e64afa5f8d930 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::interpret::{alloc_range, AllocId}; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_target::abi::FieldIdx; +use rustc_target::abi::{FieldIdx, OffsetOfIdx}; use stable_mir::mir::mono::InstanceDef; use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx}; use stable_mir::ty::{ @@ -643,6 +643,16 @@ impl<'tcx> Stable<'tcx> for FieldIdx { } } +impl<'tcx> Stable<'tcx> for OffsetOfIdx { + type T = usize; + fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { + match self { + OffsetOfIdx::Field(f) => f.as_usize(), + OffsetOfIdx::Variant(v) => v.as_usize(), + } + } +} + impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> { type T = stable_mir::mir::Operand; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index f6f8b53d130b5..a37a5bb26893f 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -250,7 +250,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } - pub fn offset_of_subfield(self, cx: &C, indices: impl Iterator) -> Size + pub fn offset_of_subfield(self, cx: &C, indices: impl Iterator) -> Size where Ty: TyAbiInterface<'a, C>, { @@ -258,13 +258,21 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { let mut offset = Size::ZERO; for index in indices { - offset += layout.fields.offset(index); - layout = layout.field(cx, index); - assert!( - layout.is_sized(), - "offset of unsized field (type {:?}) cannot be computed statically", - layout.ty - ); + match index { + OffsetOfIdx::Field(field) => { + let index = field.index(); + offset += layout.fields.offset(index); + layout = layout.field(cx, index); + assert!( + layout.is_sized(), + "offset of unsized field (type {:?}) cannot be computed statically", + layout.ty + ); + } + OffsetOfIdx::Variant(variant) => { + layout = layout.for_variant(cx, variant); + } + } } offset diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff index c73d217aeec4e..e460c08f9bb8d 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff @@ -8,6 +8,9 @@ let mut _4: usize; let mut _6: usize; let mut _8: usize; + let mut _10: usize; + let mut _12: usize; + let mut _14: usize; scope 1 { debug x => _1; let _3: usize; @@ -19,6 +22,18 @@ let _7: usize; scope 4 { debug z1 => _7; + let _9: usize; + scope 5 { + debug eA0 => _9; + let _11: usize; + scope 6 { + debug eA1 => _11; + let _13: usize; + scope 7 { + debug eC => _13; + } + } + } } } } @@ -27,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); -- _2 = OffsetOf(Alpha, [0]); +- _2 = OffsetOf(Alpha, [Field(0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; + _2 = const 4_usize; + _1 = must_use::(const 4_usize) -> [return: bb1, unwind unreachable]; @@ -37,7 +52,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); -- _4 = OffsetOf(Alpha, [1]); +- _4 = OffsetOf(Alpha, [Field(1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; + _4 = const 0_usize; + _3 = must_use::(const 0_usize) -> [return: bb2, unwind unreachable]; @@ -47,7 +62,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Alpha, [2, 0]); +- _6 = OffsetOf(Alpha, [Field(2), Field(0)]); - _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; + _6 = const 2_usize; + _5 = must_use::(const 2_usize) -> [return: bb3, unwind unreachable]; @@ -57,7 +72,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Alpha, [2, 1]); +- _8 = OffsetOf(Alpha, [Field(2), Field(1)]); - _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; + _8 = const 3_usize; + _7 = must_use::(const 3_usize) -> [return: bb4, unwind unreachable]; @@ -65,7 +80,40 @@ bb4: { StorageDead(_8); + StorageLive(_9); + StorageLive(_10); +- _10 = OffsetOf(Epsilon, [Variant(0), Field(0)]); +- _9 = must_use::(move _10) -> [return: bb5, unwind unreachable]; ++ _10 = const 1_usize; ++ _9 = must_use::(const 1_usize) -> [return: bb5, unwind unreachable]; + } + + bb5: { + StorageDead(_10); + StorageLive(_11); + StorageLive(_12); +- _12 = OffsetOf(Epsilon, [Variant(0), Field(1)]); +- _11 = must_use::(move _12) -> [return: bb6, unwind unreachable]; ++ _12 = const 2_usize; ++ _11 = must_use::(const 2_usize) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_12); + StorageLive(_13); + StorageLive(_14); +- _14 = OffsetOf(Epsilon, [Variant(2), Field(0)]); +- _13 = must_use::(move _14) -> [return: bb7, unwind unreachable]; ++ _14 = const 4_usize; ++ _13 = must_use::(const 4_usize) -> [return: bb7, unwind unreachable]; + } + + bb7: { + StorageDead(_14); _0 = const (); + StorageDead(_13); + StorageDead(_11); + StorageDead(_9); StorageDead(_7); StorageDead(_5); StorageDead(_3); diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff index 913ffca4ae904..3b8d0d75101f4 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff @@ -8,6 +8,9 @@ let mut _4: usize; let mut _6: usize; let mut _8: usize; + let mut _10: usize; + let mut _12: usize; + let mut _14: usize; scope 1 { debug x => _1; let _3: usize; @@ -19,6 +22,18 @@ let _7: usize; scope 4 { debug z1 => _7; + let _9: usize; + scope 5 { + debug eA0 => _9; + let _11: usize; + scope 6 { + debug eA1 => _11; + let _13: usize; + scope 7 { + debug eC => _13; + } + } + } } } } @@ -27,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); -- _2 = OffsetOf(Alpha, [0]); +- _2 = OffsetOf(Alpha, [Field(0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind continue]; + _2 = const 4_usize; + _1 = must_use::(const 4_usize) -> [return: bb1, unwind continue]; @@ -37,7 +52,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); -- _4 = OffsetOf(Alpha, [1]); +- _4 = OffsetOf(Alpha, [Field(1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind continue]; + _4 = const 0_usize; + _3 = must_use::(const 0_usize) -> [return: bb2, unwind continue]; @@ -47,7 +62,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Alpha, [2, 0]); +- _6 = OffsetOf(Alpha, [Field(2), Field(0)]); - _5 = must_use::(move _6) -> [return: bb3, unwind continue]; + _6 = const 2_usize; + _5 = must_use::(const 2_usize) -> [return: bb3, unwind continue]; @@ -57,7 +72,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Alpha, [2, 1]); +- _8 = OffsetOf(Alpha, [Field(2), Field(1)]); - _7 = must_use::(move _8) -> [return: bb4, unwind continue]; + _8 = const 3_usize; + _7 = must_use::(const 3_usize) -> [return: bb4, unwind continue]; @@ -65,7 +80,40 @@ bb4: { StorageDead(_8); + StorageLive(_9); + StorageLive(_10); +- _10 = OffsetOf(Epsilon, [Variant(0), Field(0)]); +- _9 = must_use::(move _10) -> [return: bb5, unwind continue]; ++ _10 = const 1_usize; ++ _9 = must_use::(const 1_usize) -> [return: bb5, unwind continue]; + } + + bb5: { + StorageDead(_10); + StorageLive(_11); + StorageLive(_12); +- _12 = OffsetOf(Epsilon, [Variant(0), Field(1)]); +- _11 = must_use::(move _12) -> [return: bb6, unwind continue]; ++ _12 = const 2_usize; ++ _11 = must_use::(const 2_usize) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_12); + StorageLive(_13); + StorageLive(_14); +- _14 = OffsetOf(Epsilon, [Variant(2), Field(0)]); +- _13 = must_use::(move _14) -> [return: bb7, unwind continue]; ++ _14 = const 4_usize; ++ _13 = must_use::(const 4_usize) -> [return: bb7, unwind continue]; + } + + bb7: { + StorageDead(_14); _0 = const (); + StorageDead(_13); + StorageDead(_11); + StorageDead(_9); StorageDead(_7); StorageDead(_5); StorageDead(_3); diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff index 7519331f6d7d4..f26b104e065d7 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff @@ -8,6 +8,9 @@ let mut _4: usize; let mut _6: usize; let mut _8: usize; + let mut _10: usize; + let mut _12: usize; + let mut _14: usize; scope 1 { debug gx => _1; let _3: usize; @@ -19,6 +22,18 @@ let _7: usize; scope 4 { debug dy => _7; + let _9: usize; + scope 5 { + debug zA0 => _9; + let _11: usize; + scope 6 { + debug zA1 => _11; + let _13: usize; + scope 7 { + debug zB => _13; + } + } + } } } } @@ -27,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = OffsetOf(Gamma, [0]); + _2 = OffsetOf(Gamma, [Field(0)]); _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; } @@ -35,7 +50,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); - _4 = OffsetOf(Gamma, [1]); + _4 = OffsetOf(Gamma, [Field(1)]); _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; } @@ -43,7 +58,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); - _6 = OffsetOf(Delta, [1]); + _6 = OffsetOf(Delta, [Field(1)]); _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; } @@ -51,13 +66,40 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); - _8 = OffsetOf(Delta, [2]); + _8 = OffsetOf(Delta, [Field(2)]); _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; } bb4: { StorageDead(_8); + StorageLive(_9); + StorageLive(_10); + _10 = OffsetOf(Zeta, [Variant(0), Field(0)]); + _9 = must_use::(move _10) -> [return: bb5, unwind unreachable]; + } + + bb5: { + StorageDead(_10); + StorageLive(_11); + StorageLive(_12); + _12 = OffsetOf(Zeta, [Variant(0), Field(1)]); + _11 = must_use::(move _12) -> [return: bb6, unwind unreachable]; + } + + bb6: { + StorageDead(_12); + StorageLive(_13); + StorageLive(_14); + _14 = OffsetOf(Zeta, [Variant(1), Field(0)]); + _13 = must_use::(move _14) -> [return: bb7, unwind unreachable]; + } + + bb7: { + StorageDead(_14); _0 = const (); + StorageDead(_13); + StorageDead(_11); + StorageDead(_9); StorageDead(_7); StorageDead(_5); StorageDead(_3); diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff index fd5206e460c6d..0f8750fce460c 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff @@ -8,6 +8,9 @@ let mut _4: usize; let mut _6: usize; let mut _8: usize; + let mut _10: usize; + let mut _12: usize; + let mut _14: usize; scope 1 { debug gx => _1; let _3: usize; @@ -19,6 +22,18 @@ let _7: usize; scope 4 { debug dy => _7; + let _9: usize; + scope 5 { + debug zA0 => _9; + let _11: usize; + scope 6 { + debug zA1 => _11; + let _13: usize; + scope 7 { + debug zB => _13; + } + } + } } } } @@ -27,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = OffsetOf(Gamma, [0]); + _2 = OffsetOf(Gamma, [Field(0)]); _1 = must_use::(move _2) -> [return: bb1, unwind continue]; } @@ -35,7 +50,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); - _4 = OffsetOf(Gamma, [1]); + _4 = OffsetOf(Gamma, [Field(1)]); _3 = must_use::(move _4) -> [return: bb2, unwind continue]; } @@ -43,7 +58,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); - _6 = OffsetOf(Delta, [1]); + _6 = OffsetOf(Delta, [Field(1)]); _5 = must_use::(move _6) -> [return: bb3, unwind continue]; } @@ -51,13 +66,40 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); - _8 = OffsetOf(Delta, [2]); + _8 = OffsetOf(Delta, [Field(2)]); _7 = must_use::(move _8) -> [return: bb4, unwind continue]; } bb4: { StorageDead(_8); + StorageLive(_9); + StorageLive(_10); + _10 = OffsetOf(Zeta, [Variant(0), Field(0)]); + _9 = must_use::(move _10) -> [return: bb5, unwind continue]; + } + + bb5: { + StorageDead(_10); + StorageLive(_11); + StorageLive(_12); + _12 = OffsetOf(Zeta, [Variant(0), Field(1)]); + _11 = must_use::(move _12) -> [return: bb6, unwind continue]; + } + + bb6: { + StorageDead(_12); + StorageLive(_13); + StorageLive(_14); + _14 = OffsetOf(Zeta, [Variant(1), Field(0)]); + _13 = must_use::(move _14) -> [return: bb7, unwind continue]; + } + + bb7: { + StorageDead(_14); _0 = const (); + StorageDead(_13); + StorageDead(_11); + StorageDead(_9); StorageDead(_7); StorageDead(_5); StorageDead(_3); diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs index 21911f8dbb5de..8a5289d589914 100644 --- a/tests/mir-opt/const_prop/offset_of.rs +++ b/tests/mir-opt/const_prop/offset_of.rs @@ -28,12 +28,26 @@ struct Delta { y: u16, } +enum Epsilon { + A(u8, u16), + B, + C { c: u32 } +} + +enum Zeta { + A(T, bool), + B(char), +} + // EMIT_MIR offset_of.concrete.ConstProp.diff fn concrete() { let x = offset_of!(Alpha, x); let y = offset_of!(Alpha, y); let z0 = offset_of!(Alpha, z.0); let z1 = offset_of!(Alpha, z.1); + let eA0 = offset_of!(Epsilon, A.0); + let eA1 = offset_of!(Epsilon, A.1); + let eC = offset_of!(Epsilon, C.c); } // EMIT_MIR offset_of.generic.ConstProp.diff @@ -42,6 +56,9 @@ fn generic() { let gy = offset_of!(Gamma, y); let dx = offset_of!(Delta, x); let dy = offset_of!(Delta, y); + let zA0 = offset_of!(Zeta, A.0); + let zA1 = offset_of!(Zeta, A.1); + let zB = offset_of!(Zeta, B.0); } fn main() { diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs index d73505821ff53..92d34e67c71b2 100644 --- a/tests/ui/offset-of/offset-of-enum.rs +++ b/tests/ui/offset-of/offset-of-enum.rs @@ -9,5 +9,6 @@ enum Alpha { fn main() { offset_of!(Alpha::One, 0); //~ ERROR expected type, found variant `Alpha::One` - offset_of!(Alpha, Two.0); //~ ERROR no field `Two` on type `Alpha` + offset_of!(Alpha, One); //~ ERROR `One` is an enum variant; expected field at end of `offset_of` + offset_of!(Alpha, Two.0); } diff --git a/tests/ui/offset-of/offset-of-enum.stderr b/tests/ui/offset-of/offset-of-enum.stderr index 6958d199fbdb4..1d849e682e694 100644 --- a/tests/ui/offset-of/offset-of-enum.stderr +++ b/tests/ui/offset-of/offset-of-enum.stderr @@ -7,13 +7,13 @@ LL | offset_of!(Alpha::One, 0); | not a type | help: try using the variant's enum: `Alpha` -error[E0609]: no field `Two` on type `Alpha` +error[E0795]: `One` is an enum variant; expected field at end of `offset_of` --> $DIR/offset-of-enum.rs:12:23 | -LL | offset_of!(Alpha, Two.0); - | ^^^ +LL | offset_of!(Alpha, One); + | ^^^ enum variant error: aborting due to 2 previous errors -Some errors have detailed explanations: E0573, E0609. +Some errors have detailed explanations: E0573, E0795. For more information about an error, try `rustc --explain E0573`. diff --git a/tests/ui/offset-of/offset-of-private.rs b/tests/ui/offset-of/offset-of-private.rs index 6b1a16ba62b67..6fa30d63fb869 100644 --- a/tests/ui/offset-of/offset-of-private.rs +++ b/tests/ui/offset-of/offset-of-private.rs @@ -8,13 +8,20 @@ mod m { pub public: u8, private: u8, } + #[repr(C)] pub struct FooTuple(pub u8, u8); + #[repr(C)] struct Bar { pub public: u8, private: u8, } + + pub enum Baz { + Var1(Foo), + Var2(u64), + } } fn main() { @@ -25,4 +32,8 @@ fn main() { offset_of!(m::Bar, public); //~ ERROR struct `Bar` is private offset_of!(m::Bar, private); //~ ERROR struct `Bar` is private //~| ERROR field `private` of struct `Bar` is private + + offset_of!(m::Baz, Var1.0.public); + offset_of!(m::Baz, Var1.0.private); //~ ERROR field `private` of struct `Foo` is private + offset_of!(m::Baz, Var2.0); } diff --git a/tests/ui/offset-of/offset-of-private.stderr b/tests/ui/offset-of/offset-of-private.stderr index 0674b58f8608c..930e30e6390f5 100644 --- a/tests/ui/offset-of/offset-of-private.stderr +++ b/tests/ui/offset-of/offset-of-private.stderr @@ -1,46 +1,52 @@ error[E0603]: struct `Bar` is private - --> $DIR/offset-of-private.rs:25:19 + --> $DIR/offset-of-private.rs:32:19 | LL | offset_of!(m::Bar, public); | ^^^ private struct | note: the struct `Bar` is defined here - --> $DIR/offset-of-private.rs:14:5 + --> $DIR/offset-of-private.rs:16:5 | LL | struct Bar { | ^^^^^^^^^^ error[E0603]: struct `Bar` is private - --> $DIR/offset-of-private.rs:26:19 + --> $DIR/offset-of-private.rs:33:19 | LL | offset_of!(m::Bar, private); | ^^^ private struct | note: the struct `Bar` is defined here - --> $DIR/offset-of-private.rs:14:5 + --> $DIR/offset-of-private.rs:16:5 | LL | struct Bar { | ^^^^^^^^^^ error[E0616]: field `private` of struct `Foo` is private - --> $DIR/offset-of-private.rs:22:24 + --> $DIR/offset-of-private.rs:29:24 | LL | offset_of!(m::Foo, private); | ^^^^^^^ private field error[E0616]: field `1` of struct `FooTuple` is private - --> $DIR/offset-of-private.rs:24:29 + --> $DIR/offset-of-private.rs:31:29 | LL | offset_of!(m::FooTuple, 1); | ^ private field error[E0616]: field `private` of struct `Bar` is private - --> $DIR/offset-of-private.rs:26:24 + --> $DIR/offset-of-private.rs:33:24 | LL | offset_of!(m::Bar, private); | ^^^^^^^ private field -error: aborting due to 5 previous errors +error[E0616]: field `private` of struct `Foo` is private + --> $DIR/offset-of-private.rs:37:31 + | +LL | offset_of!(m::Baz, Var1.0.private); + | ^^^^^^^ private field + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0603, E0616. For more information about an error, try `rustc --explain E0603`. From d995bd61e77986d8466c4379ca575683c594a9c6 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 15 Aug 2023 22:32:55 +0100 Subject: [PATCH 2/4] Enums in offset_of: update based on est31, scottmcm & llogiq review --- compiler/rustc_abi/src/lib.rs | 7 -- .../src/transform/validate.rs | 36 +++---- compiler/rustc_hir_typeck/src/expr.rs | 101 ++++++++++-------- compiler/rustc_middle/src/mir/syntax.rs | 4 +- compiler/rustc_middle/src/thir.rs | 4 +- compiler/rustc_middle/src/ty/codec.rs | 14 +-- compiler/rustc_middle/src/ty/context.rs | 8 +- .../rustc_middle/src/ty/typeck_results.rs | 10 +- compiler/rustc_passes/src/dead.rs | 25 +---- compiler/rustc_smir/src/rustc_smir/mod.rs | 11 +- compiler/rustc_target/src/abi/mod.rs | 29 +++-- compiler/stable_mir/src/mir/body.rs | 2 +- library/core/src/mem/mod.rs | 10 +- tests/ui/offset-of/offset-of-enum.rs | 3 + tests/ui/offset-of/offset-of-enum.stderr | 26 ++++- 15 files changed, 150 insertions(+), 140 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 0654bfd11c5e5..9626eeea03bd8 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1133,13 +1133,6 @@ rustc_index::newtype_index! { pub struct FieldIdx {} } -/// `offset_of` can traverse fields and enum variants and should keep track of which is which. -#[derive(Copy, Clone, Debug, Eq, Hash, HashStable_Generic, PartialEq, Encodable, Decodable)] -pub enum OffsetOfIdx { - Field(FieldIdx), - Variant(VariantIdx), -} - /// Describes how the fields of a type are located in memory. #[derive(PartialEq, Eq, Hash, Clone, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index bdccd9b0edb53..4d71f76366768 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1062,37 +1062,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; let mut current_ty = *container; - let mut indices = indices.into_iter(); - use rustc_target::abi::OffsetOfIdx::*; - - while let Some(index) = indices.next() { - match (current_ty.kind(), index) { - (ty::Tuple(fields), Field(field)) => { - let Some(&f_ty) = fields.get(field.as_usize()) else { - fail_out_of_bounds(self, location, field, current_ty); + 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; - }; - - current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); - } - (ty::Adt(adt_def, args), Field(field)) if !adt_def.is_enum() => { - let Some(field) = adt_def.non_enum_variant().fields.get(field) else { + } + let Some(&f_ty) = fields.get(field.as_usize()) 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.param_env, f_ty); } - (ty::Adt(adt_def, args), Variant(variant)) if adt_def.is_enum() => { - let Some(Field(field)) = indices.next() else { - self.fail( - location, - format!("enum variant must be followed by field index in offset_of; in {current_ty:?}"), - ); - return; - }; + 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; @@ -1104,7 +1092,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { _ => { self.fail( location, - format!("Cannot get offset {index:?} from type {current_ty:?}"), + format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"), ); return; } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 394a9033765ac..bdac886bf9e73 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -54,7 +54,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_target::abi::FieldIdx; +use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; use rustc_target::spec::abi::Abi::RustIntrinsic; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; @@ -3103,8 +3103,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &[Ident], expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { - use rustc_target::abi::OffsetOfIdx::*; - let container = self.to_ty(container).normalized; let mut field_indices = Vec::with_capacity(fields.len()); @@ -3120,49 +3118,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (ident, _def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); - if let Some((index, variant)) = container_def.variants() + let Some((index, variant)) = container_def.variants() .iter_enumerated() - .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) - { - let Some(&subfield) = fields.next() else { - let mut err = type_error_struct!( - self.tcx().sess, - ident.span, - container, - E0795, - "`{ident}` is an enum variant; expected field at end of `offset_of`", - ); - err.span_label(field.span, "enum variant"); - err.emit(); - break; - }; - let (subident, sub_def_scope) = - self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block); - - if let Some((subindex, field)) = variant.fields - .iter_enumerated() - .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) - { - let field_ty = self.field_ty(expr.span, field, args); + .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) else { + let mut err = type_error_struct!( + self.tcx().sess, + ident.span, + container, + E0599, + "no variant named `{ident}` found for enum `{container}`", + ); + err.span_label(field.span, "variant not found"); + err.emit(); + break; + }; + let Some(&subfield) = fields.next() else { + let mut err = type_error_struct!( + self.tcx().sess, + ident.span, + container, + E0795, + "`{ident}` is an enum variant; expected field at end of `offset_of`", + ); + err.span_label(field.span, "enum variant"); + err.emit(); + break; + }; + let (subident, sub_def_scope) = + self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block); - // FIXME: DSTs with static alignment should be allowed - self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation); + let Some((subindex, field)) = variant.fields + .iter_enumerated() + .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) else { + let mut err = type_error_struct!( + self.tcx().sess, + ident.span, + container, + E0609, + "no field named `{subfield}` on enum variant `{container}::{ident}`", + ); + err.span_label(field.span, "this enum variant..."); + err.span_label(subident.span, "...does not have this field"); + err.emit(); + break; + }; - if field.vis.is_accessible_from(sub_def_scope, self.tcx) { - self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); - } else { - self.private_field_err(ident, container_def.did()).emit(); - } + let field_ty = self.field_ty(expr.span, field, args); - // Save the index of all fields regardless of their visibility in case - // of error recovery. - field_indices.push(Variant(index)); - field_indices.push(Field(subindex)); - current_container = field_ty; + // FIXME: DSTs with static alignment should be allowed + self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation); - continue; - } + if field.vis.is_accessible_from(sub_def_scope, self.tcx) { + self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); + } else { + self.private_field_err(ident, container_def.did()).emit(); } + + // Save the index of all fields regardless of their visibility in case + // of error recovery. + field_indices.push((index, subindex)); + current_container = field_ty; + + continue; } ty::Adt(container_def, args) => { let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); @@ -3187,7 +3204,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(Field(index)); + field_indices.push((FIRST_VARIANT, index)); current_container = field_ty; continue; @@ -3201,7 +3218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized(ty, expr.span, traits::MiscObligation); } if let Some(&field_ty) = tys.get(index) { - field_indices.push(Field(index.into())); + field_indices.push((FIRST_VARIANT, index.into())); current_container = field_ty; continue; diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index d0094a81634de..b6543affc6dbe 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -17,7 +17,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{self as hir}; use rustc_hir::{self, CoroutineKind}; use rustc_index::IndexVec; -use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx}; +use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_ast::Mutability; use rustc_span::def_id::LocalDefId; @@ -1354,7 +1354,7 @@ pub enum NullOp<'tcx> { /// Returns the minimum alignment of a type AlignOf, /// Returns the offset of a field - OffsetOf(&'tcx List), + OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>), } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 2ee726c76bf0c..3780eb4f9ac97 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -26,7 +26,7 @@ use rustc_middle::ty::{ use rustc_span::def_id::LocalDefId; use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP}; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx}; +use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; use std::ops::Index; @@ -491,7 +491,7 @@ pub enum ExprKind<'tcx> { /// Field offset (`offset_of!`) OffsetOf { container: Ty<'tcx>, - fields: &'tcx List, + fields: &'tcx List<(VariantIdx, FieldIdx)>, }, /// An expression taking a reference to a thread local. ThreadLocalRef(DefId), diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index ce5198ee3baf8..8b67e39667b8d 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; use rustc_serialize::{Decodable, Encodable}; use rustc_span::Span; -use rustc_target::abi::{FieldIdx, OffsetOfIdx}; +use rustc_target::abi::{FieldIdx, VariantIdx}; pub use rustc_type_ir::{TyDecoder, TyEncoder}; use std::hash::Hash; use std::intrinsics; @@ -414,12 +414,14 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List>> RefDecodable<'tcx, D> for ty::List { +impl<'tcx, D: TyDecoder>> 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::(|_| Decodable::decode(decoder))) + decoder.interner().mk_offset_of_from_iter( + (0..len).map::<(VariantIdx, FieldIdx), _>(|_| Decodable::decode(decoder)), + ) } } @@ -435,7 +437,7 @@ impl_decodable_via_ref! { &'tcx ty::List, &'tcx ty::List>, &'tcx ty::List, - &'tcx ty::List, + &'tcx ty::List<(VariantIdx, FieldIdx)>, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c89ae1e661ed6..68812bba42fdd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -63,7 +63,7 @@ use rustc_session::{Limit, MetadataKind, Session}; use rustc_span::def_id::{DefPathHash, StableCrateId}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{FieldIdx, Layout, LayoutS, OffsetOfIdx, TargetDataLayout, VariantIdx}; +use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; @@ -163,7 +163,7 @@ pub struct CtxtInterners<'tcx> { predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, - offset_of: InternedSet<'tcx, List>, + offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -1589,7 +1589,7 @@ slice_interners!( bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), fields: pub mk_fields(FieldIdx), local_def_ids: intern_local_def_ids(LocalDefId), - offset_of: pub mk_offset_of(OffsetOfIdx), + offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), ); impl<'tcx> TyCtxt<'tcx> { @@ -1920,7 +1920,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_offset_of_from_iter(self, iter: I) -> T::Output where I: Iterator, - T: CollectAndApply>, + T: CollectAndApply<(VariantIdx, FieldIdx), &'tcx List<(VariantIdx, FieldIdx)>>, { T::collect_and_apply(iter, |xs| self.mk_offset_of(xs)) } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 623d8d61d2d5f..e9240d1b268e6 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -24,7 +24,7 @@ use rustc_macros::HashStable; use rustc_middle::mir::FakeReadCause; use rustc_session::Session; use rustc_span::Span; -use rustc_target::abi::{FieldIdx, OffsetOfIdx}; +use rustc_target::abi::{FieldIdx, VariantIdx}; use std::{collections::hash_map::Entry, hash::Hash, iter}; use super::RvalueScopes; @@ -205,7 +205,7 @@ pub struct TypeckResults<'tcx> { pub closure_size_eval: LocalDefIdMap>, /// Container types and field indices of `offset_of!` expressions - offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec)>, + offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>, } impl<'tcx> TypeckResults<'tcx> { @@ -464,13 +464,15 @@ impl<'tcx> TypeckResults<'tcx> { &self.coercion_casts } - pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec)> { + pub fn offset_of_data( + &self, + ) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<(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)> { + ) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data } } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 3b4f6a618c8b6..2e8c58b0241f9 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -248,8 +248,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) { - use rustc_target::abi::OffsetOfIdx::*; - 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"); @@ -258,22 +256,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { let param_env = self.tcx.param_env(body_did); let mut current_ty = container; - let mut indices = indices.into_iter(); - - while let Some(&index) = indices.next() { - match (current_ty.kind(), index) { - (ty::Adt(def, subst), Field(field)) if !def.is_enum() => { - let field = &def.non_enum_variant().fields[field]; - self.insert_def_id(field.did); - let field_ty = field.ty(self.tcx, subst); - - current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty); - } - (ty::Adt(def, subst), Variant(variant)) if def.is_enum() => { - let Some(&Field(field)) = indices.next() else { - span_bug!(expr.span, "variant must be followed by field in offset_of") - }; + for &(variant, field) in indices { + match current_ty.kind() { + ty::Adt(def, subst) => { let field = &def.variant(variant).fields[field]; self.insert_def_id(field.did); @@ -283,12 +269,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } // we don't need to mark tuple fields as live, // but we may need to mark subfields - (ty::Tuple(tys), Field(field)) => { + ty::Tuple(tys) => { current_ty = self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]); } - (_, Field(_)) => span_bug!(expr.span, "named field access on non-ADT"), - (_, Variant(_)) => span_bug!(expr.span, "enum variant access on non-enum"), + _ => span_bug!(expr.span, "named field access on non-ADT"), } } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index e64afa5f8d930..2abad677bf043 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -16,7 +16,7 @@ use rustc_middle::mir::interpret::{alloc_range, AllocId}; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_target::abi::{FieldIdx, OffsetOfIdx}; +use rustc_target::abi::FieldIdx; use stable_mir::mir::mono::InstanceDef; use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx}; use stable_mir::ty::{ @@ -643,13 +643,10 @@ impl<'tcx> Stable<'tcx> for FieldIdx { } } -impl<'tcx> Stable<'tcx> for OffsetOfIdx { - type T = usize; +impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) { + type T = (usize, usize); fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { - match self { - OffsetOfIdx::Field(f) => f.as_usize(), - OffsetOfIdx::Variant(v) => v.as_usize(), - } + (self.0.as_usize(), self.1.as_usize()) } } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a37a5bb26893f..b00567e87c656 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -250,29 +250,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } - pub fn offset_of_subfield(self, cx: &C, indices: impl Iterator) -> Size + pub fn offset_of_subfield(self, cx: &C, indices: I) -> Size where Ty: TyAbiInterface<'a, C>, + I: Iterator, { let mut layout = self; let mut offset = Size::ZERO; - for index in indices { - match index { - OffsetOfIdx::Field(field) => { - let index = field.index(); - offset += layout.fields.offset(index); - layout = layout.field(cx, index); - assert!( - layout.is_sized(), - "offset of unsized field (type {:?}) cannot be computed statically", - layout.ty - ); - } - OffsetOfIdx::Variant(variant) => { - layout = layout.for_variant(cx, variant); - } - } + 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); + assert!( + layout.is_sized(), + "offset of unsized field (type {:?}) cannot be computed statically", + layout.ty + ); } offset diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 9f69e61d6fe7b..9dc746f5c4d24 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -514,7 +514,7 @@ pub enum NullOp { /// Returns the minimum alignment of a type. AlignOf, /// Returns the offset of a field. - OffsetOf(Vec), + OffsetOf(Vec<(VariantIdx, FieldIdx)>), } impl Operand { diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index df79c3a338a15..862619f31f261 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1292,11 +1292,15 @@ impl SizedTypeProperties for T {} /// Expands to the offset in bytes of a field from the beginning of the given type. /// -/// Only structs, unions and tuples are supported. +/// Structs, enums, unions and tuples are supported. /// /// Nested field accesses may be used, but not array indexes like in `C`'s `offsetof`. /// -/// Note that the output of this macro is not stable, except for `#[repr(C)]` types. +/// Enum variants may be traversed as if they were fields. Variants themselves do +/// not have an offset. +/// +/// Note that type layout is, in general, [platform-specific, and subject to +/// change](https://doc.rust-lang.org/reference/type-layout.html). /// /// # Examples /// @@ -1324,6 +1328,8 @@ impl SizedTypeProperties for T {} /// struct NestedB(u8); /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); +/// +/// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// ``` #[unstable(feature = "offset_of", issue = "106655")] #[allow_internal_unstable(builtin_syntax, hint_must_use)] diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs index 92d34e67c71b2..cf516175085b6 100644 --- a/tests/ui/offset-of/offset-of-enum.rs +++ b/tests/ui/offset-of/offset-of-enum.rs @@ -11,4 +11,7 @@ fn main() { offset_of!(Alpha::One, 0); //~ ERROR expected type, found variant `Alpha::One` offset_of!(Alpha, One); //~ ERROR `One` is an enum variant; expected field at end of `offset_of` offset_of!(Alpha, Two.0); + offset_of!(Alpha, Two.1); //~ ERROR no field named `1` on enum variant `Alpha::Two` + offset_of!(Alpha, Two.foo); //~ ERROR no field named `foo` on enum variant `Alpha::Two` + offset_of!(Alpha, NonExistent); //~ ERROR no variant named `NonExistent` found for enum `Alpha` } diff --git a/tests/ui/offset-of/offset-of-enum.stderr b/tests/ui/offset-of/offset-of-enum.stderr index 1d849e682e694..2867cc6befb56 100644 --- a/tests/ui/offset-of/offset-of-enum.stderr +++ b/tests/ui/offset-of/offset-of-enum.stderr @@ -13,7 +13,29 @@ error[E0795]: `One` is an enum variant; expected field at end of `offset_of` LL | offset_of!(Alpha, One); | ^^^ enum variant -error: aborting due to 2 previous errors +error[E0609]: no field named `1` on enum variant `Alpha::Two` + --> $DIR/offset-of-enum.rs:14:23 + | +LL | offset_of!(Alpha, Two.1); + | ^^^ - ...does not have this field + | | + | this enum variant... + +error[E0609]: no field named `foo` on enum variant `Alpha::Two` + --> $DIR/offset-of-enum.rs:15:23 + | +LL | offset_of!(Alpha, Two.foo); + | ^^^ --- ...does not have this field + | | + | this enum variant... + +error[E0599]: no variant named `NonExistent` found for enum `Alpha` + --> $DIR/offset-of-enum.rs:16:23 + | +LL | offset_of!(Alpha, NonExistent); + | ^^^^^^^^^^^ variant not found + +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0573, E0795. +Some errors have detailed explanations: E0573, E0599, E0609, E0795. For more information about an error, try `rustc --explain E0573`. From 9d6ce61376ef77bae3268b1b69ec6e7f3b815923 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 31 Oct 2023 21:25:45 +0000 Subject: [PATCH 3/4] Update MIR tests for offset_of --- compiler/rustc_abi/src/lib.rs | 26 ------------------- compiler/rustc_middle/src/thir.rs | 1 - .../src/dataflow_const_prop.rs | 6 ++--- library/core/src/mem/mod.rs | 1 + ...set_of.concrete.ConstProp.panic-abort.diff | 14 +++++----- ...et_of.concrete.ConstProp.panic-unwind.diff | 14 +++++----- ...fset_of.generic.ConstProp.panic-abort.diff | 14 +++++----- ...set_of.generic.ConstProp.panic-unwind.diff | 14 +++++----- ...oncrete.DataflowConstProp.panic-abort.diff | 8 +++--- ...ncrete.DataflowConstProp.panic-unwind.diff | 8 +++--- ...generic.DataflowConstProp.panic-abort.diff | 8 +++--- ...eneric.DataflowConstProp.panic-unwind.diff | 8 +++--- 12 files changed, 48 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 9626eeea03bd8..8e7aa59ee341e 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1107,32 +1107,6 @@ impl Scalar { } // NOTE: This struct is generic over the FieldIdx for rust-analyzer usage. -rustc_index::newtype_index! { - /// The *source-order* index of a field in a variant. - /// - /// This is how most code after type checking refers to fields, rather than - /// using names (as names have hygiene complications and more complex lookup). - /// - /// Particularly for `repr(Rust)` types, this may not be the same as *layout* order. - /// (It is for `repr(C)` `struct`s, however.) - /// - /// For example, in the following types, - /// ```rust - /// # enum Never {} - /// # #[repr(u16)] - /// enum Demo1 { - /// Variant0 { a: Never, b: i32 } = 100, - /// Variant1 { c: u8, d: u64 } = 10, - /// } - /// struct Demo2 { e: u8, f: u16, g: u8 } - /// ``` - /// `b` is `FieldIdx(1)` in `VariantIdx(0)`, - /// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and - /// `f` is `FieldIdx(1)` in `VariantIdx(0)`. - #[derive(HashStable_Generic)] - pub struct FieldIdx {} -} - /// Describes how the fields of a type are located in memory. #[derive(PartialEq, Eq, Hash, Clone, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3780eb4f9ac97..e83ebe651abff 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -25,7 +25,6 @@ use rustc_middle::ty::{ }; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP}; -use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index ca10dc48eb805..81d2bba989a7f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -286,9 +286,9 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { let val = match null_op { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => layout - .offset_of_subfield(&self.ecx, fields.iter()) - .bytes(), + NullOp::OffsetOf(fields) => { + layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() + } _ => return ValueOrPlace::Value(FlatSet::Top), }; FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx)) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 862619f31f261..b5b0e5882dad3 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1329,6 +1329,7 @@ impl SizedTypeProperties for T {} /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// +/// # #[cfg(not(bootstrap))] /// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// ``` #[unstable(feature = "offset_of", issue = "106655")] diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff index e460c08f9bb8d..711db3d21dd72 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-abort.diff @@ -42,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); -- _2 = OffsetOf(Alpha, [Field(0)]); +- _2 = OffsetOf(Alpha, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; + _2 = const 4_usize; + _1 = must_use::(const 4_usize) -> [return: bb1, unwind unreachable]; @@ -52,7 +52,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); -- _4 = OffsetOf(Alpha, [Field(1)]); +- _4 = OffsetOf(Alpha, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; + _4 = const 0_usize; + _3 = must_use::(const 0_usize) -> [return: bb2, unwind unreachable]; @@ -62,7 +62,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Alpha, [Field(2), Field(0)]); +- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); - _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; + _6 = const 2_usize; + _5 = must_use::(const 2_usize) -> [return: bb3, unwind unreachable]; @@ -72,7 +72,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Alpha, [Field(2), Field(1)]); +- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); - _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; + _8 = const 3_usize; + _7 = must_use::(const 3_usize) -> [return: bb4, unwind unreachable]; @@ -82,7 +82,7 @@ StorageDead(_8); StorageLive(_9); StorageLive(_10); -- _10 = OffsetOf(Epsilon, [Variant(0), Field(0)]); +- _10 = OffsetOf(Epsilon, [(0, 0)]); - _9 = must_use::(move _10) -> [return: bb5, unwind unreachable]; + _10 = const 1_usize; + _9 = must_use::(const 1_usize) -> [return: bb5, unwind unreachable]; @@ -92,7 +92,7 @@ StorageDead(_10); StorageLive(_11); StorageLive(_12); -- _12 = OffsetOf(Epsilon, [Variant(0), Field(1)]); +- _12 = OffsetOf(Epsilon, [(0, 1)]); - _11 = must_use::(move _12) -> [return: bb6, unwind unreachable]; + _12 = const 2_usize; + _11 = must_use::(const 2_usize) -> [return: bb6, unwind unreachable]; @@ -102,7 +102,7 @@ StorageDead(_12); StorageLive(_13); StorageLive(_14); -- _14 = OffsetOf(Epsilon, [Variant(2), Field(0)]); +- _14 = OffsetOf(Epsilon, [(2, 0)]); - _13 = must_use::(move _14) -> [return: bb7, unwind unreachable]; + _14 = const 4_usize; + _13 = must_use::(const 4_usize) -> [return: bb7, unwind unreachable]; diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff index 3b8d0d75101f4..49458145415c7 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff @@ -42,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); -- _2 = OffsetOf(Alpha, [Field(0)]); +- _2 = OffsetOf(Alpha, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind continue]; + _2 = const 4_usize; + _1 = must_use::(const 4_usize) -> [return: bb1, unwind continue]; @@ -52,7 +52,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); -- _4 = OffsetOf(Alpha, [Field(1)]); +- _4 = OffsetOf(Alpha, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind continue]; + _4 = const 0_usize; + _3 = must_use::(const 0_usize) -> [return: bb2, unwind continue]; @@ -62,7 +62,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Alpha, [Field(2), Field(0)]); +- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); - _5 = must_use::(move _6) -> [return: bb3, unwind continue]; + _6 = const 2_usize; + _5 = must_use::(const 2_usize) -> [return: bb3, unwind continue]; @@ -72,7 +72,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Alpha, [Field(2), Field(1)]); +- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); - _7 = must_use::(move _8) -> [return: bb4, unwind continue]; + _8 = const 3_usize; + _7 = must_use::(const 3_usize) -> [return: bb4, unwind continue]; @@ -82,7 +82,7 @@ StorageDead(_8); StorageLive(_9); StorageLive(_10); -- _10 = OffsetOf(Epsilon, [Variant(0), Field(0)]); +- _10 = OffsetOf(Epsilon, [(0, 0)]); - _9 = must_use::(move _10) -> [return: bb5, unwind continue]; + _10 = const 1_usize; + _9 = must_use::(const 1_usize) -> [return: bb5, unwind continue]; @@ -92,7 +92,7 @@ StorageDead(_10); StorageLive(_11); StorageLive(_12); -- _12 = OffsetOf(Epsilon, [Variant(0), Field(1)]); +- _12 = OffsetOf(Epsilon, [(0, 1)]); - _11 = must_use::(move _12) -> [return: bb6, unwind continue]; + _12 = const 2_usize; + _11 = must_use::(const 2_usize) -> [return: bb6, unwind continue]; @@ -102,7 +102,7 @@ StorageDead(_12); StorageLive(_13); StorageLive(_14); -- _14 = OffsetOf(Epsilon, [Variant(2), Field(0)]); +- _14 = OffsetOf(Epsilon, [(2, 0)]); - _13 = must_use::(move _14) -> [return: bb7, unwind continue]; + _14 = const 4_usize; + _13 = must_use::(const 4_usize) -> [return: bb7, unwind continue]; diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff index f26b104e065d7..768970a7250f0 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-abort.diff @@ -42,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = OffsetOf(Gamma, [Field(0)]); + _2 = OffsetOf(Gamma, [(0, 0)]); _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; } @@ -50,7 +50,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); - _4 = OffsetOf(Gamma, [Field(1)]); + _4 = OffsetOf(Gamma, [(0, 1)]); _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; } @@ -58,7 +58,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); - _6 = OffsetOf(Delta, [Field(1)]); + _6 = OffsetOf(Delta, [(0, 1)]); _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; } @@ -66,7 +66,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); - _8 = OffsetOf(Delta, [Field(2)]); + _8 = OffsetOf(Delta, [(0, 2)]); _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; } @@ -74,7 +74,7 @@ StorageDead(_8); StorageLive(_9); StorageLive(_10); - _10 = OffsetOf(Zeta, [Variant(0), Field(0)]); + _10 = OffsetOf(Zeta, [(0, 0)]); _9 = must_use::(move _10) -> [return: bb5, unwind unreachable]; } @@ -82,7 +82,7 @@ StorageDead(_10); StorageLive(_11); StorageLive(_12); - _12 = OffsetOf(Zeta, [Variant(0), Field(1)]); + _12 = OffsetOf(Zeta, [(0, 1)]); _11 = must_use::(move _12) -> [return: bb6, unwind unreachable]; } @@ -90,7 +90,7 @@ StorageDead(_12); StorageLive(_13); StorageLive(_14); - _14 = OffsetOf(Zeta, [Variant(1), Field(0)]); + _14 = OffsetOf(Zeta, [(1, 0)]); _13 = must_use::(move _14) -> [return: bb7, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff index 0f8750fce460c..04ccd2b36e0d8 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff @@ -42,7 +42,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = OffsetOf(Gamma, [Field(0)]); + _2 = OffsetOf(Gamma, [(0, 0)]); _1 = must_use::(move _2) -> [return: bb1, unwind continue]; } @@ -50,7 +50,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); - _4 = OffsetOf(Gamma, [Field(1)]); + _4 = OffsetOf(Gamma, [(0, 1)]); _3 = must_use::(move _4) -> [return: bb2, unwind continue]; } @@ -58,7 +58,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); - _6 = OffsetOf(Delta, [Field(1)]); + _6 = OffsetOf(Delta, [(0, 1)]); _5 = must_use::(move _6) -> [return: bb3, unwind continue]; } @@ -66,7 +66,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); - _8 = OffsetOf(Delta, [Field(2)]); + _8 = OffsetOf(Delta, [(0, 2)]); _7 = must_use::(move _8) -> [return: bb4, unwind continue]; } @@ -74,7 +74,7 @@ StorageDead(_8); StorageLive(_9); StorageLive(_10); - _10 = OffsetOf(Zeta, [Variant(0), Field(0)]); + _10 = OffsetOf(Zeta, [(0, 0)]); _9 = must_use::(move _10) -> [return: bb5, unwind continue]; } @@ -82,7 +82,7 @@ StorageDead(_10); StorageLive(_11); StorageLive(_12); - _12 = OffsetOf(Zeta, [Variant(0), Field(1)]); + _12 = OffsetOf(Zeta, [(0, 1)]); _11 = must_use::(move _12) -> [return: bb6, unwind continue]; } @@ -90,7 +90,7 @@ StorageDead(_12); StorageLive(_13); StorageLive(_14); - _14 = OffsetOf(Zeta, [Variant(1), Field(0)]); + _14 = OffsetOf(Zeta, [(1, 0)]); _13 = must_use::(move _14) -> [return: bb7, unwind continue]; } 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 index c61414b6541a7..f8f8917503370 100644 --- 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 @@ -27,7 +27,7 @@ bb0: { StorageLive(_1); StorageLive(_2); -- _2 = OffsetOf(Alpha, [0]); +- _2 = OffsetOf(Alpha, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; + _2 = const 4_usize; + _1 = must_use::(const 4_usize) -> [return: bb1, unwind unreachable]; @@ -37,7 +37,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); -- _4 = OffsetOf(Alpha, [1]); +- _4 = OffsetOf(Alpha, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; + _4 = const 0_usize; + _3 = must_use::(const 0_usize) -> [return: bb2, unwind unreachable]; @@ -47,7 +47,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Alpha, [2, 0]); +- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); - _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; + _6 = const 2_usize; + _5 = must_use::(const 2_usize) -> [return: bb3, unwind unreachable]; @@ -57,7 +57,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Alpha, [2, 1]); +- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); - _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; + _8 = const 3_usize; + _7 = must_use::(const 3_usize) -> [return: bb4, unwind unreachable]; 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 index 0c3939a3456ac..d4f8cb66704ae 100644 --- 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 @@ -27,7 +27,7 @@ bb0: { StorageLive(_1); StorageLive(_2); -- _2 = OffsetOf(Alpha, [0]); +- _2 = OffsetOf(Alpha, [(0, 0)]); - _1 = must_use::(move _2) -> [return: bb1, unwind continue]; + _2 = const 4_usize; + _1 = must_use::(const 4_usize) -> [return: bb1, unwind continue]; @@ -37,7 +37,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); -- _4 = OffsetOf(Alpha, [1]); +- _4 = OffsetOf(Alpha, [(0, 1)]); - _3 = must_use::(move _4) -> [return: bb2, unwind continue]; + _4 = const 0_usize; + _3 = must_use::(const 0_usize) -> [return: bb2, unwind continue]; @@ -47,7 +47,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Alpha, [2, 0]); +- _6 = OffsetOf(Alpha, [(0, 2), (0, 0)]); - _5 = must_use::(move _6) -> [return: bb3, unwind continue]; + _6 = const 2_usize; + _5 = must_use::(const 2_usize) -> [return: bb3, unwind continue]; @@ -57,7 +57,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Alpha, [2, 1]); +- _8 = OffsetOf(Alpha, [(0, 2), (0, 1)]); - _7 = must_use::(move _8) -> [return: bb4, unwind continue]; + _8 = const 3_usize; + _7 = must_use::(const 3_usize) -> [return: bb4, unwind continue]; 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 index d54d46870609d..7f166e4fa356a 100644 --- 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 @@ -27,7 +27,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = OffsetOf(Gamma, [0]); + _2 = OffsetOf(Gamma, [(0, 0)]); _1 = must_use::(move _2) -> [return: bb1, unwind unreachable]; } @@ -35,7 +35,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); - _4 = OffsetOf(Gamma, [1]); + _4 = OffsetOf(Gamma, [(0, 1)]); _3 = must_use::(move _4) -> [return: bb2, unwind unreachable]; } @@ -43,7 +43,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Delta, [1]); +- _6 = OffsetOf(Delta, [(0, 1)]); - _5 = must_use::(move _6) -> [return: bb3, unwind unreachable]; + _6 = const 0_usize; + _5 = must_use::(const 0_usize) -> [return: bb3, unwind unreachable]; @@ -53,7 +53,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Delta, [2]); +- _8 = OffsetOf(Delta, [(0, 2)]); - _7 = must_use::(move _8) -> [return: bb4, unwind unreachable]; + _8 = const 2_usize; + _7 = must_use::(const 2_usize) -> [return: bb4, unwind unreachable]; 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 index 6032a2274efe9..38ad6f7980160 100644 --- 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 @@ -27,7 +27,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = OffsetOf(Gamma, [0]); + _2 = OffsetOf(Gamma, [(0, 0)]); _1 = must_use::(move _2) -> [return: bb1, unwind continue]; } @@ -35,7 +35,7 @@ StorageDead(_2); StorageLive(_3); StorageLive(_4); - _4 = OffsetOf(Gamma, [1]); + _4 = OffsetOf(Gamma, [(0, 1)]); _3 = must_use::(move _4) -> [return: bb2, unwind continue]; } @@ -43,7 +43,7 @@ StorageDead(_4); StorageLive(_5); StorageLive(_6); -- _6 = OffsetOf(Delta, [1]); +- _6 = OffsetOf(Delta, [(0, 1)]); - _5 = must_use::(move _6) -> [return: bb3, unwind continue]; + _6 = const 0_usize; + _5 = must_use::(const 0_usize) -> [return: bb3, unwind continue]; @@ -53,7 +53,7 @@ StorageDead(_6); StorageLive(_7); StorageLive(_8); -- _8 = OffsetOf(Delta, [2]); +- _8 = OffsetOf(Delta, [(0, 2)]); - _7 = must_use::(move _8) -> [return: bb4, unwind continue]; + _8 = const 2_usize; + _7 = must_use::(const 2_usize) -> [return: bb4, unwind continue]; From e742f809f68d571a28b7c9153366194e47714b65 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 31 Oct 2023 23:41:40 +0000 Subject: [PATCH 4/4] Update based on wesleywiser review --- compiler/rustc_mir_transform/src/gvn.rs | 6 +++--- library/core/src/mem/mod.rs | 4 ++-- tests/ui/offset-of/offset-of-enum.rs | 1 + tests/ui/offset-of/offset-of-enum.stderr | 12 +++++++++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index de0dc25808b30..dce298e92e166 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -467,9 +467,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => layout - .offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index())) - .bytes(), + NullOp::OffsetOf(fields) => { + layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() + } }; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); let imm = ImmTy::try_from_uint(val, usize_layout)?; diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index b5b0e5882dad3..8792134cdc862 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1299,8 +1299,8 @@ impl SizedTypeProperties for T {} /// Enum variants may be traversed as if they were fields. Variants themselves do /// not have an offset. /// -/// Note that type layout is, in general, [platform-specific, and subject to -/// change](https://doc.rust-lang.org/reference/type-layout.html). +/// Note that type layout is, in general, [subject to change and +/// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). /// /// # Examples /// diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs index cf516175085b6..e8b5a08377bdd 100644 --- a/tests/ui/offset-of/offset-of-enum.rs +++ b/tests/ui/offset-of/offset-of-enum.rs @@ -14,4 +14,5 @@ fn main() { offset_of!(Alpha, Two.1); //~ ERROR no field named `1` on enum variant `Alpha::Two` offset_of!(Alpha, Two.foo); //~ ERROR no field named `foo` on enum variant `Alpha::Two` offset_of!(Alpha, NonExistent); //~ ERROR no variant named `NonExistent` found for enum `Alpha` + offset_of!(Beta, One); //~ ERROR cannot find type `Beta` in this scope } diff --git a/tests/ui/offset-of/offset-of-enum.stderr b/tests/ui/offset-of/offset-of-enum.stderr index 2867cc6befb56..7e7ad41f5b6a9 100644 --- a/tests/ui/offset-of/offset-of-enum.stderr +++ b/tests/ui/offset-of/offset-of-enum.stderr @@ -7,6 +7,12 @@ LL | offset_of!(Alpha::One, 0); | not a type | help: try using the variant's enum: `Alpha` +error[E0412]: cannot find type `Beta` in this scope + --> $DIR/offset-of-enum.rs:17:16 + | +LL | offset_of!(Beta, One); + | ^^^^ not found in this scope + error[E0795]: `One` is an enum variant; expected field at end of `offset_of` --> $DIR/offset-of-enum.rs:12:23 | @@ -35,7 +41,7 @@ error[E0599]: no variant named `NonExistent` found for enum `Alpha` LL | offset_of!(Alpha, NonExistent); | ^^^^^^^^^^^ variant not found -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0573, E0599, E0609, E0795. -For more information about an error, try `rustc --explain E0573`. +Some errors have detailed explanations: E0412, E0573, E0599, E0609, E0795. +For more information about an error, try `rustc --explain E0412`.