restructure unary_op to also dispatch on type first; fix promotion with unary '-' overflowing
This commit is contained in:
parent
066d2eea25
commit
e6a5a9418a
2 changed files with 62 additions and 42 deletions
|
@ -302,38 +302,33 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
let right = right.to_scalar()?;
|
let right = right.to_scalar()?;
|
||||||
|
|
||||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||||
bin_op, left, left_layout.ty.sty, right, right_layout.ty.sty);
|
bin_op, left, left_layout.ty, right, right_layout.ty);
|
||||||
|
|
||||||
match left_layout.ty.sty {
|
match left_layout.ty.sty {
|
||||||
ty::Char => {
|
ty::Char => {
|
||||||
assert_eq!(left_layout.ty, right_layout.ty);
|
assert_eq!(left_layout.ty, right_layout.ty);
|
||||||
let l = left.to_char()?;
|
let left = left.to_char()?;
|
||||||
let r = right.to_char()?;
|
let right = right.to_char()?;
|
||||||
self.binary_char_op(bin_op, l, r)
|
self.binary_char_op(bin_op, left, right)
|
||||||
}
|
}
|
||||||
ty::Bool => {
|
ty::Bool => {
|
||||||
assert_eq!(left_layout.ty, right_layout.ty);
|
assert_eq!(left_layout.ty, right_layout.ty);
|
||||||
let l = left.to_bool()?;
|
let left = left.to_bool()?;
|
||||||
let r = right.to_bool()?;
|
let right = right.to_bool()?;
|
||||||
self.binary_bool_op(bin_op, l, r)
|
self.binary_bool_op(bin_op, left, right)
|
||||||
}
|
}
|
||||||
ty::Float(fty) => {
|
ty::Float(fty) => {
|
||||||
assert_eq!(left_layout.ty, right_layout.ty);
|
assert_eq!(left_layout.ty, right_layout.ty);
|
||||||
let l = left.to_bits(left_layout.size)?;
|
let left = left.to_bits(left_layout.size)?;
|
||||||
let r = right.to_bits(right_layout.size)?;
|
let right = right.to_bits(right_layout.size)?;
|
||||||
self.binary_float_op(bin_op, fty, l, r)
|
self.binary_float_op(bin_op, fty, left, right)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// Must be integer(-like) types
|
// Must be integer(-like) types. Don't forget about == on fn pointers.
|
||||||
#[inline]
|
assert!(left_layout.ty.is_integral() || left_layout.ty.is_unsafe_ptr() ||
|
||||||
fn is_ptr<'tcx>(ty: ty::Ty<'tcx>) -> bool {
|
left_layout.ty.is_fn());
|
||||||
match ty.sty {
|
assert!(right_layout.ty.is_integral() || right_layout.ty.is_unsafe_ptr() ||
|
||||||
ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
|
right_layout.ty.is_fn());
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert!(left_layout.ty.is_integral() || is_ptr(left_layout.ty));
|
|
||||||
assert!(right_layout.ty.is_integral() || is_ptr(right_layout.ty));
|
|
||||||
|
|
||||||
// Handle operations that support pointer values
|
// Handle operations that support pointer values
|
||||||
if let Some(handled) =
|
if let Some(handled) =
|
||||||
|
@ -343,9 +338,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything else only works with "proper" bits
|
// Everything else only works with "proper" bits
|
||||||
let l = left.to_bits(left_layout.size)?;
|
let left = left.to_bits(left_layout.size)?;
|
||||||
let r = right.to_bits(right_layout.size)?;
|
let right = right.to_bits(right_layout.size)?;
|
||||||
self.binary_int_op(bin_op, l, left_layout, r, right_layout)
|
self.binary_int_op(bin_op, left, left_layout, right, right_layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,25 +355,42 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
use rustc_apfloat::ieee::{Single, Double};
|
use rustc_apfloat::ieee::{Single, Double};
|
||||||
use rustc_apfloat::Float;
|
use rustc_apfloat::Float;
|
||||||
|
|
||||||
let size = layout.size;
|
trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty.sty);
|
||||||
let bytes = val.to_bits(size)?;
|
|
||||||
|
|
||||||
let result_bytes = match (un_op, &layout.ty.sty) {
|
match layout.ty.sty {
|
||||||
|
ty::Bool => {
|
||||||
(Not, ty::Bool) => !val.to_bool()? as u128,
|
let val = val.to_bool()?;
|
||||||
|
let res = match un_op {
|
||||||
(Not, _) => !bytes,
|
Not => !val,
|
||||||
|
_ => bug!("Invalid bool op {:?}", un_op)
|
||||||
(Neg, ty::Float(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)),
|
};
|
||||||
(Neg, ty::Float(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)),
|
Ok(Scalar::from_bool(res))
|
||||||
|
}
|
||||||
(Neg, _) if bytes == (1 << (size.bits() - 1)) => return err!(OverflowNeg),
|
ty::Float(fty) => {
|
||||||
(Neg, _) => (-(bytes as i128)) as u128,
|
let val = val.to_bits(layout.size)?;
|
||||||
};
|
let res = match (un_op, fty) {
|
||||||
|
(Neg, FloatTy::F32) => Single::to_bits(-Single::from_bits(val)),
|
||||||
Ok(Scalar::Bits {
|
(Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)),
|
||||||
bits: self.truncate(result_bytes, layout),
|
_ => bug!("Invalid float op {:?}", un_op)
|
||||||
size: size.bytes() as u8,
|
};
|
||||||
})
|
Ok(Scalar::Bits { bits: res, size: layout.size.bytes() as u8 })
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
assert!(layout.ty.is_integral());
|
||||||
|
let val = val.to_bits(layout.size)?;
|
||||||
|
let res = match un_op {
|
||||||
|
Not => !val,
|
||||||
|
Neg => {
|
||||||
|
assert!(layout.abi.is_signed());
|
||||||
|
(-(val as i128)) as u128
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// res needs tuncating
|
||||||
|
Ok(Scalar::Bits {
|
||||||
|
bits: self.truncate(res, layout),
|
||||||
|
size: layout.size.bytes() as u8,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,18 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// compile-flags: -O
|
||||||
|
|
||||||
fn foo(_: &'static [&'static str]) {}
|
fn foo(_: &'static [&'static str]) {}
|
||||||
fn bar(_: &'static [&'static str; 3]) {}
|
fn bar(_: &'static [&'static str; 3]) {}
|
||||||
|
fn baz_i32(_: &'static i32) {}
|
||||||
|
fn baz_u32(_: &'static u32) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo(&["a", "b", "c"]);
|
foo(&["a", "b", "c"]);
|
||||||
bar(&["d", "e", "f"]);
|
bar(&["d", "e", "f"]);
|
||||||
|
|
||||||
|
// make sure that these do not cause trouble despite overflowing
|
||||||
|
baz_u32(&(0-1));
|
||||||
|
baz_i32(&-std::i32::MIN);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue