Enums in offset_of: update based on est31, scottmcm & llogiq review
This commit is contained in:
parent
e936416a8d
commit
d995bd61e7
15 changed files with 150 additions and 140 deletions
|
@ -1133,13 +1133,6 @@ rustc_index::newtype_index! {
|
||||||
pub struct FieldIdx {}
|
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))]
|
||||||
|
|
|
@ -1062,13 +1062,17 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut current_ty = *container;
|
let mut current_ty = *container;
|
||||||
let mut indices = indices.into_iter();
|
|
||||||
|
|
||||||
use rustc_target::abi::OffsetOfIdx::*;
|
for (variant, field) in indices.iter() {
|
||||||
|
match current_ty.kind() {
|
||||||
while let Some(index) = indices.next() {
|
ty::Tuple(fields) => {
|
||||||
match (current_ty.kind(), index) {
|
if variant != FIRST_VARIANT {
|
||||||
(ty::Tuple(fields), Field(field)) => {
|
self.fail(
|
||||||
|
location,
|
||||||
|
format!("tried to get variant {variant:?} of tuple"),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
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;
|
||||||
|
@ -1076,23 +1080,7 @@ 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), Field(field)) if !adt_def.is_enum() => {
|
ty::Adt(adt_def, args) => {
|
||||||
let Some(field) = adt_def.non_enum_variant().fields.get(field) else {
|
|
||||||
fail_out_of_bounds(self, location, field, current_ty);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let f_ty = field.ty(self.tcx, args);
|
|
||||||
current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
|
|
||||||
}
|
|
||||||
(ty::Adt(adt_def, args), Variant(variant)) if adt_def.is_enum() => {
|
|
||||||
let Some(Field(field)) = indices.next() else {
|
|
||||||
self.fail(
|
|
||||||
location,
|
|
||||||
format!("enum variant must be followed by field index in offset_of; in {current_ty:?}"),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(field) = adt_def.variant(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);
|
fail_out_of_bounds(self, location, field, current_ty);
|
||||||
return;
|
return;
|
||||||
|
@ -1104,7 +1092,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
_ => {
|
_ => {
|
||||||
self.fail(
|
self.fail(
|
||||||
location,
|
location,
|
||||||
format!("Cannot get offset {index:?} from type {current_ty:?}"),
|
format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::hygiene::DesugaringKind;
|
use rustc_span::hygiene::DesugaringKind;
|
||||||
use rustc_span::source_map::{Span, Spanned};
|
use rustc_span::source_map::{Span, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
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_target::spec::abi::Abi::RustIntrinsic;
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||||
|
@ -3103,8 +3103,6 @@ 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());
|
||||||
|
@ -3120,10 +3118,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
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);
|
||||||
|
|
||||||
if let Some((index, variant)) = container_def.variants()
|
let Some((index, variant)) = container_def.variants()
|
||||||
.iter_enumerated()
|
.iter_enumerated()
|
||||||
.find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident)
|
.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 Some(&subfield) = fields.next() else {
|
||||||
let mut err = type_error_struct!(
|
let mut err = type_error_struct!(
|
||||||
self.tcx().sess,
|
self.tcx().sess,
|
||||||
|
@ -3139,10 +3147,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
let (subident, sub_def_scope) =
|
let (subident, sub_def_scope) =
|
||||||
self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block);
|
self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block);
|
||||||
|
|
||||||
if let Some((subindex, field)) = variant.fields
|
let Some((subindex, field)) = variant.fields
|
||||||
.iter_enumerated()
|
.iter_enumerated()
|
||||||
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident)
|
.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);
|
let field_ty = self.field_ty(expr.span, field, args);
|
||||||
|
|
||||||
// FIXME: DSTs with static alignment should be allowed
|
// FIXME: DSTs with static alignment should be allowed
|
||||||
|
@ -3156,14 +3176,11 @@ 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(Variant(index));
|
field_indices.push((index, subindex));
|
||||||
field_indices.push(Field(subindex));
|
|
||||||
current_container = field_ty;
|
current_container = field_ty;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::Adt(container_def, args) => {
|
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) =
|
||||||
|
@ -3187,7 +3204,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(Field(index));
|
field_indices.push((FIRST_VARIANT, index));
|
||||||
current_container = field_ty;
|
current_container = field_ty;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -3201,7 +3218,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(Field(index.into()));
|
field_indices.push((FIRST_VARIANT, 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, OffsetOfIdx, VariantIdx};
|
use rustc_target::abi::{FieldIdx, 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<OffsetOfIdx>),
|
OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
|
|
@ -26,7 +26,7 @@ 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_span::{sym, Span, Symbol, DUMMY_SP};
|
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
|
||||||
use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx};
|
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
@ -491,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<OffsetOfIdx>,
|
fields: &'tcx List<(VariantIdx, FieldIdx)>,
|
||||||
},
|
},
|
||||||
/// 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, OffsetOfIdx};
|
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||||
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,12 +414,14 @@ 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> {
|
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
|
||||||
|
for ty::List<(VariantIdx, FieldIdx)>
|
||||||
|
{
|
||||||
fn decode(decoder: &mut D) -> &'tcx Self {
|
fn decode(decoder: &mut D) -> &'tcx Self {
|
||||||
let len = decoder.read_usize();
|
let len = decoder.read_usize();
|
||||||
decoder
|
decoder.interner().mk_offset_of_from_iter(
|
||||||
.interner()
|
(0..len).map::<(VariantIdx, FieldIdx), _>(|_| Decodable::decode(decoder)),
|
||||||
.mk_offset_of_from_iter((0..len).map::<OffsetOfIdx, _>(|_| Decodable::decode(decoder)))
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,7 +437,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>,
|
&'tcx ty::List<(VariantIdx, FieldIdx)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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, OffsetOfIdx, TargetDataLayout, VariantIdx};
|
use rustc_target::abi::{FieldIdx, Layout, LayoutS, 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,7 +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>>,
|
offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> CtxtInterners<'tcx> {
|
impl<'tcx> CtxtInterners<'tcx> {
|
||||||
|
@ -1589,7 +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),
|
offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'tcx> TyCtxt<'tcx> {
|
impl<'tcx> TyCtxt<'tcx> {
|
||||||
|
@ -1920,7 +1920,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||||
pub fn mk_offset_of_from_iter<I, T>(self, iter: I) -> T::Output
|
pub fn mk_offset_of_from_iter<I, T>(self, iter: I) -> T::Output
|
||||||
where
|
where
|
||||||
I: Iterator<Item = T>,
|
I: Iterator<Item = T>,
|
||||||
T: CollectAndApply<OffsetOfIdx, &'tcx List<OffsetOfIdx>>,
|
T: CollectAndApply<(VariantIdx, FieldIdx), &'tcx List<(VariantIdx, FieldIdx)>>,
|
||||||
{
|
{
|
||||||
T::collect_and_apply(iter, |xs| self.mk_offset_of(xs))
|
T::collect_and_apply(iter, |xs| self.mk_offset_of(xs))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, OffsetOfIdx};
|
use rustc_target::abi::{FieldIdx, VariantIdx};
|
||||||
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<OffsetOfIdx>)>,
|
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeckResults<'tcx> {
|
impl<'tcx> TypeckResults<'tcx> {
|
||||||
|
@ -464,13 +464,15 @@ impl<'tcx> TypeckResults<'tcx> {
|
||||||
&self.coercion_casts
|
&self.coercion_casts
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<OffsetOfIdx>)> {
|
pub fn offset_of_data(
|
||||||
|
&self,
|
||||||
|
) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> {
|
||||||
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(
|
pub fn offset_of_data_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<OffsetOfIdx>)> {
|
) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> {
|
||||||
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
|
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,8 +248,6 @@ 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");
|
||||||
|
@ -258,22 +256,10 @@ 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();
|
|
||||||
|
|
||||||
while let Some(&index) = indices.next() {
|
for &(variant, field) in indices {
|
||||||
match (current_ty.kind(), index) {
|
match current_ty.kind() {
|
||||||
(ty::Adt(def, subst), Field(field)) if !def.is_enum() => {
|
ty::Adt(def, subst) => {
|
||||||
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];
|
let field = &def.variant(variant).fields[field];
|
||||||
|
|
||||||
self.insert_def_id(field.did);
|
self.insert_def_id(field.did);
|
||||||
|
@ -283,12 +269,11 @@ 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), Field(field)) => {
|
ty::Tuple(tys) => {
|
||||||
current_ty =
|
current_ty =
|
||||||
self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]);
|
self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]);
|
||||||
}
|
}
|
||||||
(_, Field(_)) => span_bug!(expr.span, "named field access on non-ADT"),
|
_ => 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, OffsetOfIdx};
|
use rustc_target::abi::FieldIdx;
|
||||||
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,13 +643,10 @@ impl<'tcx> Stable<'tcx> for FieldIdx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for OffsetOfIdx {
|
impl<'tcx> Stable<'tcx> for (rustc_target::abi::VariantIdx, FieldIdx) {
|
||||||
type T = usize;
|
type T = (usize, usize);
|
||||||
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
|
||||||
match self {
|
(self.0.as_usize(), self.1.as_usize())
|
||||||
OffsetOfIdx::Field(f) => f.as_usize(),
|
|
||||||
OffsetOfIdx::Variant(v) => v.as_usize(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -250,16 +250,16 @@ 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 = OffsetOfIdx>) -> Size
|
pub fn offset_of_subfield<C, I>(self, cx: &C, indices: I) -> Size
|
||||||
where
|
where
|
||||||
Ty: TyAbiInterface<'a, C>,
|
Ty: TyAbiInterface<'a, C>,
|
||||||
|
I: Iterator<Item = (VariantIdx, FieldIdx)>,
|
||||||
{
|
{
|
||||||
let mut layout = self;
|
let mut layout = self;
|
||||||
let mut offset = Size::ZERO;
|
let mut offset = Size::ZERO;
|
||||||
|
|
||||||
for index in indices {
|
for (variant, field) in indices {
|
||||||
match index {
|
layout = layout.for_variant(cx, variant);
|
||||||
OffsetOfIdx::Field(field) => {
|
|
||||||
let index = field.index();
|
let index = field.index();
|
||||||
offset += layout.fields.offset(index);
|
offset += layout.fields.offset(index);
|
||||||
layout = layout.field(cx, index);
|
layout = layout.field(cx, index);
|
||||||
|
@ -269,11 +269,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
||||||
layout.ty
|
layout.ty
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
OffsetOfIdx::Variant(variant) => {
|
|
||||||
layout = layout.for_variant(cx, variant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
offset
|
offset
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,7 @@ pub enum NullOp {
|
||||||
/// 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(Vec<FieldIdx>),
|
OffsetOf(Vec<(VariantIdx, FieldIdx)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operand {
|
impl Operand {
|
||||||
|
|
|
@ -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.
|
/// 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`.
|
/// 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
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -1324,6 +1328,8 @@ impl<T> SizedTypeProperties for T {}
|
||||||
/// struct NestedB(u8);
|
/// struct NestedB(u8);
|
||||||
///
|
///
|
||||||
/// assert_eq!(mem::offset_of!(NestedA, b.0), 0);
|
/// 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")]
|
#[unstable(feature = "offset_of", issue = "106655")]
|
||||||
#[allow_internal_unstable(builtin_syntax, hint_must_use)]
|
#[allow_internal_unstable(builtin_syntax, hint_must_use)]
|
||||||
|
|
|
@ -11,4 +11,7 @@ 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, One); //~ ERROR `One` is an enum variant; expected field at end of `offset_of`
|
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.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`
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,29 @@ error[E0795]: `One` is an enum variant; expected field at end of `offset_of`
|
||||||
LL | offset_of!(Alpha, One);
|
LL | offset_of!(Alpha, One);
|
||||||
| ^^^ enum variant
|
| ^^^ 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, E0795.
|
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, E0599, E0609, E0795.
|
||||||
For more information about an error, try `rustc --explain E0573`.
|
For more information about an error, try `rustc --explain E0573`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue