Support enum variants in offset_of!
This commit is contained in:
parent
9d83ac2179
commit
e936416a8d
27 changed files with 472 additions and 75 deletions
|
@ -1107,6 +1107,39 @@ impl Scalar {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This struct is generic over the FieldIdx for rust-analyzer usage.
|
// 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.
|
/// Describes how the fields of a type are located in memory.
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||||
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
|
||||||
|
|
|
@ -766,7 +766,7 @@ fn codegen_stmt<'tcx>(
|
||||||
NullOp::SizeOf => layout.size.bytes(),
|
NullOp::SizeOf => layout.size.bytes(),
|
||||||
NullOp::AlignOf => layout.align.abi.bytes(),
|
NullOp::AlignOf => layout.align.abi.bytes(),
|
||||||
NullOp::OffsetOf(fields) => {
|
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(
|
let val = CValue::by_val(
|
||||||
|
|
|
@ -680,7 +680,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
layout.align.abi.bytes()
|
layout.align.abi.bytes()
|
||||||
}
|
}
|
||||||
mir::NullOp::OffsetOf(fields) => {
|
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);
|
let val = bx.cx().const_usize(val);
|
||||||
|
|
|
@ -275,7 +275,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
mir::NullOp::SizeOf => layout.size.bytes(),
|
mir::NullOp::SizeOf => layout.size.bytes(),
|
||||||
mir::NullOp::AlignOf => layout.align.abi.bytes(),
|
mir::NullOp::AlignOf => layout.align.abi.bytes(),
|
||||||
mir::NullOp::OffsetOf(fields) => {
|
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)?;
|
self.write_scalar(Scalar::from_target_usize(val, self), &dest)?;
|
||||||
|
|
|
@ -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| {
|
let fail_out_of_bounds = |this: &mut Self, location, field, ty| {
|
||||||
this.fail(location, format!("Out of bounds field {field:?} for {ty:?}"));
|
this.fail(location, format!("Out of bounds field {field:?} for {ty:?}"));
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut current_ty = *container;
|
let mut current_ty = *container;
|
||||||
|
let mut indices = indices.into_iter();
|
||||||
|
|
||||||
for field in fields.iter() {
|
use rustc_target::abi::OffsetOfIdx::*;
|
||||||
match current_ty.kind() {
|
|
||||||
ty::Tuple(fields) => {
|
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 {
|
let Some(&f_ty) = fields.get(field.as_usize()) else {
|
||||||
fail_out_of_bounds(self, location, field, current_ty);
|
fail_out_of_bounds(self, location, field, current_ty);
|
||||||
return;
|
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);
|
current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
|
||||||
}
|
}
|
||||||
ty::Adt(adt_def, args) => {
|
(ty::Adt(adt_def, args), Field(field)) if !adt_def.is_enum() => {
|
||||||
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(
|
self.fail(
|
||||||
location,
|
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;
|
return;
|
||||||
}
|
};
|
||||||
|
let Some(field) = adt_def.variant(variant).fields.get(field) else {
|
||||||
let Some(field) = adt_def.non_enum_variant().fields.get(field) else {
|
|
||||||
fail_out_of_bounds(self, location, field, current_ty);
|
fail_out_of_bounds(self, location, field, current_ty);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -1093,7 +1104,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
_ => {
|
_ => {
|
||||||
self.fail(
|
self.fail(
|
||||||
location,
|
location,
|
||||||
format!("Cannot get field offset from non-adt type {current_ty:?}"),
|
format!("Cannot get offset {index:?} from type {current_ty:?}"),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,6 +514,7 @@ E0791: include_str!("./error_codes/E0791.md"),
|
||||||
E0792: include_str!("./error_codes/E0792.md"),
|
E0792: include_str!("./error_codes/E0792.md"),
|
||||||
E0793: include_str!("./error_codes/E0793.md"),
|
E0793: include_str!("./error_codes/E0793.md"),
|
||||||
E0794: include_str!("./error_codes/E0794.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
|
// Undocumented removed error codes. Note that many removed error codes are kept in the list above
|
||||||
|
|
28
compiler/rustc_error_codes/src/error_codes/E0795.md
Normal file
28
compiler/rustc_error_codes/src/error_codes/E0795.md
Normal 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.
|
|
@ -3103,16 +3103,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fields: &[Ident],
|
fields: &[Ident],
|
||||||
expr: &'tcx hir::Expr<'tcx>,
|
expr: &'tcx hir::Expr<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
|
use rustc_target::abi::OffsetOfIdx::*;
|
||||||
|
|
||||||
let container = self.to_ty(container).normalized;
|
let container = self.to_ty(container).normalized;
|
||||||
|
|
||||||
let mut field_indices = Vec::with_capacity(fields.len());
|
let mut field_indices = Vec::with_capacity(fields.len());
|
||||||
let mut current_container = container;
|
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);
|
let container = self.structurally_resolve_type(expr.span, current_container);
|
||||||
|
|
||||||
match container.kind() {
|
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 block = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
|
||||||
let (ident, def_scope) =
|
let (ident, def_scope) =
|
||||||
self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
|
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
|
// Save the index of all fields regardless of their visibility in case
|
||||||
// of error recovery.
|
// of error recovery.
|
||||||
field_indices.push(index);
|
field_indices.push(Field(index));
|
||||||
current_container = field_ty;
|
current_container = field_ty;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -3149,7 +3201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.require_type_is_sized(ty, expr.span, traits::MiscObligation);
|
self.require_type_is_sized(ty, expr.span, traits::MiscObligation);
|
||||||
}
|
}
|
||||||
if let Some(&field_ty) = tys.get(index) {
|
if let Some(&field_ty) = tys.get(index) {
|
||||||
field_indices.push(index.into());
|
field_indices.push(Field(index.into()));
|
||||||
current_container = field_ty;
|
current_container = field_ty;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -17,7 +17,7 @@ use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{self as hir};
|
use rustc_hir::{self as hir};
|
||||||
use rustc_hir::{self, CoroutineKind};
|
use rustc_hir::{self, CoroutineKind};
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_target::abi::{FieldIdx, VariantIdx};
|
use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx};
|
||||||
|
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
|
@ -1354,7 +1354,7 @@ pub enum NullOp<'tcx> {
|
||||||
/// Returns the minimum alignment of a type
|
/// Returns the minimum alignment of a type
|
||||||
AlignOf,
|
AlignOf,
|
||||||
/// Returns the offset of a field
|
/// Returns the offset of a field
|
||||||
OffsetOf(&'tcx List<FieldIdx>),
|
OffsetOf(&'tcx List<OffsetOfIdx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
|
|
@ -25,7 +25,8 @@ use rustc_middle::ty::{
|
||||||
};
|
};
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP};
|
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 rustc_target::asm::InlineAsmRegOrRegClass;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
@ -490,7 +491,7 @@ pub enum ExprKind<'tcx> {
|
||||||
/// Field offset (`offset_of!`)
|
/// Field offset (`offset_of!`)
|
||||||
OffsetOf {
|
OffsetOf {
|
||||||
container: Ty<'tcx>,
|
container: Ty<'tcx>,
|
||||||
fields: &'tcx List<FieldIdx>,
|
fields: &'tcx List<OffsetOfIdx>,
|
||||||
},
|
},
|
||||||
/// An expression taking a reference to a thread local.
|
/// An expression taking a reference to a thread local.
|
||||||
ThreadLocalRef(DefId),
|
ThreadLocalRef(DefId),
|
||||||
|
|
|
@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_serialize::{Decodable, Encodable};
|
use rustc_serialize::{Decodable, Encodable};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::FieldIdx;
|
use rustc_target::abi::{FieldIdx, OffsetOfIdx};
|
||||||
pub use rustc_type_ir::{TyDecoder, TyEncoder};
|
pub use rustc_type_ir::{TyDecoder, TyEncoder};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::intrinsics;
|
use std::intrinsics;
|
||||||
|
@ -414,6 +414,15 @@ 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<OffsetOfIdx> {
|
||||||
|
fn decode(decoder: &mut D) -> &'tcx Self {
|
||||||
|
let len = decoder.read_usize();
|
||||||
|
decoder
|
||||||
|
.interner()
|
||||||
|
.mk_offset_of_from_iter((0..len).map::<OffsetOfIdx, _>(|_| Decodable::decode(decoder)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl_decodable_via_ref! {
|
impl_decodable_via_ref! {
|
||||||
&'tcx ty::TypeckResults<'tcx>,
|
&'tcx ty::TypeckResults<'tcx>,
|
||||||
&'tcx ty::List<Ty<'tcx>>,
|
&'tcx ty::List<Ty<'tcx>>,
|
||||||
|
@ -426,6 +435,7 @@ impl_decodable_via_ref! {
|
||||||
&'tcx ty::List<ty::BoundVariableKind>,
|
&'tcx ty::List<ty::BoundVariableKind>,
|
||||||
&'tcx ty::List<ty::Clause<'tcx>>,
|
&'tcx ty::List<ty::Clause<'tcx>>,
|
||||||
&'tcx ty::List<FieldIdx>,
|
&'tcx ty::List<FieldIdx>,
|
||||||
|
&'tcx ty::List<OffsetOfIdx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
|
@ -63,7 +63,7 @@ use rustc_session::{Limit, MetadataKind, Session};
|
||||||
use rustc_span::def_id::{DefPathHash, StableCrateId};
|
use rustc_span::def_id::{DefPathHash, StableCrateId};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
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_target::spec::abi;
|
||||||
use rustc_type_ir::TyKind::*;
|
use rustc_type_ir::TyKind::*;
|
||||||
use rustc_type_ir::WithCachedTypeInfo;
|
use rustc_type_ir::WithCachedTypeInfo;
|
||||||
|
@ -163,6 +163,7 @@ pub struct CtxtInterners<'tcx> {
|
||||||
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
|
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
|
||||||
fields: InternedSet<'tcx, List<FieldIdx>>,
|
fields: InternedSet<'tcx, List<FieldIdx>>,
|
||||||
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
|
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
|
||||||
|
offset_of: InternedSet<'tcx, List<OffsetOfIdx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> CtxtInterners<'tcx> {
|
impl<'tcx> CtxtInterners<'tcx> {
|
||||||
|
@ -189,6 +190,7 @@ impl<'tcx> CtxtInterners<'tcx> {
|
||||||
predefined_opaques_in_body: Default::default(),
|
predefined_opaques_in_body: Default::default(),
|
||||||
fields: Default::default(),
|
fields: Default::default(),
|
||||||
local_def_ids: 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),
|
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
|
||||||
fields: pub mk_fields(FieldIdx),
|
fields: pub mk_fields(FieldIdx),
|
||||||
local_def_ids: intern_local_def_ids(LocalDefId),
|
local_def_ids: intern_local_def_ids(LocalDefId),
|
||||||
|
offset_of: pub mk_offset_of(OffsetOfIdx),
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
@ -1914,6 +1917,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
T::collect_and_apply(iter, |xs| self.mk_fields(xs))
|
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<OffsetOfIdx, &'tcx List<OffsetOfIdx>>,
|
||||||
|
{
|
||||||
|
T::collect_and_apply(iter, |xs| self.mk_offset_of(xs))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mk_args_trait(
|
pub fn mk_args_trait(
|
||||||
self,
|
self,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
|
|
@ -24,7 +24,7 @@ use rustc_macros::HashStable;
|
||||||
use rustc_middle::mir::FakeReadCause;
|
use rustc_middle::mir::FakeReadCause;
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::Span;
|
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 std::{collections::hash_map::Entry, hash::Hash, iter};
|
||||||
|
|
||||||
use super::RvalueScopes;
|
use super::RvalueScopes;
|
||||||
|
@ -205,7 +205,7 @@ pub struct TypeckResults<'tcx> {
|
||||||
pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>,
|
pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>,
|
||||||
|
|
||||||
/// Container types and field indices of `offset_of!` expressions
|
/// Container types and field indices of `offset_of!` expressions
|
||||||
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>,
|
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<OffsetOfIdx>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeckResults<'tcx> {
|
impl<'tcx> TypeckResults<'tcx> {
|
||||||
|
@ -464,11 +464,13 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
&self.coercion_casts
|
&self.coercion_casts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<FieldIdx>)> {
|
pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<OffsetOfIdx>)> {
|
||||||
LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data }
|
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<OffsetOfIdx>)> {
|
||||||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
|
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -670,7 +670,7 @@ impl<'tcx> Cx<'tcx> {
|
||||||
hir::ExprKind::OffsetOf(_, _) => {
|
hir::ExprKind::OffsetOf(_, _) => {
|
||||||
let data = self.typeck_results.offset_of_data();
|
let data = self.typeck_results.offset_of_data();
|
||||||
let &(container, ref indices) = data.get(expr.hir_id).unwrap();
|
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 }
|
ExprKind::OffsetOf { container, fields }
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,7 +287,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
||||||
NullOp::SizeOf if layout.is_sized() => layout.size.bytes(),
|
NullOp::SizeOf if layout.is_sized() => layout.size.bytes(),
|
||||||
NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(),
|
NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(),
|
||||||
NullOp::OffsetOf(fields) => layout
|
NullOp::OffsetOf(fields) => layout
|
||||||
.offset_of_subfield(&self.ecx, fields.iter().map(|f| f.index()))
|
.offset_of_subfield(&self.ecx, fields.iter())
|
||||||
.bytes(),
|
.bytes(),
|
||||||
_ => return ValueOrPlace::Value(FlatSet::Top),
|
_ => return ValueOrPlace::Value(FlatSet::Top),
|
||||||
};
|
};
|
||||||
|
|
|
@ -248,6 +248,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'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 data = self.typeck_results().offset_of_data();
|
||||||
let &(container, ref indices) =
|
let &(container, ref indices) =
|
||||||
data.get(expr.hir_id).expect("no offset_of_data for offset_of");
|
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 param_env = self.tcx.param_env(body_did);
|
||||||
|
|
||||||
let mut current_ty = container;
|
let mut current_ty = container;
|
||||||
|
let mut indices = indices.into_iter();
|
||||||
|
|
||||||
for &index in indices {
|
while let Some(&index) = indices.next() {
|
||||||
match current_ty.kind() {
|
match (current_ty.kind(), index) {
|
||||||
ty::Adt(def, subst) => {
|
(ty::Adt(def, subst), Field(field)) if !def.is_enum() => {
|
||||||
let field = &def.non_enum_variant().fields[index];
|
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")
|
||||||
|
};
|
||||||
|
let field = &def.variant(variant).fields[field];
|
||||||
|
|
||||||
self.insert_def_id(field.did);
|
self.insert_def_id(field.did);
|
||||||
let field_ty = field.ty(self.tcx, subst);
|
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,
|
// we don't need to mark tuple fields as live,
|
||||||
// but we may need to mark subfields
|
// but we may need to mark subfields
|
||||||
ty::Tuple(tys) => {
|
(ty::Tuple(tys), Field(field)) => {
|
||||||
current_ty =
|
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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use rustc_middle::mir::interpret::{alloc_range, AllocId};
|
||||||
use rustc_middle::mir::mono::MonoItem;
|
use rustc_middle::mir::mono::MonoItem;
|
||||||
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance};
|
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt, Variance};
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
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::mono::InstanceDef;
|
||||||
use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
|
use stable_mir::mir::{Body, CopyNonOverlapping, Statement, UserTypeProjection, VariantIdx};
|
||||||
use stable_mir::ty::{
|
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> {
|
impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
|
||||||
type T = stable_mir::mir::Operand;
|
type T = stable_mir::mir::Operand;
|
||||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
|
|
|
@ -250,7 +250,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
Ty::is_transparent(self)
|
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>(self, cx: &C, indices: impl Iterator<Item = OffsetOfIdx>) -> Size
|
||||||
where
|
where
|
||||||
Ty: TyAbiInterface<'a, C>,
|
Ty: TyAbiInterface<'a, C>,
|
||||||
{
|
{
|
||||||
|
@ -258,13 +258,21 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
let mut offset = Size::ZERO;
|
let mut offset = Size::ZERO;
|
||||||
|
|
||||||
for index in indices {
|
for index in indices {
|
||||||
offset += layout.fields.offset(index);
|
match index {
|
||||||
layout = layout.field(cx, index);
|
OffsetOfIdx::Field(field) => {
|
||||||
assert!(
|
let index = field.index();
|
||||||
layout.is_sized(),
|
offset += layout.fields.offset(index);
|
||||||
"offset of unsized field (type {:?}) cannot be computed statically",
|
layout = layout.field(cx, index);
|
||||||
layout.ty
|
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
|
offset
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
let mut _4: usize;
|
let mut _4: usize;
|
||||||
let mut _6: usize;
|
let mut _6: usize;
|
||||||
let mut _8: usize;
|
let mut _8: usize;
|
||||||
|
let mut _10: usize;
|
||||||
|
let mut _12: usize;
|
||||||
|
let mut _14: usize;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
let _3: usize;
|
let _3: usize;
|
||||||
|
@ -19,6 +22,18 @@
|
||||||
let _7: usize;
|
let _7: usize;
|
||||||
scope 4 {
|
scope 4 {
|
||||||
debug z1 => _7;
|
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: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
- _2 = OffsetOf(Alpha, [0]);
|
- _2 = OffsetOf(Alpha, [Field(0)]);
|
||||||
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
||||||
+ _2 = const 4_usize;
|
+ _2 = const 4_usize;
|
||||||
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
|
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind unreachable];
|
||||||
|
@ -37,7 +52,7 @@
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
- _4 = OffsetOf(Alpha, [1]);
|
- _4 = OffsetOf(Alpha, [Field(1)]);
|
||||||
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
||||||
+ _4 = const 0_usize;
|
+ _4 = const 0_usize;
|
||||||
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
|
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind unreachable];
|
||||||
|
@ -47,7 +62,7 @@
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
- _6 = OffsetOf(Alpha, [2, 0]);
|
- _6 = OffsetOf(Alpha, [Field(2), Field(0)]);
|
||||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
||||||
+ _6 = const 2_usize;
|
+ _6 = const 2_usize;
|
||||||
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
|
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind unreachable];
|
||||||
|
@ -57,7 +72,7 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
- _8 = OffsetOf(Alpha, [2, 1]);
|
- _8 = OffsetOf(Alpha, [Field(2), Field(1)]);
|
||||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
||||||
+ _8 = const 3_usize;
|
+ _8 = const 3_usize;
|
||||||
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
|
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind unreachable];
|
||||||
|
@ -65,7 +80,40 @@
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
StorageLive(_10);
|
||||||
|
- _10 = OffsetOf(Epsilon, [Variant(0), Field(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, [Variant(0), Field(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, [Variant(2), Field(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 ();
|
_0 = const ();
|
||||||
|
StorageDead(_13);
|
||||||
|
StorageDead(_11);
|
||||||
|
StorageDead(_9);
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
let mut _4: usize;
|
let mut _4: usize;
|
||||||
let mut _6: usize;
|
let mut _6: usize;
|
||||||
let mut _8: usize;
|
let mut _8: usize;
|
||||||
|
let mut _10: usize;
|
||||||
|
let mut _12: usize;
|
||||||
|
let mut _14: usize;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
let _3: usize;
|
let _3: usize;
|
||||||
|
@ -19,6 +22,18 @@
|
||||||
let _7: usize;
|
let _7: usize;
|
||||||
scope 4 {
|
scope 4 {
|
||||||
debug z1 => _7;
|
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: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
- _2 = OffsetOf(Alpha, [0]);
|
- _2 = OffsetOf(Alpha, [Field(0)]);
|
||||||
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
- _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
||||||
+ _2 = const 4_usize;
|
+ _2 = const 4_usize;
|
||||||
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
|
+ _1 = must_use::<usize>(const 4_usize) -> [return: bb1, unwind continue];
|
||||||
|
@ -37,7 +52,7 @@
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
- _4 = OffsetOf(Alpha, [1]);
|
- _4 = OffsetOf(Alpha, [Field(1)]);
|
||||||
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
- _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
||||||
+ _4 = const 0_usize;
|
+ _4 = const 0_usize;
|
||||||
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
|
+ _3 = must_use::<usize>(const 0_usize) -> [return: bb2, unwind continue];
|
||||||
|
@ -47,7 +62,7 @@
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
- _6 = OffsetOf(Alpha, [2, 0]);
|
- _6 = OffsetOf(Alpha, [Field(2), Field(0)]);
|
||||||
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
- _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
||||||
+ _6 = const 2_usize;
|
+ _6 = const 2_usize;
|
||||||
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
|
+ _5 = must_use::<usize>(const 2_usize) -> [return: bb3, unwind continue];
|
||||||
|
@ -57,7 +72,7 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
- _8 = OffsetOf(Alpha, [2, 1]);
|
- _8 = OffsetOf(Alpha, [Field(2), Field(1)]);
|
||||||
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
- _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
||||||
+ _8 = const 3_usize;
|
+ _8 = const 3_usize;
|
||||||
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
|
+ _7 = must_use::<usize>(const 3_usize) -> [return: bb4, unwind continue];
|
||||||
|
@ -65,7 +80,40 @@
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
StorageLive(_10);
|
||||||
|
- _10 = OffsetOf(Epsilon, [Variant(0), Field(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, [Variant(0), Field(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, [Variant(2), Field(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 ();
|
_0 = const ();
|
||||||
|
StorageDead(_13);
|
||||||
|
StorageDead(_11);
|
||||||
|
StorageDead(_9);
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
let mut _4: usize;
|
let mut _4: usize;
|
||||||
let mut _6: usize;
|
let mut _6: usize;
|
||||||
let mut _8: usize;
|
let mut _8: usize;
|
||||||
|
let mut _10: usize;
|
||||||
|
let mut _12: usize;
|
||||||
|
let mut _14: usize;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug gx => _1;
|
debug gx => _1;
|
||||||
let _3: usize;
|
let _3: usize;
|
||||||
|
@ -19,6 +22,18 @@
|
||||||
let _7: usize;
|
let _7: usize;
|
||||||
scope 4 {
|
scope 4 {
|
||||||
debug dy => _7;
|
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: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = OffsetOf(Gamma<T>, [0]);
|
_2 = OffsetOf(Gamma<T>, [Field(0)]);
|
||||||
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +50,7 @@
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = OffsetOf(Gamma<T>, [1]);
|
_4 = OffsetOf(Gamma<T>, [Field(1)]);
|
||||||
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +58,7 @@
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = OffsetOf(Delta<T>, [1]);
|
_6 = OffsetOf(Delta<T>, [Field(1)]);
|
||||||
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,13 +66,40 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = OffsetOf(Delta<T>, [2]);
|
_8 = OffsetOf(Delta<T>, [Field(2)]);
|
||||||
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind unreachable];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
StorageLive(_10);
|
||||||
|
_10 = OffsetOf(Zeta<T>, [Variant(0), Field(0)]);
|
||||||
|
_9 = must_use::<usize>(move _10) -> [return: bb5, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
StorageDead(_10);
|
||||||
|
StorageLive(_11);
|
||||||
|
StorageLive(_12);
|
||||||
|
_12 = OffsetOf(Zeta<T>, [Variant(0), Field(1)]);
|
||||||
|
_11 = must_use::<usize>(move _12) -> [return: bb6, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
StorageDead(_12);
|
||||||
|
StorageLive(_13);
|
||||||
|
StorageLive(_14);
|
||||||
|
_14 = OffsetOf(Zeta<T>, [Variant(1), Field(0)]);
|
||||||
|
_13 = must_use::<usize>(move _14) -> [return: bb7, unwind unreachable];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
StorageDead(_14);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
|
StorageDead(_13);
|
||||||
|
StorageDead(_11);
|
||||||
|
StorageDead(_9);
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
let mut _4: usize;
|
let mut _4: usize;
|
||||||
let mut _6: usize;
|
let mut _6: usize;
|
||||||
let mut _8: usize;
|
let mut _8: usize;
|
||||||
|
let mut _10: usize;
|
||||||
|
let mut _12: usize;
|
||||||
|
let mut _14: usize;
|
||||||
scope 1 {
|
scope 1 {
|
||||||
debug gx => _1;
|
debug gx => _1;
|
||||||
let _3: usize;
|
let _3: usize;
|
||||||
|
@ -19,6 +22,18 @@
|
||||||
let _7: usize;
|
let _7: usize;
|
||||||
scope 4 {
|
scope 4 {
|
||||||
debug dy => _7;
|
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: {
|
bb0: {
|
||||||
StorageLive(_1);
|
StorageLive(_1);
|
||||||
StorageLive(_2);
|
StorageLive(_2);
|
||||||
_2 = OffsetOf(Gamma<T>, [0]);
|
_2 = OffsetOf(Gamma<T>, [Field(0)]);
|
||||||
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
_1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +50,7 @@
|
||||||
StorageDead(_2);
|
StorageDead(_2);
|
||||||
StorageLive(_3);
|
StorageLive(_3);
|
||||||
StorageLive(_4);
|
StorageLive(_4);
|
||||||
_4 = OffsetOf(Gamma<T>, [1]);
|
_4 = OffsetOf(Gamma<T>, [Field(1)]);
|
||||||
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
_3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +58,7 @@
|
||||||
StorageDead(_4);
|
StorageDead(_4);
|
||||||
StorageLive(_5);
|
StorageLive(_5);
|
||||||
StorageLive(_6);
|
StorageLive(_6);
|
||||||
_6 = OffsetOf(Delta<T>, [1]);
|
_6 = OffsetOf(Delta<T>, [Field(1)]);
|
||||||
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
_5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,13 +66,40 @@
|
||||||
StorageDead(_6);
|
StorageDead(_6);
|
||||||
StorageLive(_7);
|
StorageLive(_7);
|
||||||
StorageLive(_8);
|
StorageLive(_8);
|
||||||
_8 = OffsetOf(Delta<T>, [2]);
|
_8 = OffsetOf(Delta<T>, [Field(2)]);
|
||||||
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
_7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
|
||||||
}
|
}
|
||||||
|
|
||||||
bb4: {
|
bb4: {
|
||||||
StorageDead(_8);
|
StorageDead(_8);
|
||||||
|
StorageLive(_9);
|
||||||
|
StorageLive(_10);
|
||||||
|
_10 = OffsetOf(Zeta<T>, [Variant(0), Field(0)]);
|
||||||
|
_9 = must_use::<usize>(move _10) -> [return: bb5, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb5: {
|
||||||
|
StorageDead(_10);
|
||||||
|
StorageLive(_11);
|
||||||
|
StorageLive(_12);
|
||||||
|
_12 = OffsetOf(Zeta<T>, [Variant(0), Field(1)]);
|
||||||
|
_11 = must_use::<usize>(move _12) -> [return: bb6, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb6: {
|
||||||
|
StorageDead(_12);
|
||||||
|
StorageLive(_13);
|
||||||
|
StorageLive(_14);
|
||||||
|
_14 = OffsetOf(Zeta<T>, [Variant(1), Field(0)]);
|
||||||
|
_13 = must_use::<usize>(move _14) -> [return: bb7, unwind continue];
|
||||||
|
}
|
||||||
|
|
||||||
|
bb7: {
|
||||||
|
StorageDead(_14);
|
||||||
_0 = const ();
|
_0 = const ();
|
||||||
|
StorageDead(_13);
|
||||||
|
StorageDead(_11);
|
||||||
|
StorageDead(_9);
|
||||||
StorageDead(_7);
|
StorageDead(_7);
|
||||||
StorageDead(_5);
|
StorageDead(_5);
|
||||||
StorageDead(_3);
|
StorageDead(_3);
|
||||||
|
|
|
@ -28,12 +28,26 @@ struct Delta<T> {
|
||||||
y: u16,
|
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
|
// EMIT_MIR offset_of.concrete.ConstProp.diff
|
||||||
fn concrete() {
|
fn concrete() {
|
||||||
let x = offset_of!(Alpha, x);
|
let x = offset_of!(Alpha, x);
|
||||||
let y = offset_of!(Alpha, y);
|
let y = offset_of!(Alpha, y);
|
||||||
let z0 = offset_of!(Alpha, z.0);
|
let z0 = offset_of!(Alpha, z.0);
|
||||||
let z1 = offset_of!(Alpha, z.1);
|
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
|
// EMIT_MIR offset_of.generic.ConstProp.diff
|
||||||
|
@ -42,6 +56,9 @@ fn generic<T>() {
|
||||||
let gy = offset_of!(Gamma<T>, y);
|
let gy = offset_of!(Gamma<T>, y);
|
||||||
let dx = offset_of!(Delta<T>, x);
|
let dx = offset_of!(Delta<T>, x);
|
||||||
let dy = offset_of!(Delta<T>, y);
|
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() {
|
fn main() {
|
||||||
|
|
|
@ -9,5 +9,6 @@ enum Alpha {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
offset_of!(Alpha::One, 0); //~ ERROR expected type, found variant `Alpha::One`
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ LL | offset_of!(Alpha::One, 0);
|
||||||
| not a type
|
| not a type
|
||||||
| help: try using the variant's enum: `Alpha`
|
| 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
|
--> $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: 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`.
|
For more information about an error, try `rustc --explain E0573`.
|
||||||
|
|
|
@ -8,13 +8,20 @@ mod m {
|
||||||
pub public: u8,
|
pub public: u8,
|
||||||
private: u8,
|
private: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FooTuple(pub u8, u8);
|
pub struct FooTuple(pub u8, u8);
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Bar {
|
struct Bar {
|
||||||
pub public: u8,
|
pub public: u8,
|
||||||
private: u8,
|
private: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Baz {
|
||||||
|
Var1(Foo),
|
||||||
|
Var2(u64),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -25,4 +32,8 @@ fn main() {
|
||||||
offset_of!(m::Bar, public); //~ ERROR struct `Bar` is private
|
offset_of!(m::Bar, public); //~ ERROR struct `Bar` is private
|
||||||
offset_of!(m::Bar, private); //~ ERROR struct `Bar` is private
|
offset_of!(m::Bar, private); //~ ERROR struct `Bar` is private
|
||||||
//~| ERROR field `private` of 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,52 @@
|
||||||
error[E0603]: struct `Bar` is private
|
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);
|
LL | offset_of!(m::Bar, public);
|
||||||
| ^^^ private struct
|
| ^^^ private struct
|
||||||
|
|
|
|
||||||
note: the struct `Bar` is defined here
|
note: the struct `Bar` is defined here
|
||||||
--> $DIR/offset-of-private.rs:14:5
|
--> $DIR/offset-of-private.rs:16:5
|
||||||
|
|
|
|
||||||
LL | struct Bar {
|
LL | struct Bar {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error[E0603]: struct `Bar` is private
|
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);
|
LL | offset_of!(m::Bar, private);
|
||||||
| ^^^ private struct
|
| ^^^ private struct
|
||||||
|
|
|
|
||||||
note: the struct `Bar` is defined here
|
note: the struct `Bar` is defined here
|
||||||
--> $DIR/offset-of-private.rs:14:5
|
--> $DIR/offset-of-private.rs:16:5
|
||||||
|
|
|
|
||||||
LL | struct Bar {
|
LL | struct Bar {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error[E0616]: field `private` of struct `Foo` is private
|
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);
|
LL | offset_of!(m::Foo, private);
|
||||||
| ^^^^^^^ private field
|
| ^^^^^^^ private field
|
||||||
|
|
||||||
error[E0616]: field `1` of struct `FooTuple` is private
|
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);
|
LL | offset_of!(m::FooTuple, 1);
|
||||||
| ^ private field
|
| ^ private field
|
||||||
|
|
||||||
error[E0616]: field `private` of struct `Bar` is private
|
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);
|
LL | offset_of!(m::Bar, private);
|
||||||
| ^^^^^^^ private field
|
| ^^^^^^^ 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.
|
Some errors have detailed explanations: E0603, E0616.
|
||||||
For more information about an error, try `rustc --explain E0603`.
|
For more information about an error, try `rustc --explain E0603`.
|
||||||
|
|
Loading…
Add table
Reference in a new issue