diff options
| author | Jakob Degen <jakob.e.degen@gmail.com> | 2022-05-06 16:09:59 -0400 |
|---|---|---|
| committer | Jakob Degen <jakob.e.degen@gmail.com> | 2022-05-06 16:43:09 -0400 |
| commit | c4168fdb50bd3d50a1729ae9af3ca4921841c35a (patch) | |
| tree | befb189a8658e5e614de9d12ac3d22f1e4cfe735 | |
| parent | 5289bbece312fb6704febea1a95a601f0dd27b02 (diff) | |
| download | rust-c4168fdb50bd3d50a1729ae9af3ca4921841c35a.tar.gz rust-c4168fdb50bd3d50a1729ae9af3ca4921841c35a.zip | |
Check that field projections have the correct type
| -rw-r--r-- | compiler/rustc_const_eval/src/transform/validate.rs | 56 |
1 files changed, 55 insertions, 1 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index a790a723305..25209e20e99 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::AlwaysLiveLocals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; -use rustc_target::abi::Size; +use rustc_target::abi::{Size, VariantIdx}; #[derive(Copy, Clone, Debug)] enum EdgeKind { @@ -244,6 +244,60 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, format!("bad index ({:?} != usize)", index_ty)) } } + if let ProjectionElem::Field(f, ty) = elem { + let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) }; + let parent_ty = parent.ty(&self.body.local_decls, self.tcx); + let fail_out_of_bounds = |this: &Self, location| { + this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty)); + }; + let check_equal = |this: &Self, location, f_ty| { + if !this.mir_assign_valid_types(ty, f_ty) { + this.fail( + location, + format!( + "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}", + parent, f, ty, f_ty + ) + ) + } + }; + match parent_ty.ty.kind() { + ty::Tuple(fields) => { + let Some(f_ty) = fields.get(f.as_usize()) else { + fail_out_of_bounds(self, location); + return; + }; + check_equal(self, location, *f_ty); + } + ty::Adt(adt_def, substs) => { + let var = parent_ty.variant_index.unwrap_or(VariantIdx::from_u32(0)); + let Some(field) = adt_def.variant(var).fields.get(f.as_usize()) else { + fail_out_of_bounds(self, location); + return; + }; + check_equal(self, location, field.ty(self.tcx, substs)); + } + ty::Closure(_, substs) => { + let substs = substs.as_closure(); + let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else { + fail_out_of_bounds(self, location); + return; + }; + check_equal(self, location, f_ty); + } + ty::Generator(_, substs, _) => { + let substs = substs.as_generator(); + let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else { + fail_out_of_bounds(self, location); + return; + }; + check_equal(self, location, f_ty); + } + _ => { + self.fail(location, format!("{:?} does not have fields", parent_ty.ty)); + } + } + } self.super_projection_elem(local, proj_base, elem, context, location); } |
