Rollup merge of #96788 - JakobDegen:checked-binop, r=oli-obk
Improve validator around field projections and checked bin ops The two commits are unrelated. In both cases, these rules were already documented in MIR docs.
This commit is contained in:
commit
27a2bae89c
@ -14,7 +14,7 @@
|
||||
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 @@ fn visit_projection_elem(
|
||||
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);
|
||||
}
|
||||
|
||||
@ -291,7 +345,7 @@ macro_rules! check_kinds {
|
||||
ty::Array(..) | ty::Slice(..)
|
||||
);
|
||||
}
|
||||
Rvalue::BinaryOp(op, vals) | Rvalue::CheckedBinaryOp(op, vals) => {
|
||||
Rvalue::BinaryOp(op, vals) => {
|
||||
use BinOp::*;
|
||||
let a = vals.0.ty(&self.body.local_decls, self.tcx);
|
||||
let b = vals.1.ty(&self.body.local_decls, self.tcx);
|
||||
@ -355,19 +409,57 @@ macro_rules! check_kinds {
|
||||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot perform op on type {:?}",
|
||||
"Cannot perform arithmetic on type {:?}",
|
||||
ty::Uint(..) | ty::Int(..) | ty::Float(..)
|
||||
)
|
||||
}
|
||||
if a != b {
|
||||
self.fail(
|
||||
location,
|
||||
format!("Cannot perform op on unequal types {:?} and {:?}", a, b),
|
||||
format!(
|
||||
"Cannot perform arithmetic on unequal types {:?} and {:?}",
|
||||
a, b
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(op, vals) => {
|
||||
use BinOp::*;
|
||||
let a = vals.0.ty(&self.body.local_decls, self.tcx);
|
||||
let b = vals.1.ty(&self.body.local_decls, self.tcx);
|
||||
match op {
|
||||
Add | Sub | Mul => {
|
||||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot perform checked arithmetic on type {:?}",
|
||||
ty::Uint(..) | ty::Int(..)
|
||||
)
|
||||
}
|
||||
if a != b {
|
||||
self.fail(
|
||||
location,
|
||||
format!(
|
||||
"Cannot perform checked arithmetic on unequal types {:?} and {:?}",
|
||||
a, b
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Shl | Shr => {
|
||||
for x in [a, b] {
|
||||
check_kinds!(
|
||||
x,
|
||||
"Cannot perform checked shift on non-integer type {:?}",
|
||||
ty::Uint(..) | ty::Int(..)
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => self.fail(location, format!("There is no checked version of {:?}", op)),
|
||||
}
|
||||
}
|
||||
Rvalue::UnaryOp(op, operand) => {
|
||||
let a = operand.ty(&self.body.local_decls, self.tcx);
|
||||
match op {
|
||||
|
Loading…
Reference in New Issue
Block a user