Auto merge of #114208 - GKFX:offset_of_enum, r=wesleywiser

Support enum variants in offset_of!

This MR implements support for navigating through enum variants in `offset_of!`, placing the enum variant name in the second argument to `offset_of!`. The RFC placed it in the first argument, but I think it interacts better with nested field access in the second, as you can then write things like

```rust
offset_of!(Type, field.Variant.field)
```

Alternatively, a syntactic distinction could be made between variants and fields (e.g. `field::Variant.field`) but I'm not convinced this would be helpful.

[RFC 3308 # Enum Support](https://rust-lang.github.io/rfcs/3308-offset_of.html#enum-support-offset_ofsomeenumstructvariant-field_on_variant)
Tracking Issue #106655.
This commit is contained in:
bors 2023-11-01 14:17:56 +00:00
commit 146dafa262
33 changed files with 477 additions and 89 deletions

View File

@ -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(

View File

@ -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);

View File

@ -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)?;

View File

@ -1056,16 +1056,23 @@ 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;
for field in fields.iter() {
for (variant, field) in indices.iter() {
match current_ty.kind() {
ty::Tuple(fields) => {
if variant != FIRST_VARIANT {
self.fail(
location,
format!("tried to get variant {variant:?} of tuple"),
);
return;
}
let Some(&f_ty) = fields.get(field.as_usize()) else {
fail_out_of_bounds(self, location, field, current_ty);
return;
@ -1074,15 +1081,7 @@ 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() {
self.fail(
location,
format!("Cannot get field offset from enum {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 +1092,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 ({variant:?}, {field:?}) from type {current_ty:?}"),
);
return;
}

View File

@ -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

View File

@ -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<u8>, 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<u8>` can be found by specifying
the field name `0`:
```
#![feature(offset_of)]
let x: usize = std::mem::offset_of!(Option<u8>, 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.

View File

@ -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;
@ -3107,12 +3107,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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);
let Some((index, variant)) = container_def.variants()
.iter_enumerated()
.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);
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;
};
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((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);
let (ident, def_scope) =
self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
@ -3135,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(index);
field_indices.push((FIRST_VARIANT, index));
current_container = field_ty;
continue;
@ -3149,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(index.into());
field_indices.push((FIRST_VARIANT, index.into()));
current_container = field_ty;
continue;

View File

@ -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<FieldIdx>),
OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]

View File

@ -492,7 +492,7 @@ pub enum ExprKind<'tcx> {
/// Field offset (`offset_of!`)
OffsetOf {
container: Ty<'tcx>,
fields: &'tcx List<FieldIdx>,
fields: &'tcx List<(VariantIdx, FieldIdx)>,
},
/// An expression taking a reference to a thread local.
ThreadLocalRef(DefId),

View File

@ -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, VariantIdx};
pub use rustc_type_ir::{TyDecoder, TyEncoder};
use std::hash::Hash;
use std::intrinsics;
@ -414,6 +414,17 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Fi
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
for ty::List<(VariantIdx, FieldIdx)>
{
fn decode(decoder: &mut D) -> &'tcx Self {
let len = decoder.read_usize();
decoder.interner().mk_offset_of_from_iter(
(0..len).map::<(VariantIdx, FieldIdx), _>(|_| Decodable::decode(decoder)),
)
}
}
impl_decodable_via_ref! {
&'tcx ty::TypeckResults<'tcx>,
&'tcx ty::List<Ty<'tcx>>,
@ -426,6 +437,7 @@ impl_decodable_via_ref! {
&'tcx ty::List<ty::BoundVariableKind>,
&'tcx ty::List<ty::Clause<'tcx>>,
&'tcx ty::List<FieldIdx>,
&'tcx ty::List<(VariantIdx, FieldIdx)>,
}
#[macro_export]

View File

@ -163,6 +163,7 @@ pub struct CtxtInterners<'tcx> {
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
fields: InternedSet<'tcx, List<FieldIdx>>,
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
}
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((VariantIdx, FieldIdx)),
);
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<I, T>(self, iter: I) -> T::Output
where
I: Iterator<Item = T>,
T: CollectAndApply<(VariantIdx, FieldIdx), &'tcx List<(VariantIdx, FieldIdx)>>,
{
T::collect_and_apply(iter, |xs| self.mk_offset_of(xs))
}
pub fn mk_args_trait(
self,
self_ty: Ty<'tcx>,

View File

@ -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, 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<ClosureSizeProfileData<'tcx>>,
/// Container types and field indices of `offset_of!` expressions
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>,
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
}
impl<'tcx> TypeckResults<'tcx> {
@ -464,11 +464,15 @@ impl<'tcx> TypeckResults<'tcx> {
&self.coercion_casts
}
pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<FieldIdx>)> {
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<FieldIdx>)> {
pub fn offset_of_data_mut(
&mut self,
) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
}
}

