@@ -8,6 +8,33 @@ use rustc::mir::interpret::{EvalResult, Scalar};
8
8
9
9
use super :: { EvalContext , Machine } ;
10
10
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
+
11
38
impl < ' a , ' mir , ' tcx , M : Machine < ' mir , ' tcx > > EvalContext < ' a , ' mir , ' tcx , M > {
12
39
pub fn inc_step_counter_and_detect_loops ( & mut self ) -> EvalResult < ' tcx , ( ) > {
13
40
/// 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> {
147
174
}
148
175
149
176
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) ?;
152
181
self . binop_ignore_overflow (
153
182
bin_op,
154
183
left,
@@ -158,8 +187,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
158
187
}
159
188
160
189
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) ?;
163
194
self . binop_with_overflow (
164
195
bin_op,
165
196
left,
@@ -169,8 +200,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
169
200
}
170
201
171
202
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 ) ?;
174
206
self . write_scalar ( val, dest) ?;
175
207
}
176
208
0 commit comments