diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 0315625269c20..12dd1542d7994 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1119,13 +1119,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 7f1a27242cfec..bd833c4dee894 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -971,37 +971,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; @@ -1013,7 +1001,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 b6f06714b9962..e9ca69e00246f 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -52,7 +52,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; @@ -3128,8 +3128,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()); @@ -3145,49 +3143,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); @@ -3212,7 +3229,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; @@ -3226,7 +3243,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 fa1509250ab4c..2791dd757bc6b 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, GeneratorKind}; 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; @@ -1281,7 +1281,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 f56519255505e..84398a48b6cfc 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarArgs}; use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; use rustc_span::def_id::LocalDefId; 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; @@ -488,7 +488,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 9d2feeb9e2d47..c4fb9612eb994 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; @@ -412,12 +412,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)), + ) } } @@ -433,7 +435,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 846deddcc4b9c..251c79955c7fc 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::sty::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; @@ -156,7 +156,7 @@ pub struct CtxtInterners<'tcx> { external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List>, - offset_of: InternedSet<'tcx, List>, + offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -1538,7 +1538,7 @@ slice_interners!( place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), fields: pub mk_fields(FieldIdx), - offset_of: pub mk_offset_of(OffsetOfIdx), + offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), ); impl<'tcx> TyCtxt<'tcx> { @@ -1863,7 +1863,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 106bf39ebcef6..f4cde81ffef1e 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; @@ -209,7 +209,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)>)>, } /// Whenever a value may be live across a generator yield, the type of that value winds up in the @@ -534,13 +534,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 3e2e68f406e76..6cd5efff0e378 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -247,8 +247,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"); @@ -257,22 +255,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); @@ -282,12 +268,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 4de511d630cb0..7aaf251bef698 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::interpret::alloc_range; use rustc_middle::mir::{self, ConstantKind}; use rustc_middle::ty::{self, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use rustc_target::abi::{FieldIdx, OffsetOfIdx}; +use rustc_target::abi::FieldIdx; use tracing::debug; impl<'tcx> Context for Tables<'tcx> { @@ -450,13 +450,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_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs index c16bd6cbd70e2..28000250851cf 100644 --- a/compiler/rustc_smir/src/stable_mir/mir/body.rs +++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs @@ -474,5 +474,5 @@ pub enum NullOp { /// Returns the minimum alignment of a type. AlignOf, /// Returns the offset of a field. - OffsetOf(Vec), + OffsetOf(Vec<(VariantIdx, FieldIdx)>), } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index d4830224007bb..01c53ff1dcc16 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -125,29 +125,24 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_unit(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/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 2fff3f0efd73a..14d35de918826 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1283,11 +1283,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 /// @@ -1315,6 +1319,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`.