diff options
| author | DrMeepster <19316085+DrMeepster@users.noreply.github.com> | 2022-09-11 00:37:49 -0700 |
|---|---|---|
| committer | DrMeepster <19316085+DrMeepster@users.noreply.github.com> | 2023-04-21 02:14:02 -0700 |
| commit | 511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5 (patch) | |
| tree | 9aed1b0210cfd3c784a7c5cc89646b8d9dad5427 /compiler/rustc_const_eval/src/transform/validate.rs | |
| parent | b92a41c6760801a7128ca0ec69ba4ba9c9194054 (diff) | |
| download | rust-511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5.tar.gz rust-511e457c4ba88097ee46ef07b7ef80ce4dd4a3c5.zip | |
offset_of
Diffstat (limited to 'compiler/rustc_const_eval/src/transform/validate.rs')
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/validate.rs | 53 |
1 files changed, 49 insertions, 4 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 8aee019e994..119fe9801e4 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -8,9 +8,10 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{ traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location, - MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, - RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, - TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK, + MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef, + ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, + Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, + START_BLOCK, }; use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; use rustc_mir_dataflow::impls::MaybeStorageLive; @@ -711,10 +712,54 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } + Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => { + let fail_out_of_bounds = |this: &Self, location, field, ty| { + this.fail(location, format!("Out of bounds field {field:?} for {ty:?}")); + }; + + let mut current_ty = *container; + + for &field in fields { + match current_ty.kind() { + ty::Tuple(fields) => { + let Some(&f_ty) = fields.get(field.as_usize()) else { + fail_out_of_bounds(self, location, field, current_ty); + return; + }; + + current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); + } + ty::Adt(adt_def, substs) => { + 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 { + fail_out_of_bounds(self, location, field, current_ty); + return; + }; + + let f_ty = field.ty(self.tcx, substs); + current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty); + } + _ => { + self.fail( + location, + format!("Cannot get field offset from non-adt type {current_ty:?}"), + ); + return; + } + } + } + } Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::AddressOf(_, _) - | Rvalue::NullaryOp(_, _) + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::Discriminant(_) => {} } self.super_rvalue(rvalue, location); |
