Skip to content

Commit

Permalink
Enums in offset_of: update based on est31, scottmcm & llogiq review
Browse files Browse the repository at this point in the history
  • Loading branch information
GKFX committed Aug 15, 2023
1 parent 825bb5a commit 3b11007
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 140 deletions.
7 changes: 0 additions & 7 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1119,13 +1119,6 @@ rustc_index::newtype_index! {
pub struct FieldIdx {}
}

/// `offset_of` can traverse fields and enum variants and should keep track of which is which.
#[derive(Copy, Clone, Debug, Eq, Hash, HashStable_Generic, PartialEq, Encodable, Decodable)]
pub enum OffsetOfIdx {
Field(FieldIdx),
Variant(VariantIdx),
}

/// Describes how the fields of a type are located in memory.
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
Expand Down
36 changes: 12 additions & 24 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,37 +971,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
};

let mut current_ty = *container;
let mut indices = indices.into_iter();

use rustc_target::abi::OffsetOfIdx::*;

while let Some(index) = indices.next() {
match (current_ty.kind(), index) {
(ty::Tuple(fields), Field(field)) => {
let Some(&f_ty) = fields.get(field.as_usize()) else {
fail_out_of_bounds(self, location, field, current_ty);
for (variant, field) in indices.iter() {
match current_ty.kind() {
ty::Tuple(fields) => {
if variant != FIRST_VARIANT {
self.fail(
location,
format!("tried to get variant {variant:?} of tuple"),
);
return;
};

current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
}
(ty::Adt(adt_def, args), Field(field)) if !adt_def.is_enum() => {
let Some(field) = adt_def.non_enum_variant().fields.get(field) else {
}
let Some(&f_ty) = fields.get(field.as_usize()) else {
fail_out_of_bounds(self, location, field, current_ty);
return;
};

let f_ty = field.ty(self.tcx, args);
current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
}
(ty::Adt(adt_def, args), Variant(variant)) if adt_def.is_enum() => {
let Some(Field(field)) = indices.next() else {
self.fail(
location,
format!("enum variant must be followed by field index in offset_of; in {current_ty:?}"),
);
return;
};
ty::Adt(adt_def, args) => {
let Some(field) = adt_def.variant(variant).fields.get(field) else {
fail_out_of_bounds(self, location, field, current_ty);
return;
Expand All @@ -1013,7 +1001,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
_ => {
self.fail(
location,
format!("Cannot get offset {index:?} from type {current_ty:?}"),
format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"),
);
return;
}
Expand Down
101 changes: 59 additions & 42 deletions compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_target::abi::FieldIdx;
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
use rustc_target::spec::abi::Abi::RustIntrinsic;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
Expand Down Expand Up @@ -3128,8 +3128,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fields: &[Ident],
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
use rustc_target::abi::OffsetOfIdx::*;

let container = self.to_ty(container).normalized;

let mut field_indices = Vec::with_capacity(fields.len());
Expand All @@ -3145,49 +3143,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let (ident, _def_scope) =
self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);

if let Some((index, variant)) = container_def.variants()
let Some((index, variant)) = container_def.variants()
.iter_enumerated()
.find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident)
{
let Some(&subfield) = fields.next() else {
let mut err = type_error_struct!(
self.tcx().sess,
ident.span,
container,
E0795,
"`{ident}` is an enum variant; expected field at end of `offset_of`",
);
err.span_label(field.span, "enum variant");
err.emit();
break;
};
let (subident, sub_def_scope) =
self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block);

if let Some((subindex, field)) = variant.fields
.iter_enumerated()
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident)
{
let field_ty = self.field_ty(expr.span, field, args);
.find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) else {
let mut err = type_error_struct!(
self.tcx().sess,
ident.span,
container,
E0599,
"no variant named `{ident}` found for enum `{container}`",
);
err.span_label(field.span, "variant not found");
err.emit();
break;
};
let Some(&subfield) = fields.next() else {
let mut err = type_error_struct!(
self.tcx().sess,
ident.span,
container,
E0795,
"`{ident}` is an enum variant; expected field at end of `offset_of`",
);
err.span_label(field.span, "enum variant");
err.emit();
break;
};
let (subident, sub_def_scope) =
self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block);

// FIXME: DSTs with static alignment should be allowed
self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);
let Some((subindex, field)) = variant.fields
.iter_enumerated()
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) else {
let mut err = type_error_struct!(
self.tcx().sess,
ident.span,
container,
E0609,
"no field named `{subfield}` on enum variant `{container}::{ident}`",
);
err.span_label(field.span, "this enum variant...");
err.span_label(subident.span, "...does not have this field");
err.emit();
break;
};

if field.vis.is_accessible_from(sub_def_scope, self.tcx) {
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
} else {
self.private_field_err(ident, container_def.did()).emit();
}
let field_ty = self.field_ty(expr.span, field, args);

// Save the index of all fields regardless of their visibility in case
// of error recovery.
field_indices.push(Variant(index));
field_indices.push(Field(subindex));
current_container = field_ty;
// FIXME: DSTs with static alignment should be allowed
self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);

continue;
}
if field.vis.is_accessible_from(sub_def_scope, self.tcx) {
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
} else {
self.private_field_err(ident, container_def.did()).emit();
}

// Save the index of all fields regardless of their visibility in case
// of error recovery.
field_indices.push((index, subindex));
current_container = field_ty;

continue;
}
ty::Adt(container_def, args) => {
let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
Expand All @@ -3212,7 +3229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// Save the index of all fields regardless of their visibility in case
// of error recovery.
field_indices.push(Field(index));
field_indices.push((FIRST_VARIANT, index));
current_container = field_ty;

continue;
Expand All @@ -3226,7 +3243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.require_type_is_sized(ty, expr.span, traits::MiscObligation);
}
if let Some(&field_ty) = tys.get(index) {
field_indices.push(Field(index.into()));
field_indices.push((FIRST_VARIANT, index.into()));
current_container = field_ty;

continue;
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir};
use rustc_hir::{self, GeneratorKind};
use rustc_index::IndexVec;
use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx};
use rustc_target::abi::{FieldIdx, VariantIdx};

