Skip to content

Commit c780e55

Browse files
committed
Dedup some type checks in the MIR validator
1 parent 3fd8501 commit c780e55

File tree

3 files changed

+57
-76
lines changed

3 files changed

+57
-76
lines changed

compiler/rustc_const_eval/src/interpret/step.rs

+4-26
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,7 @@ use rustc_middle::mir::interpret::{InterpResult, Scalar};
99
use rustc_middle::ty::layout::LayoutOf;
1010

1111
use super::{ImmTy, InterpCx, Machine};
12-
13-
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
14-
/// same type as the result.
15-
#[inline]
16-
fn binop_left_homogeneous(op: mir::BinOp) -> bool {
17-
use rustc_middle::mir::BinOp::*;
18-
match op {
19-
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
20-
| BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
21-
Eq | Ne | Lt | Le | Gt | Ge => false,
22-
}
23-
}
24-
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
25-
/// same type as the LHS.
26-
#[inline]
27-
fn binop_right_homogeneous(op: mir::BinOp) -> bool {
28-
use rustc_middle::mir::BinOp::*;
29-
match op {
30-
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
31-
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
32-
Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
33-
}
34-
}
12+
use crate::util;
3513

3614
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3715
/// Returns `true` as long as there are more things to do.
@@ -181,17 +159,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
181159
}
182160

183161
BinaryOp(bin_op, box (ref left, ref right)) => {
184-
let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
162+
let layout = util::binop_left_homogeneous(bin_op).then_some(dest.layout);
185163
let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
186-
let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
164+
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
187165
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
188166
self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
189167
}
190168

191169
CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
192170
// Due to the extra boolean in the result, we can never reuse the `dest.layout`.
193171
let left = self.read_immediate(&self.eval_operand(left, None)?)?;
194-
let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
172+
let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
195173
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
196174
self.binop_with_overflow(bin_op, &left, &right, &dest)?;
197175
}

compiler/rustc_const_eval/src/transform/validate.rs

+27-50
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
498498

499499
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
500500
macro_rules! check_kinds {
501-
($t:expr, $text:literal, $($patterns:tt)*) => {
502-
if !matches!(($t).kind(), $($patterns)*) {
501+
($t:expr, $text:literal, $typat:pat) => {
502+
if !matches!(($t).kind(), $typat) {
503503
self.fail(location, format!($text, $t));
504504
}
505505
};
@@ -527,6 +527,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
527527
use BinOp::*;
528528
let a = vals.0.ty(&self.body.local_decls, self.tcx);
529529
let b = vals.1.ty(&self.body.local_decls, self.tcx);
530+
if crate::util::binop_right_homogeneous(*op) {
531+
if let Eq | Lt | Le | Ne | Ge | Gt = op {
532+
// The function pointer types can have lifetimes
533+
if !self.mir_assign_valid_types(a, b) {
534+
self.fail(
535+
location,
536+
format!("Cannot {op:?} compare incompatible types {a:?} and {b:?}"),
537+
);
538+
}
539+
} else if a != b {
540+
self.fail(
541+
location,
542+
format!(
543+
"Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}"
544+
),
545+
);
546+
}
547+
}
548+
530549
match op {
531550
Offset => {
532551
check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..));
@@ -538,7 +557,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
538557
for x in [a, b] {
539558
check_kinds!(
540559
x,
541-
"Cannot compare type {:?}",
560+
"Cannot {op:?} compare type {:?}",
542561
ty::Bool
543562
| ty::Char
544563
| ty::Int(..)
@@ -548,19 +567,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
548567
| ty::FnPtr(..)
549568
)
550569
}
551-
// The function pointer types can have lifetimes
552-
if !self.mir_assign_valid_types(a, b) {
553-
self.fail(
554-
location,
555-
format!("Cannot compare unequal types {:?} and {:?}", a, b),
556-
);
557-
}
558570
}
559-
Shl | ShlUnchecked | Shr | ShrUnchecked => {
571+
AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
572+
| ShrUnchecked => {
560573
for x in [a, b] {
561574
check_kinds!(
562575
x,
563-
"Cannot shift non-integer type {:?}",
576+
"Cannot {op:?} non-integer type {:?}",
564577
ty::Uint(..) | ty::Int(..)
565578
)
566579
}
@@ -569,55 +582,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
569582
for x in [a, b] {
570583
check_kinds!(
571584
x,
572-
"Cannot perform bitwise op on type {:?}",
585+
"Cannot perform bitwise op {op:?} on type {:?}",
573586
ty::Uint(..) | ty::Int(..) | ty::Bool
574587
)
575588
}
576-
if a != b {
577-
self.fail(
578-
location,
579-
format!(
580-
"Cannot perform bitwise op on unequal types {:?} and {:?}",
581-
a, b
582-
),
583-
);
584-
}
585589
}
586590
Add | Sub | Mul | Div | Rem => {
587591
for x in [a, b] {
588592
check_kinds!(
589593
x,
590-
"Cannot perform arithmetic on type {:?}",
594+
"Cannot perform arithmetic {op:?} on type {:?}",
591595
ty::Uint(..) | ty::Int(..) | ty::Float(..)
592596
)
593597
}
594-
if a != b {
595-
self.fail(
596-
location,
597-
format!(
598-
"Cannot perform arithmetic on unequal types {:?} and {:?}",
599-
a, b
600-
),
601-
);
602-
}
603-
}
604-
AddUnchecked | SubUnchecked | MulUnchecked => {
605-
for x in [a, b] {
606-
check_kinds!(
607-
x,
608-
"Cannot perform unchecked arithmetic on type {:?}",
609-
ty::Uint(..) | ty::Int(..)
610-
)
611-
}
612-
if a != b {
613-
self.fail(
614-
location,
615-
format!(
616-
"Cannot perform unchecked arithmetic on unequal types {:?} and {:?}",
617-
a, b
618-
),
619-
);
620-
}
621598
}
622599
}
623600
}

compiler/rustc_const_eval/src/util/mod.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use rustc_middle::mir;
2+
13
mod alignment;
24
mod check_validity_requirement;
35
mod compare_types;
@@ -7,3 +9,27 @@ pub use self::alignment::is_disaligned;
79
pub use self::check_validity_requirement::check_validity_requirement;
810
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
911
pub use self::type_name::type_name;
12+
13+
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
14+
/// same type as the result.
15+
#[inline]
16+
pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool {
17+
use rustc_middle::mir::BinOp::*;
18+
match op {
19+
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
20+
| BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
21+
Eq | Ne | Lt | Le | Gt | Ge => false,
22+
}
23+
}
24+
25+
/// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
26+
/// same type as the LHS.
27+
#[inline]
28+
pub(crate) fn binop_right_homogeneous(op: mir::BinOp) -> bool {
29+
use rustc_middle::mir::BinOp::*;
30+
match op {
31+
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
32+
| BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge => true,
33+
Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
34+
}
35+
}

0 commit comments

Comments
 (0)