View File

@ -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 }
}

View File

@ -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().map(|f| f.index()))
.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))

View File

@ -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)?;

View File

@ -257,10 +257,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
let mut current_ty = container;
for &index in indices {
for &(variant, field) in indices {
match current_ty.kind() {
ty::Adt(def, subst) => {
let field = &def.non_enum_variant().fields[index];
let field = &def.variant(variant).fields[field];
self.insert_def_id(field.did);
let field_ty = field.ty(self.tcx, subst);
@ -271,7 +271,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
// but we may need to mark subfields
ty::Tuple(tys) => {
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"),
}

View File

@ -649,6 +649,13 @@ impl<'tcx> Stable<'tcx> for FieldIdx {
}
}
impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) {
type T = (usize, usize);
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
(self.0.as_usize(), self.1.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 {

View File

@ -250,14 +250,17 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Ty::is_transparent(self)
}
pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size
pub fn offset_of_subfield<C, I>(self, cx: &C, indices: I) -> Size
where
Ty: TyAbiInterface<'a, C>,
I: Iterator<Item = (VariantIdx, FieldIdx)>,
{
let mut layout = self;
let mut offset = Size::ZERO;
for index in indices {
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!(

View File

@ -516,7 +516,7 @@ pub enum NullOp {
/// Returns the minimum alignment of a type.
AlignOf,
/// Returns the offset of a field.
OffsetOf(Vec<FieldIdx>),
OffsetOf(Vec<(VariantIdx, FieldIdx)>),
}
impl Operand {

View File

@ -1292,11 +1292,15 @@ impl<T> 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, [subject to change and
/// platform-specific](https://doc.rust-lang.org/reference/type-layout.html).
///
/// # Examples
///
@ -1324,6 +1328,9 @@ impl<T> SizedTypeProperties for T {}
/// struct NestedB(u8);
///
/// 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")]
#[allow_internal_unstable(builtin_syntax, hint_must_use)]

View File

@ -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, [(0, 0)]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
@ -37,7 +52,7 @@
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _4 = OffsetOf(Alpha, [(0, 1)]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(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, [(0, 2), (0, 0)]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(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, [(0, 2), (0, 1)]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
@ -65,7 +80,40 @@
bb4: {
StorageDead(_8);
StorageLive(_9);
StorageLive(_10);
- _10 = OffsetOf(Epsilon, [(0, 0)]);
- _9 = must_use::<usize>(move _10) -> [return: bb5, unwind unreachable];
+ _10 = const 1_usize;
+ _9 = must_use::<usize>(const 1_usize) -> [return: bb5, unwind unreachable];
}
bb5: {
StorageDead(_10);
StorageLive(_11);
StorageLive(_12);
- _12 = OffsetOf(Epsilon, [(0, 1)]);
- _11 = must_use::<usize>(move _12) -> [return: bb6, unwind unreachable];
+ _12 = const 2_usize;
+ _11 = must_use::<usize>(const 2_usize) -> [return: bb6, unwind unreachable];
}
bb6: {
StorageDead(_12);
StorageLive(_13);
StorageLive(_14);
- _14 = OffsetOf(Epsilon, [(2, 0)]);
- _13 = must_use::<usize>(move _14) -> [return: bb7, unwind unreachable];
+ _14 = const 4_usize;
+ _13 = must_use::<usize>(const 4_usize) -> [return: bb7, unwind unreachable];
}
bb7: {
StorageDead(_14);
_0 = const ();
StorageDead(_13);
StorageDead(_11);
StorageDead(_9);
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);

View File

@ -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, [(0, 0)]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
@ -37,7 +52,7 @@
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
- _4 = OffsetOf(Alpha, [1]);
- _4 = OffsetOf(Alpha, [(0, 1)]);
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(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, [(0, 2), (0, 0)]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(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, [(0, 2), (0, 1)]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
@ -65,7 +80,40 @@
bb4: {
StorageDead(_8);
StorageLive(_9);
StorageLive(_10);
- _10 = OffsetOf(Epsilon, [(0, 0)]);
- _9 = must_use::<usize>(move _10) -> [return: bb5, unwind continue];
+ _10 = const 1_usize;
+ _9 = must_use::<usize>(const 1_usize) -> [return: bb5, unwind continue];
}
bb5: {
StorageDead(_10);
StorageLive(_11);
StorageLive(_12);
- _12 = OffsetOf(Epsilon, [(0, 1)]);
- _11 = must_use::<usize>(move _12) -> [return: bb6, unwind continue];
+ _12 = const 2_usize;
+ _11 = must_use::<usize>(const 2_usize) -> [return: bb6, unwind continue];
}
bb6: {
StorageDead(_12);
StorageLive(_13);
StorageLive(_14);
- _14 = OffsetOf(Epsilon, [(2, 0)]);
- _13 = must_use::<usize>(move _14) -> [return: bb7, unwind continue];
+ _14 = const 4_usize;
+ _13 = must_use::<usize>(const 4_usize) -> [return: bb7, unwind continue];
}
bb7: {
StorageDead(_14);
_0 = const ();
StorageDead(_13);
StorageDead(_11);
StorageDead(_9);
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);

View File

@ -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<T>, [0]);
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
}
@ -35,7 +50,7 @@
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
_4 = OffsetOf(Gamma<T>, [1]);
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
}
@ -43,7 +58,7 @@
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
_6 = OffsetOf(Delta<T>, [1]);
_6 = OffsetOf(Delta<T>, [(0, 1)]);
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
}
@ -51,13 +66,40 @@
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
_8 = OffsetOf(Delta<T>, [2]);
_8 = OffsetOf(Delta<T>, [(0, 2)]);
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
}
bb4: {
StorageDead(_8);
StorageLive(_9);
StorageLive(_10);
_10 = OffsetOf(Zeta<T>, [(0, 0)]);
_9 = must_use::<usize>(move _10) -> [return: bb5, unwind unreachable];
}
bb5: {
StorageDead(_10);
StorageLive(_11);
StorageLive(_12);
_12 = OffsetOf(Zeta<T>, [(0, 1)]);
_11 = must_use::<usize>(move _12) -> [return: bb6, unwind unreachable];
}
bb6: {
StorageDead(_12);
StorageLive(_13);
StorageLive(_14);
_14 = OffsetOf(Zeta<T>, [(1, 0)]);
_13 = must_use::<usize>(move _14) -> [return: bb7, unwind unreachable];
}
bb7: {
StorageDead(_14);
_0 = const ();
StorageDead(_13);
StorageDead(_11);
StorageDead(_9);
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);

View File

@ -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<T>, [0]);
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
}
@ -35,7 +50,7 @@
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
_4 = OffsetOf(Gamma<T>, [1]);
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
}
@ -43,7 +58,7 @@
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
_6 = OffsetOf(Delta<T>, [1]);
_6 = OffsetOf(Delta<T>, [(0, 1)]);
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
}
@ -51,13 +66,40 @@
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
_8 = OffsetOf(Delta<T>, [2]);
_8 = OffsetOf(Delta<T>, [(0, 2)]);
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
}
bb4: {
StorageDead(_8);
StorageLive(_9);
StorageLive(_10);
_10 = OffsetOf(Zeta<T>, [(0, 0)]);
_9 = must_use::<usize>(move _10) -> [return: bb5, unwind continue];
}
bb5: {
StorageDead(_10);
StorageLive(_11);
StorageLive(_12);
_12 = OffsetOf(Zeta<T>, [(0, 1)]);
_11 = must_use::<usize>(move _12) -> [return: bb6, unwind continue];
}
bb6: {
StorageDead(_12);
StorageLive(_13);
StorageLive(_14);
_14 = OffsetOf(Zeta<T>, [(1, 0)]);
_13 = must_use::<usize>(move _14) -> [return: bb7, unwind continue];
}
bb7: {
StorageDead(_14);
_0 = const ();
StorageDead(_13);
StorageDead(_11);
StorageDead(_9);
StorageDead(_7);
StorageDead(_5);
StorageDead(_3);

View File

@ -28,12 +28,26 @@ struct Delta<T> {
y: u16,
}
enum Epsilon {
A(u8, u16),
B,
C { c: u32 }
}
enum Zeta<T> {
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<T>() {
let gy = offset_of!(Gamma<T>, y);
let dx = offset_of!(Delta<T>, x);
let dy = offset_of!(Delta<T>, y);
let zA0 = offset_of!(Zeta<T>, A.0);
let zA1 = offset_of!(Zeta<T>, A.1);
let zB = offset_of!(Zeta<T>, B.0);
}
fn main() {

View File

@ -27,7 +27,7 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _2 = OffsetOf(Alpha, [(0, 0)]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(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::<usize>(move _4) -> [return: bb2, unwind unreachable];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(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::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(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::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];

View File

@ -27,7 +27,7 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = OffsetOf(Alpha, [0]);
- _2 = OffsetOf(Alpha, [(0, 0)]);
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
+ _2 = const 4_usize;
+ _1 = must_use::<usize>(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::<usize>(move _4) -> [return: bb2, unwind continue];
+ _4 = const 0_usize;
+ _3 = must_use::<usize>(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::<usize>(move _6) -> [return: bb3, unwind continue];
+ _6 = const 2_usize;
+ _5 = must_use::<usize>(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::<usize>(move _8) -> [return: bb4, unwind continue];
+ _8 = const 3_usize;
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];

View File

@ -27,7 +27,7 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = OffsetOf(Gamma<T>, [0]);
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
}
@ -35,7 +35,7 @@
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
_4 = OffsetOf(Gamma<T>, [1]);
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
}
@ -43,7 +43,7 @@
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Delta<T>, [1]);
- _6 = OffsetOf(Delta<T>, [(0, 1)]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
+ _6 = const 0_usize;
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind unreachable];
@ -53,7 +53,7 @@
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Delta<T>, [2]);
- _8 = OffsetOf(Delta<T>, [(0, 2)]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
+ _8 = const 2_usize;
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind unreachable];

View File

@ -27,7 +27,7 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
_2 = OffsetOf(Gamma<T>, [0]);
_2 = OffsetOf(Gamma<T>, [(0, 0)]);
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
}
@ -35,7 +35,7 @@
StorageDead(_2);
StorageLive(_3);
StorageLive(_4);
_4 = OffsetOf(Gamma<T>, [1]);
_4 = OffsetOf(Gamma<T>, [(0, 1)]);
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
}
@ -43,7 +43,7 @@
StorageDead(_4);
StorageLive(_5);
StorageLive(_6);
- _6 = OffsetOf(Delta<T>, [1]);
- _6 = OffsetOf(Delta<T>, [(0, 1)]);
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
+ _6 = const 0_usize;
+ _5 = must_use::<usize>(const 0_usize) -> [return: bb3, unwind continue];
@ -53,7 +53,7 @@
StorageDead(_6);
StorageLive(_7);
StorageLive(_8);
- _8 = OffsetOf(Delta<T>, [2]);
- _8 = OffsetOf(Delta<T>, [(0, 2)]);
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
+ _8 = const 2_usize;
+ _7 = must_use::<usize>(const 2_usize) -> [return: bb4, unwind continue];

View File

@ -9,5 +9,10 @@ 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);
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
}

View File

@ -7,13 +7,41 @@ 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[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
|
LL | offset_of!(Alpha, Two.0);
| ^^^
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...
Some errors have detailed explanations: E0573, E0609.
For more information about an error, try `rustc --explain E0573`.
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 6 previous errors
Some errors have detailed explanations: E0412, E0573, E0599, E0609, E0795.
For more information about an error, try `rustc --explain E0412`.

View File

@ -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);
}

View File

@ -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`.