@@ -8,6 +8,33 @@ use rustc::mir::interpret::{EvalResult, Scalar};
88
99use super :: { EvalContext , Machine } ;
1010
11+ /// Classify whether an operator is "left-homogeneous", i.e. the LHS has the
12+ /// same type as the result.
13+ #[ inline]
14+ fn binop_left_homogeneous ( op : mir:: BinOp ) -> bool {
15+ use rustc:: mir:: BinOp :: * ;
16+ match op {
17+ Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
18+ Offset | Shl | Shr =>
19+ true ,
20+ Eq | Ne | Lt | Le | Gt | Ge =>
21+ 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:: mir:: BinOp :: * ;
29+ match op {
30+ Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr |
31+ Eq | Ne | Lt | Le | Gt | Ge =>
32+ true ,
33+ Offset | Shl | Shr =>
34+ false ,
35+ }
36+ }
37+
1138impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > EvalContext < ' a , ' mir , ' tcx , M > {
1239 pub fn inc_step_counter_and_detect_loops ( & mut self ) -> EvalResult < ' tcx , ( ) > {
1340 /// The number of steps between loop detector snapshots.
@@ -147,8 +174,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
147174 }
148175
149176 BinaryOp ( bin_op, ref left, ref right) => {
150- let left = self . eval_operand_and_read_valty ( left) ?;
151- let right = self . eval_operand_and_read_valty ( right) ?;
177+ let layout = if binop_left_homogeneous ( bin_op) { Some ( dest. layout ) } else { None } ;
178+ let left = self . eval_operand_and_read_value ( left, layout) ?;
179+ let layout = if binop_right_homogeneous ( bin_op) { Some ( left. layout ) } else { None } ;
180+ let right = self . eval_operand_and_read_value ( right, layout) ?;
152181 self . binop_ignore_overflow (
153182 bin_op,
154183 left,
@@ -158,8 +187,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
158187 }
159188
160189 CheckedBinaryOp ( bin_op, ref left, ref right) => {
161- let left = self . eval_operand_and_read_valty ( left) ?;
162- let right = self . eval_operand_and_read_valty ( right) ?;
190+ // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
191+ let left = self . eval_operand_and_read_value ( left, None ) ?;
192+ let layout = if binop_right_homogeneous ( bin_op) { Some ( left. layout ) } else { None } ;
193+ let right = self . eval_operand_and_read_value ( right, layout) ?;
163194 self . binop_with_overflow (
164195 bin_op,
165196 left,
@@ -169,8 +200,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
169200 }
170201
171202 UnaryOp ( un_op, ref operand) => {
172- let val = self . eval_operand_and_read_scalar ( operand) ?;
173- let val = self . unary_op ( un_op, val. not_undef ( ) ?, dest. layout ) ?;
203+ // The operand always has the same type as the result.
204+ let val = self . eval_operand_and_read_value ( operand, Some ( dest. layout ) ) ?;
205+ let val = self . unary_op ( un_op, val. to_scalar ( ) ?, dest. layout ) ?;
174206 self . write_scalar ( val, dest) ?;
175207 }
176208
0 commit comments