Skip to content

Commit c4168fd

Browse files
committed
Check that field projections have the correct type
1 parent 5289bbe commit c4168fd

File tree

1 file changed

+55
-1
lines changed

1 file changed

+55
-1
lines changed

compiler/rustc_const_eval/src/transform/validate.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
1414
use rustc_mir_dataflow::impls::MaybeStorageLive;
1515
use rustc_mir_dataflow::storage::AlwaysLiveLocals;
1616
use rustc_mir_dataflow::{Analysis, ResultsCursor};
17-
use rustc_target::abi::Size;
17+
use rustc_target::abi::{Size, VariantIdx};
1818

1919
#[derive(Copy, Clone, Debug)]
2020
enum EdgeKind {
@@ -244,6 +244,60 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
244244
self.fail(location, format!("bad index ({:?} != usize)", index_ty))
245245
}
246246
}
247+
if let ProjectionElem::Field(f, ty) = elem {
248+
let parent = Place { local, projection: self.tcx.intern_place_elems(proj_base) };
249+
let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
250+
let fail_out_of_bounds = |this: &Self, location| {
251+
this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
252+
};
253+
let check_equal = |this: &Self, location, f_ty| {
254+
if !this.mir_assign_valid_types(ty, f_ty) {
255+
this.fail(
256+
location,
257+
format!(
258+
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is {:?}",
259+
parent, f, ty, f_ty
260+
)
261+
)
262+
}
263+
};
264+
match parent_ty.ty.kind() {
265+
ty::Tuple(fields) => {
266+
let Some(f_ty) = fields.get(f.as_usize()) else {
267+
fail_out_of_bounds(self, location);
268+
return;
269+
};
270+
check_equal(self, location, *f_ty);
271+
}
272+
ty::Adt(adt_def, substs) => {
273+
let var = parent_ty.variant_index.unwrap_or(VariantIdx::from_u32(0));
274+
let Some(field) = adt_def.variant(var).fields.get(f.as_usize()) else {
275+
fail_out_of_bounds(self, location);
276+
return;
277+
};
278+
check_equal(self, location, field.ty(self.tcx, substs));
279+
}
280+
ty::Closure(_, substs) => {
281+
let substs = substs.as_closure();
282+
let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
283+
fail_out_of_bounds(self, location);
284+
return;
285+
};
286+
check_equal(self, location, f_ty);
287+
}
288+
ty::Generator(_, substs, _) => {
289+
let substs = substs.as_generator();
290+
let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
291+
fail_out_of_bounds(self, location);
292+
return;
293+
};
294+
check_equal(self, location, f_ty);
295+
}
296+
_ => {
297+
self.fail(location, format!("{:?} does not have fields", parent_ty.ty));
298+
}
299+
}
300+
}
247301
self.super_projection_elem(local, proj_base, elem, context, location);
248302
}
249303

0 commit comments

Comments
 (0)