Auto merge of #114208 - GKFX:offset_of_enum, r=wesleywiser
Support enum variants in offset_of! This MR implements support for navigating through enum variants in `offset_of!`, placing the enum variant name in the second argument to `offset_of!`. The RFC placed it in the first argument, but I think it interacts better with nested field access in the second, as you can then write things like ```rust offset_of!(Type, field.Variant.field) ``` Alternatively, a syntactic distinction could be made between variants and fields (e.g. `field::Variant.field`) but I'm not convinced this would be helpful. [RFC 3308 # Enum Support](https://rust-lang.github.io/rfcs/3308-offset_of.html#enum-support-offset_ofsomeenumstructvariant-field_on_variant) Tracking Issue #106655.
This commit is contained in:
commit
146dafa262
33 changed files with 477 additions and 89 deletions
|
@ -275,7 +275,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
mir::NullOp::SizeOf => layout.size.bytes(),
|
||||
mir::NullOp::AlignOf => layout.align.abi.bytes(),
|
||||
mir::NullOp::OffsetOf(fields) => {
|
||||
layout.offset_of_subfield(self, fields.iter().map(|f| f.index())).bytes()
|
||||
layout.offset_of_subfield(self, fields.iter()).bytes()
|
||||
}
|
||||
};
|
||||
self.write_scalar(Scalar::from_target_usize(val, self), &dest)?;
|
||||
|
|
|
@ -1056,16 +1056,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => {
|
||||
Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => {
|
||||
let fail_out_of_bounds = |this: &mut Self, location, field, ty| {
|
||||
this.fail(location, format!("Out of bounds field {field:?} for {ty:?}"));
|
||||
};
|
||||
|
||||
let mut current_ty = *container;
|
||||
|
||||
for field in fields.iter() {
|
||||
for (variant, field) in indices.iter() {
|
||||
match current_ty.kind() {
|
||||
ty::Tuple(fields) => {
|
||||
if variant != FIRST_VARIANT {
|
||||
self.fail(
|
||||
location,
|
||||
format!("tried to get variant {variant:?} of tuple"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
let Some(&f_ty) = fields.get(field.as_usize()) else {
|
||||
fail_out_of_bounds(self, location, field, current_ty);
|
||||
return;
|
||||
|
@ -1074,15 +1081,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
|
||||
}
|
||||
ty::Adt(adt_def, args) => {
|
||||
if adt_def.is_enum() {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot get field offset from enum {current_ty:?}"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(field) = adt_def.non_enum_variant().fields.get(field) else {
|
||||
let Some(field) = adt_def.variant(variant).fields.get(field) else {
|
||||
fail_out_of_bounds(self, location, field, current_ty);
|
||||
return;
|
||||
};
|
||||
|
@ -1093,7 +1092,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
_ => {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot get field offset from non-adt type {current_ty:?}"),
|
||||
format!("Cannot get offset ({variant:?}, {field:?}) from type {current_ty:?}"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue