diff options
| author | bors <bors@rust-lang.org> | 2023-11-01 14:17:56 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-11-01 14:17:56 +0000 |
| commit | 146dafa26277c873172f555017b970ef006d302a (patch) | |
| tree | 876ed8c65789f5eaeb01332ce8f2a6d034a471df /compiler/rustc_const_eval/src | |
| parent | 11cd1f00268061dff447bc0df3d679b35d460875 (diff) | |
| parent | e742f809f68d571a28b7c9153366194e47714b65 (diff) | |
| download | rust-146dafa26277c873172f555017b970ef006d302a.tar.gz rust-146dafa26277c873172f555017b970ef006d302a.zip | |
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.
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/step.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/validate.rs | 23 |
2 files changed, 12 insertions, 13 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 8c34d05042b..b6993d939c5 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -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)?; diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b70a342aa15..4d71f763667 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -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; } |
