Skip to content

Commit 8e4d8dd

Browse files
committed
Enums in offset_of: update based on est31, scottmcm & llogiq review
1 parent ea047fb commit 8e4d8dd

File tree

15 files changed

+150
-140
lines changed

15 files changed

+150
-140
lines changed

compiler/rustc_abi/src/lib.rs

-7
Original file line numberDiff line numberDiff line change
@@ -1133,13 +1133,6 @@ rustc_index::newtype_index! {
11331133
pub struct FieldIdx {}
11341134
}
11351135

1136-
/// `offset_of` can traverse fields and enum variants and should keep track of which is which.
1137-
#[derive(Copy, Clone, Debug, Eq, Hash, HashStable_Generic, PartialEq, Encodable, Decodable)]
1138-
pub enum OffsetOfIdx {
1139-
Field(FieldIdx),
1140-
Variant(VariantIdx),
1141-
}
1142-
11431136
/// Describes how the fields of a type are located in memory.
11441137
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
11451138
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]

compiler/rustc_const_eval/src/transform/validate.rs

+12-24
Original file line numberDiff line numberDiff line change
@@ -1062,37 +1062,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
10621062
};
10631063

10641064
let mut current_ty = *container;
1065-
let mut indices = indices.into_iter();
10661065

1067-
use rustc_target::abi::OffsetOfIdx::*;
1068-
1069-
while let Some(index) = indices.next() {
1070-
match (current_ty.kind(), index) {
1071-
(ty::Tuple(fields), Field(field)) => {
1072-
let Some(&f_ty) = fields.get(field.as_usize()) else {
1073-
fail_out_of_bounds(self, location, field, current_ty);
1066+
for (variant, field) in indices.iter() {
1067+
match current_ty.kind() {
1068+
ty::Tuple(fields) => {
1069+
if variant != FIRST_VARIANT {
1070+
self.fail(
1071+
location,
1072+
format!("tried to get variant {variant:?} of tuple"),
1073+
);
10741074
return;
1075-
};
1076-
1077-
current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
1078-
}
1079-
(ty::Adt(adt_def, args), Field(field)) if !adt_def.is_enum() => {
1080-
let Some(field) = adt_def.non_enum_variant().fields.get(field) else {
1075+
}
1076+
let Some(&f_ty) = fields.get(field.as_usize()) else {
10811077
fail_out_of_bounds(self, location, field, current_ty);
10821078
return;
10831079
};
10841080

1085-
let f_ty = field.ty(self.tcx, args);
10861081
current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
10871082
}
1088-
(ty::Adt(adt_def, args), Variant(variant)) if adt_def.is_enum() => {
1089-
let Some(Field(field)) = indices.next() else {
1090-
self.fail(
1091-
location,
1092-
format!("enum variant must be followed by field index in offset_of; in {current_ty:?}"),
1093-
);
1094-
return;
1095-
};
1083+
ty::Adt(adt_def, args) => {
10961084
let Some(field) = adt_def.variant(variant).fields.get(field) else {
10971085
fail_out_of_bounds(self, location, field, current_ty);
10981086
return;
@@ -1104,7 +1092,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11041092
_ => {
11051093
self.fail(
11061094
location,
1107-
format!("Cannot get offset {index:?} from type {current_ty:?}"),
1095+
format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"),
11081096
);
11091097
return;
11101098
}

compiler/rustc_hir_typeck/src/expr.rs

+59-42
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
5454
use rustc_span::hygiene::DesugaringKind;
5555
use rustc_span::source_map::{Span, Spanned};
5656
use rustc_span::symbol::{kw, sym, Ident, Symbol};
57-
use rustc_target::abi::FieldIdx;
57+
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
5858
use rustc_target::spec::abi::Abi::RustIntrinsic;
5959
use rustc_trait_selection::infer::InferCtxtExt;
6060
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@@ -3098,8 +3098,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
30983098
fields: &[Ident],
30993099
expr: &'tcx hir::Expr<'tcx>,
31003100
) -> Ty<'tcx> {
3101-
use rustc_target::abi::OffsetOfIdx::*;
3102-
31033101
let container = self.to_ty(container).normalized;
31043102

31053103
let mut field_indices = Vec::with_capacity(fields.len());
@@ -3115,49 +3113,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31153113
let (ident, _def_scope) =
31163114
self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
31173115

3118-
if let Some((index, variant)) = container_def.variants()
3116+
let Some((index, variant)) = container_def.variants()
31193117
.iter_enumerated()
3120-
.find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident)
3121-
{
3122-
let Some(&subfield) = fields.next() else {
3123-
let mut err = type_error_struct!(
3124-
self.tcx().sess,
3125-
ident.span,
3126-
container,
3127-
E0795,
3128-
"`{ident}` is an enum variant; expected field at end of `offset_of`",
3129-
);
3130-
err.span_label(field.span, "enum variant");
3131-
err.emit();
3132-
break;
3133-
};
3134-
let (subident, sub_def_scope) =
3135-
self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block);
3136-
3137-
if let Some((subindex, field)) = variant.fields
3138-
.iter_enumerated()
3139-
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident)
3140-
{
3141-
let field_ty = self.field_ty(expr.span, field, args);
3118+
.find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident) else {
3119+
let mut err = type_error_struct!(
3120+
self.tcx().sess,
3121+
ident.span,
3122+
container,
3123+
E0599,
3124+
"no variant named `{ident}` found for enum `{container}`",
3125+
);
3126+
err.span_label(field.span, "variant not found");
3127+
err.emit();
3128+
break;
3129+
};
3130+
let Some(&subfield) = fields.next() else {
3131+
let mut err = type_error_struct!(
3132+
self.tcx().sess,
3133+
ident.span,
3134+
container,
3135+
E0795,
3136+
"`{ident}` is an enum variant; expected field at end of `offset_of`",
3137+
);
3138+
err.span_label(field.span, "enum variant");
3139+
err.emit();
3140+
break;
3141+
};
3142+
let (subident, sub_def_scope) =
3143+
self.tcx.adjust_ident_and_get_scope(subfield, variant.def_id, block);
31423144

3143-
// FIXME: DSTs with static alignment should be allowed
3144-
self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);
3145+
let Some((subindex, field)) = variant.fields
3146+
.iter_enumerated()
3147+
.find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) else {
3148+
let mut err = type_error_struct!(
3149+
self.tcx().sess,
3150+
ident.span,
3151+
container,
3152+
E0609,
3153+
"no field named `{subfield}` on enum variant `{container}::{ident}`",
3154+
);
3155+
err.span_label(field.span, "this enum variant...");
3156+
err.span_label(subident.span, "...does not have this field");
3157+
err.emit();
3158+
break;
3159+
};
31453160

3146-
if field.vis.is_accessible_from(sub_def_scope, self.tcx) {
3147-
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
3148-
} else {
3149-
self.private_field_err(ident, container_def.did()).emit();
3150-
}
3161+
let field_ty = self.field_ty(expr.span, field, args);
31513162

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

3158-
continue;
3159-
}
3166+
if field.vis.is_accessible_from(sub_def_scope, self.tcx) {
3167+
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
3168+
} else {
3169+
self.private_field_err(ident, container_def.did()).emit();
31603170
}
3171+
3172+
// Save the index of all fields regardless of their visibility in case
3173+
// of error recovery.
3174+
field_indices.push((index, subindex));
3175+
current_container = field_ty;
3176+
3177+
continue;
31613178
}
31623179
ty::Adt(container_def, args) => {
31633180
let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
@@ -3182,7 +3199,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31823199

31833200
// Save the index of all fields regardless of their visibility in case
31843201
// of error recovery.
3185-
field_indices.push(Field(index));
3202+
field_indices.push((FIRST_VARIANT, index));
31863203
current_container = field_ty;
31873204

31883205
continue;
@@ -3196,7 +3213,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
31963213
self.require_type_is_sized(ty, expr.span, traits::MiscObligation);
31973214
}
31983215
if let Some(&field_ty) = tys.get(index) {
3199-
field_indices.push(Field(index.into()));
3216+
field_indices.push((FIRST_VARIANT, index.into()));
32003217
current_container = field_ty;
32013218

32023219
continue;

compiler/rustc_middle/src/mir/syntax.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_hir::def_id::DefId;
1717
use rustc_hir::{self as hir};
1818
use rustc_hir::{self, CoroutineKind};
1919
use rustc_index::IndexVec;
20-
use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx};
20+
use rustc_target::abi::{FieldIdx, VariantIdx};
2121

2222
use rustc_ast::Mutability;
2323
use rustc_span::def_id::LocalDefId;
@@ -1354,7 +1354,7 @@ pub enum NullOp<'tcx> {
13541354
/// Returns the minimum alignment of a type
13551355
AlignOf,
13561356
/// Returns the offset of a field
1357-
OffsetOf(&'tcx List<OffsetOfIdx>),
1357+
OffsetOf(&'tcx List<(VariantIdx, FieldIdx)>),
13581358
}
13591359

13601360
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]

compiler/rustc_middle/src/thir.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc_middle::ty::{
2626
use rustc_span::def_id::LocalDefId;
2727
use rustc_span::{sym, ErrorGuaranteed, Span, Symbol, DUMMY_SP};
2828
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
29-
use rustc_target::abi::{FieldIdx, OffsetOfIdx, VariantIdx};
29+
use rustc_target::abi::{FieldIdx, VariantIdx};
3030
use rustc_target::asm::InlineAsmRegOrRegClass;
3131
use std::fmt;
3232
use std::ops::Index;
@@ -491,7 +491,7 @@ pub enum ExprKind<'tcx> {
491491
/// Field offset (`offset_of!`)
492492
OffsetOf {
493493
container: Ty<'tcx>,
494-
fields: &'tcx List<OffsetOfIdx>,
494+
fields: &'tcx List<(VariantIdx, FieldIdx)>,
495495
},
496496
/// An expression taking a reference to a thread local.
497497
ThreadLocalRef(DefId),

compiler/rustc_middle/src/ty/codec.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashMap;
1919
use rustc_middle::ty::TyCtxt;
2020
use rustc_serialize::{Decodable, Encodable};
2121
use rustc_span::Span;
22-
use rustc_target::abi::{FieldIdx, OffsetOfIdx};
22+
use rustc_target::abi::{FieldIdx, VariantIdx};
2323
pub use rustc_type_ir::{TyDecoder, TyEncoder};
2424
use std::hash::Hash;
2525
use std::intrinsics;
@@ -414,12 +414,14 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Fi
414414
}
415415
}
416416

417-
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<OffsetOfIdx> {
417+
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
418+
for ty::List<(VariantIdx, FieldIdx)>
419+
{
418420
fn decode(decoder: &mut D) -> &'tcx Self {
419421
let len = decoder.read_usize();
420-
decoder
421-
.interner()
422-
.mk_offset_of_from_iter((0..len).map::<OffsetOfIdx, _>(|_| Decodable::decode(decoder)))
422+
decoder.interner().mk_offset_of_from_iter(
423+
(0..len).map::<(VariantIdx, FieldIdx), _>(|_| Decodable::decode(decoder)),
424+
)
423425
}
424426
}
425427

@@ -435,7 +437,7 @@ impl_decodable_via_ref! {
435437
&'tcx ty::List<ty::BoundVariableKind>,
436438
&'tcx ty::List<ty::Clause<'tcx>>,
437439
&'tcx ty::List<FieldIdx>,
438-
&'tcx ty::List<OffsetOfIdx>,
440+
&'tcx ty::List<(VariantIdx, FieldIdx)>,
439441
}
440442

441443
#[macro_export]

compiler/rustc_middle/src/ty/context.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use rustc_session::{Limit, MetadataKind, Session};
6363
use rustc_span::def_id::{DefPathHash, StableCrateId};
6464
use rustc_span::symbol::{kw, sym, Ident, Symbol};
6565
use rustc_span::{Span, DUMMY_SP};
66-
use rustc_target::abi::{FieldIdx, Layout, LayoutS, OffsetOfIdx, TargetDataLayout, VariantIdx};
66+
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
6767
use rustc_target::spec::abi;
6868
use rustc_type_ir::TyKind::*;
6969
use rustc_type_ir::WithCachedTypeInfo;
@@ -163,7 +163,7 @@ pub struct CtxtInterners<'tcx> {
163163
predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
164164
fields: InternedSet<'tcx, List<FieldIdx>>,
165165
local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
166-
offset_of: InternedSet<'tcx, List<OffsetOfIdx>>,
166+
offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
167167
}
168168

169169
impl<'tcx> CtxtInterners<'tcx> {
@@ -1578,7 +1578,7 @@ slice_interners!(
15781578
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
15791579
fields: pub mk_fields(FieldIdx),
15801580
local_def_ids: intern_local_def_ids(LocalDefId),
1581-
offset_of: pub mk_offset_of(OffsetOfIdx),
1581+
offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
15821582
);
15831583

15841584
impl<'tcx> TyCtxt<'tcx> {
@@ -1909,7 +1909,7 @@ impl<'tcx> TyCtxt<'tcx> {
19091909
pub fn mk_offset_of_from_iter<I, T>(self, iter: I) -> T::Output
19101910
where
19111911
I: Iterator<Item = T>,
1912-
T: CollectAndApply<OffsetOfIdx, &'tcx List<OffsetOfIdx>>,
1912+
T: CollectAndApply<(VariantIdx, FieldIdx), &'tcx List<(VariantIdx, FieldIdx)>>,
19131913
{
19141914
T::collect_and_apply(iter, |xs| self.mk_offset_of(xs))
19151915
}

compiler/rustc_middle/src/ty/typeck_results.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_macros::HashStable;
2424
use rustc_middle::mir::FakeReadCause;
2525
use rustc_session::Session;
2626
use rustc_span::Span;
27-
use rustc_target::abi::{FieldIdx, OffsetOfIdx};
27+
use rustc_target::abi::{FieldIdx, VariantIdx};
2828
use std::{collections::hash_map::Entry, hash::Hash, iter};
2929

3030
use super::RvalueScopes;
@@ -205,7 +205,7 @@ pub struct TypeckResults<'tcx> {
205205
pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>,
206206

207207
/// Container types and field indices of `offset_of!` expressions
208-
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<OffsetOfIdx>)>,
208+
offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>,
209209
}
210210

211211
impl<'tcx> TypeckResults<'tcx> {
@@ -464,13 +464,15 @@ impl<'tcx> TypeckResults<'tcx> {
464464
&self.coercion_casts
465465
}
466466

467-
pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<OffsetOfIdx>)> {
467+
pub fn offset_of_data(
468+
&self,
469+
) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> {
468470
LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data }
469471
}
470472

471473
pub fn offset_of_data_mut(
472474
&mut self,
473-
) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<OffsetOfIdx>)> {
475+
) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)> {
474476
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
475477
}
476478
}

0 commit comments

Comments
 (0)