Skip to content

Commit a11e9ed

Browse files
committed
restructure unary_op to also dispatch on type first; fix promotion with unary '-' overflowing
1 parent 1e35088 commit a11e9ed

File tree

2 files changed

+62
-42
lines changed

2 files changed

+62
-42
lines changed

src/librustc_mir/interpret/operator.rs

+54-42
Original file line numberDiff line numberDiff line change
@@ -302,38 +302,33 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
302302
let right = right.to_scalar()?;
303303

304304
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
305-
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);
305+
bin_op, left, left_layout.ty, right, right_layout.ty);
306306

307307
match left_layout.ty.sty {
308308
ty::Char => {
309309
assert_eq!(left_layout.ty, right_layout.ty);
310-
let l = left.to_char()?;
311-
let r = right.to_char()?;
312-
self.binary_char_op(bin_op, l, r)
310+
let left = left.to_char()?;
311+
let right = right.to_char()?;
312+
self.binary_char_op(bin_op, left, right)
313313
}
314314
ty::Bool => {
315315
assert_eq!(left_layout.ty, right_layout.ty);
316-
let l = left.to_bool()?;
317-
let r = right.to_bool()?;
318-
self.binary_bool_op(bin_op, l, r)
316+
let left = left.to_bool()?;
317+
let right = right.to_bool()?;
318+
self.binary_bool_op(bin_op, left, right)
319319
}
320320
ty::Float(fty) => {
321321
assert_eq!(left_layout.ty, right_layout.ty);
322-
let l = left.to_bits(left_layout.size)?;
323-
let r = right.to_bits(right_layout.size)?;
324-
self.binary_float_op(bin_op, fty, l, r)
322+
let left = left.to_bits(left_layout.size)?;
323+
let right = right.to_bits(right_layout.size)?;
324+
self.binary_float_op(bin_op, fty, left, right)
325325
}
326326
_ => {
327-
// Must be integer(-like) types
328-
#[inline]
329-
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
330-
match ty.sty {
331-
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
332-
_ => false,
333-
}
334-
}
335-
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
336-
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));
327+
// Must be integer(-like) types. Don't forget about == on fn pointers.
328+
assert!(left_layout.ty.is_integral() || left_layout.ty.is_unsafe_ptr() ||
329+
left_layout.ty.is_fn());
330+
assert!(right_layout.ty.is_integral() || right_layout.ty.is_unsafe_ptr() ||
331+
right_layout.ty.is_fn());
337332

338333
// Handle operations that support pointer values
339334
if let Some(handled) =
@@ -343,9 +338,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
343338
}
344339

345340
// Everything else only works with "proper" bits
346-
let l = left.to_bits(left_layout.size)?;
347-
let r = right.to_bits(right_layout.size)?;
348-
self.binary_int_op(bin_op, l, left_layout, r, right_layout)
341+
let left = left.to_bits(left_layout.size)?;
342+
let right = right.to_bits(right_layout.size)?;
343+
self.binary_int_op(bin_op, left, left_layout, right, right_layout)
349344
}
350345
}
351346
}
@@ -360,25 +355,42 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
360355
use rustc_apfloat::ieee::{Single, Double};
361356
use rustc_apfloat::Float;
362357

363-
let size = layout.size;
364-
let bytes = val.to_bits(size)?;
365-
366-
let result_bytes = match (un_op, &layout.ty.sty) {
367-
368-
(Not, ty::Bool) => !val.to_bool()? as u128,
369-
370-
(Not, _) => !bytes,
358+
trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty.sty);
371359

372-
(Neg, ty::Float(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)),
373-
(Neg, ty::Float(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)),
374-
375-
(Neg, _) if bytes == (1 << (size.bits() - 1)) => return err!(OverflowNeg),
376-
(Neg, _) => (-(bytes as i128)) as u128,
377-
};
378-
379-
Ok(Scalar::Bits {
380-
bits: self.truncate(result_bytes, layout),
381-
size: size.bytes() as u8,
382-
})
360+
match layout.ty.sty {
361+
ty::Bool => {
362+
let val = val.to_bool()?;
363+
let res = match un_op {
364+
Not => !val,
365+
_ => bug!("Invalid bool op {:?}", un_op)
366+
};
367+
Ok(Scalar::from_bool(res))
368+
}
369+
ty::Float(fty) => {
370+
let val = val.to_bits(layout.size)?;
371+
let res = match (un_op, fty) {
372+
(Neg, FloatTy::F32) => Single::to_bits(-Single::from_bits(val)),
373+
(Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)),
374+
_ => bug!("Invalid float op {:?}", un_op)
375+
};
376+
Ok(Scalar::Bits { bits: res, size: layout.size.bytes() as u8 })
377+
}
378+
_ => {
379+
assert!(layout.ty.is_integral());
380+
let val = val.to_bits(layout.size)?;
381+
let res = match un_op {
382+
Not => !val,
383+
Neg => {
384+
assert!(layout.abi.is_signed());
385+
(-(val as i128)) as u128
386+
}
387+
};
388+
// res needs tuncating
389+
Ok(Scalar::Bits {
390+
bits: self.truncate(res, layout),
391+
size: layout.size.bytes() as u8,
392+
})
393+
}
394+
}
383395
}
384396
}

src/test/run-pass/ctfe/promotion.rs

+8
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,18 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// compile-flags: -O
12+
1113
fn foo(_: &'static [&'static str]) {}
1214
fn bar(_: &'static [&'static str; 3]) {}
15+
fn baz_i32(_: &'static i32) {}
16+
fn baz_u32(_: &'static u32) {}
1317

1418
fn main() {
1519
foo(&["a", "b", "c"]);
1620
bar(&["d", "e", "f"]);
21+
22+
// make sure that these do not cause trouble despite overflowing
23+
baz_u32(&(0-1));
24+
baz_i32(&-std::i32::MIN);
1725
}

0 commit comments

Comments
 (0)