use rustc_ast::Mutability;
use rustc_span::def_id::LocalDefId;
Expand Down Expand Up @@ -1281,7 +1281,7 @@ pub enum NullOp<'tcx> {
/// Returns the minimum alignment of a type
AlignOf,
/// Returns the offset of a field
OffsetOf(&'tcx List<OffsetOfIdx>),
OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarArgs};
use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx};
use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_target::asm::InlineAsmRegOrRegClass;
use std::fmt;
use std::ops::Index;
Expand Down Expand Up @@ -488,7 +488,7 @@ pub enum ExprKind<'tcx> {
/// Field offset (`offset_of!`)
OffsetOf {
container: Ty<'tcx>,
fields: &'tcx List<OffsetOfIdx>,
fields: &'tcx List<(VariantIdx, FieldIdx)>,
},
/// An expression taking a reference to a thread local.
ThreadLocalRef(DefId),
Expand Down
14 changes: 8 additions & 6 deletions compiler/rustc_middle/src/ty/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
use rustc_serialize::{Decodable, Encodable};
use rustc_span::Span;
use rustc_target::abi::{FieldIdx, OffsetOfIdx};
use rustc_target::abi::{FieldIdx, VariantIdx};
pub use rustc_type_ir::{TyDecoder, TyEncoder};
use std::hash::Hash;
use std::intrinsics;
Expand Down Expand Up @@ -412,12 +412,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 {
let len = decoder.read_usize();
decoder
.interner()
.mk_offset_of_from_iter((0..len).map::<OffsetOfIdx, _>(|_| Decodable::decode(decoder)))
decoder.interner().mk_offset_of_from_iter(
(0..len).map::<(VariantIdx, FieldIdx), _>(|_| Decodable::decode(decoder)),
)
}
}

Expand All @@ -433,7 +435,7 @@ impl_decodable_via_ref! {
&'tcx ty::List<ty::BoundVariableKind>,
&'tcx ty::List<ty::Clause<'tcx>>,
&'tcx ty::List<FieldIdx>,
&'tcx ty::List<OffsetOfIdx>,
&'tcx ty::List<(VariantIdx, FieldIdx)>,
}

#[macro_export]
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use rustc_session::{Limit, MetadataKind, Session};
use rustc_span::def_id::{DefPathHash, StableCrateId};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{FieldIdx, Layout, LayoutS, OffsetOfIdx, TargetDataLayout, VariantIdx};
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
use rustc_target::spec::abi;
use rustc_type_ir::sty::TyKind::*;
use rustc_type_ir::WithCachedTypeInfo;
Expand Down Expand Up @@ -156,7 +156,7 @@ pub struct CtxtInterners<'tcx> {
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
fields: InternedSet<'tcx, List<FieldIdx>>,
offset_of: InternedSet<'tcx, List<OffsetOfIdx>>,
offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
}

impl<'tcx> CtxtInterners<'tcx> {
Expand Down Expand Up @@ -1538,7 +1538,7 @@ slice_interners!(
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
fields: pub mk_fields(FieldIdx),
offset_of: pub mk_offset_of(OffsetOfIdx),
offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
);

impl<'tcx> TyCtxt<'tcx> {
Expand Down Expand Up @@ -1863,7 +1863,7 @@ impl<'tcx> TyCtxt<'tcx> {
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: CollectAndApply<(VariantIdx, FieldIdx), &'tcx List<(VariantIdx, FieldIdx)>>,
{
T::collect_and_apply(iter, |xs| self.mk_offset_of(xs))
}
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_middle/src/ty/typeck_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use rustc_macros::HashStable;
use rustc_middle::mir::FakeReadCause;
use rustc_session::Session;
use rustc_span::Span;
use rustc_target::abi::{FieldIdx, OffsetOfIdx};
use rustc_target::abi::{FieldIdx, VariantIdx};
use std::{collections::hash_map::Entry, hash::Hash, iter};

use super::RvalueScopes;
Expand Down Expand Up @@ -209,7 +209,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<OffsetOfIdx>)>,
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
}

/// Whenever a value may be live across a generator yield, the type of that value winds up in the
Expand Down Expand Up @@ -534,13 +534,15 @@ impl<'tcx> TypeckResults<'tcx> {
&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 }
}

pub fn offset_of_data_mut(
&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 }
}
}
Expand Down
Loading

0 comments on commit 3b11007

Please sign in to comment.