diff options
| author | George Bateman <george.bateman16@gmail.com> | 2023-08-15 20:10:45 +0100 |
|---|---|---|
| committer | George Bateman <george.bateman16@gmail.com> | 2023-10-31 23:25:54 +0000 |
| commit | e936416a8d3cfb501504f00d7250d5b595fed244 (patch) | |
| tree | c0dd8196372db8a77ae1a90d38d87b630658e90e /compiler/rustc_const_eval/src/transform | |
| parent | 9d83ac217957eece2189eccf4a7232caec7232ee (diff) | |
| download | rust-e936416a8d3cfb501504f00d7250d5b595fed244.tar.gz rust-e936416a8d3cfb501504f00d7250d5b595fed244.zip | |
Support enum variants in offset_of!
Diffstat (limited to 'compiler/rustc_const_eval/src/transform')
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/validate.rs | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b70a342aa15..bdccd9b0edb 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1056,16 +1056,19 @@ 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; + let mut indices = indices.into_iter(); - for field in fields.iter() { - match current_ty.kind() { - ty::Tuple(fields) => { + 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); return; @@ -1073,16 +1076,24 @@ 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() { + (ty::Adt(adt_def, args), Field(field)) if !adt_def.is_enum() => { + 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!("Cannot get field offset from enum {current_ty:?}"), + format!("enum variant must be followed by field index in offset_of; in {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 +1104,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 {index:?} from type {current_ty:?}"), ); return; } |
