Auto merge of #34006 - eddyb:mir-const-fixes, r=nikomatsakis
[MIR] Fix double-rounding of float constants and ignore NaN sign in tests. Fixes #32805 by handling f32 and f64 separately in rustc_const_eval. Also removes `#[rustc_no_mir]` from a couple libstd tests by ignoring NaN sign. Turns out that runtime evaluation of `0.0 / 0.0` produces a NaN with the sign bit set, whereas LLVM constant folds it to a NaN with the sign bit unset, which we were testing for.
This commit is contained in:
commit
763f9234b0
@ -12,14 +12,12 @@
|
||||
use syntax::ast;
|
||||
use std::rc::Rc;
|
||||
use hir::def_id::DefId;
|
||||
use std::hash;
|
||||
use std::mem::transmute;
|
||||
use rustc_const_math::*;
|
||||
use self::ConstVal::*;
|
||||
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
|
||||
pub enum ConstVal {
|
||||
Float(f64),
|
||||
Float(ConstFloat),
|
||||
Integral(ConstInt),
|
||||
Str(InternedString),
|
||||
ByteStr(Rc<Vec<u8>>),
|
||||
@ -36,55 +34,10 @@ pub enum ConstVal {
|
||||
Dummy,
|
||||
}
|
||||
|
||||
impl hash::Hash for ConstVal {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
match *self {
|
||||
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
|
||||
Integral(a) => a.hash(state),
|
||||
Str(ref a) => a.hash(state),
|
||||
ByteStr(ref a) => a.hash(state),
|
||||
Bool(a) => a.hash(state),
|
||||
Struct(a) => a.hash(state),
|
||||
Tuple(a) => a.hash(state),
|
||||
Function(a) => a.hash(state),
|
||||
Array(a, n) => { a.hash(state); n.hash(state) },
|
||||
Repeat(a, n) => { a.hash(state); n.hash(state) },
|
||||
Char(c) => c.hash(state),
|
||||
Dummy => ().hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that equality for `ConstVal` means that the it is the same
|
||||
/// constant, not that the rust values are equal. In particular, `NaN
|
||||
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
|
||||
/// are considering unequal).
|
||||
impl PartialEq for ConstVal {
|
||||
fn eq(&self, other: &ConstVal) -> bool {
|
||||
match (self, other) {
|
||||
(&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
|
||||
(&Integral(a), &Integral(b)) => a == b,
|
||||
(&Str(ref a), &Str(ref b)) => a == b,
|
||||
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
|
||||
(&Bool(a), &Bool(b)) => a == b,
|
||||
(&Struct(a), &Struct(b)) => a == b,
|
||||
(&Tuple(a), &Tuple(b)) => a == b,
|
||||
(&Function(a), &Function(b)) => a == b,
|
||||
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
|
||||
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
|
||||
(&Char(a), &Char(b)) => a == b,
|
||||
(&Dummy, &Dummy) => true, // FIXME: should this be false?
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ConstVal { }
|
||||
|
||||
impl ConstVal {
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
Float(_) => "float",
|
||||
Float(f) => f.description(),
|
||||
Integral(i) => i.description(),
|
||||
Str(_) => "string literal",
|
||||
ByteStr(_) => "byte string literal",
|
||||
|
@ -621,18 +621,19 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
match (eval_const_expr_partial(tcx, &a, ty_hint, fn_args)?,
|
||||
eval_const_expr_partial(tcx, &b, b_ty, fn_args)?) {
|
||||
(Float(a), Float(b)) => {
|
||||
use std::cmp::Ordering::*;
|
||||
match op.node {
|
||||
hir::BiAdd => Float(a + b),
|
||||
hir::BiSub => Float(a - b),
|
||||
hir::BiMul => Float(a * b),
|
||||
hir::BiDiv => Float(a / b),
|
||||
hir::BiRem => Float(a % b),
|
||||
hir::BiEq => Bool(a == b),
|
||||
hir::BiLt => Bool(a < b),
|
||||
hir::BiLe => Bool(a <= b),
|
||||
hir::BiNe => Bool(a != b),
|
||||
hir::BiGe => Bool(a >= b),
|
||||
hir::BiGt => Bool(a > b),
|
||||
hir::BiAdd => Float(math!(e, a + b)),
|
||||
hir::BiSub => Float(math!(e, a - b)),
|
||||
hir::BiMul => Float(math!(e, a * b)),
|
||||
hir::BiDiv => Float(math!(e, a / b)),
|
||||
hir::BiRem => Float(math!(e, a % b)),
|
||||
hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
|
||||
hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
|
||||
hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
|
||||
hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
|
||||
hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
|
||||
hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
|
||||
_ => signal!(e, InvalidOpForFloats(op.node)),
|
||||
}
|
||||
}
|
||||
@ -1078,13 +1079,13 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::
|
||||
}
|
||||
},
|
||||
ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
|
||||
Infer(u) => Ok(Float(u as f64)),
|
||||
InferSigned(i) => Ok(Float(i as f64)),
|
||||
Infer(u) => Ok(Float(F64(u as f64))),
|
||||
InferSigned(i) => Ok(Float(F64(i as f64))),
|
||||
_ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
|
||||
},
|
||||
ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() {
|
||||
Infer(u) => Ok(Float(u as f32 as f64)),
|
||||
InferSigned(i) => Ok(Float(i as f32 as f64)),
|
||||
Infer(u) => Ok(Float(F32(u as f32))),
|
||||
InferSigned(i) => Ok(Float(F32(i as f32))),
|
||||
_ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
|
||||
},
|
||||
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
|
||||
@ -1097,13 +1098,35 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::
|
||||
}
|
||||
}
|
||||
|
||||
fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, f: f64, ty: ty::Ty) -> CastResult {
|
||||
fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
val: ConstFloat,
|
||||
ty: ty::Ty) -> CastResult {
|
||||
match ty.sty {
|
||||
ty::TyInt(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
|
||||
ty::TyInt(_) => cast_const_int(tcx, InferSigned(f as i64), ty),
|
||||
ty::TyUint(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
|
||||
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(f)),
|
||||
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(f as f32 as f64)),
|
||||
ty::TyInt(_) | ty::TyUint(_) => {
|
||||
let i = match val {
|
||||
F32(f) if f >= 0.0 => Infer(f as u64),
|
||||
FInfer { f64: f, .. } |
|
||||
F64(f) if f >= 0.0 => Infer(f as u64),
|
||||
|
||||
F32(f) => InferSigned(f as i64),
|
||||
FInfer { f64: f, .. } |
|
||||
F64(f) => InferSigned(f as i64)
|
||||
};
|
||||
|
||||
if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) {
|
||||
return Err(CannotCast);
|
||||
}
|
||||
|
||||
cast_const_int(tcx, i, ty)
|
||||
}
|
||||
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
|
||||
F32(f) => f as f64,
|
||||
FInfer { f64: f, .. } | F64(f) => f
|
||||
}))),
|
||||
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
|
||||
F64(f) => f as f32,
|
||||
FInfer { f32: f, .. } | F32(f) => f
|
||||
}))),
|
||||
_ => Err(CannotCast),
|
||||
}
|
||||
}
|
||||
@ -1161,33 +1184,43 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
|
||||
infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral)
|
||||
},
|
||||
|
||||
LitKind::Float(ref n, _) |
|
||||
LitKind::Float(ref n, fty) => {
|
||||
Ok(Float(parse_float(n, Some(fty), span)))
|
||||
}
|
||||
LitKind::FloatUnsuffixed(ref n) => {
|
||||
if let Ok(x) = n.parse::<f64>() {
|
||||
Ok(Float(x))
|
||||
} else {
|
||||
// FIXME(#31407) this is only necessary because float parsing is buggy
|
||||
span_bug!(span, "could not evaluate float literal (see issue #31407)");
|
||||
}
|
||||
let fty_hint = match ty_hint.map(|t| &t.sty) {
|
||||
Some(&ty::TyFloat(fty)) => Some(fty),
|
||||
_ => None
|
||||
};
|
||||
Ok(Float(parse_float(n, fty_hint, span)))
|
||||
}
|
||||
LitKind::Bool(b) => Ok(Bool(b)),
|
||||
LitKind::Char(c) => Ok(Char(c)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>, span: Span) -> ConstFloat {
|
||||
let val = match fty_hint {
|
||||
Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
|
||||
Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
|
||||
None => {
|
||||
num.parse::<f32>().and_then(|f32| {
|
||||
num.parse::<f64>().map(|f64| {
|
||||
FInfer { f32: f32, f64: f64 }
|
||||
})
|
||||
})
|
||||
}
|
||||
};
|
||||
val.unwrap_or_else(|_| {
|
||||
// FIXME(#31407) this is only necessary because float parsing is buggy
|
||||
span_bug!(span, "could not evaluate float literal (see issue #31407)");
|
||||
})
|
||||
}
|
||||
|
||||
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
|
||||
match (a, b) {
|
||||
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
|
||||
(&Float(a), &Float(b)) => {
|
||||
// This is pretty bad but it is the existing behavior.
|
||||
Some(if a == b {
|
||||
Ordering::Equal
|
||||
} else if a < b {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
})
|
||||
}
|
||||
(&Float(a), &Float(b)) => a.try_cmp(b).ok(),
|
||||
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
|
||||
(&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
|
||||
(&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
|
||||
|
@ -45,17 +45,17 @@ pub fn description(&self) -> &'static str {
|
||||
use self::Op::*;
|
||||
match *self {
|
||||
NotInRange => "inferred value out of range",
|
||||
CmpBetweenUnequalTypes => "compared two integrals of different types",
|
||||
UnequalTypes(Add) => "tried to add two integrals of different types",
|
||||
UnequalTypes(Sub) => "tried to subtract two integrals of different types",
|
||||
UnequalTypes(Mul) => "tried to multiply two integrals of different types",
|
||||
UnequalTypes(Div) => "tried to divide two integrals of different types",
|
||||
CmpBetweenUnequalTypes => "compared two values of different types",
|
||||
UnequalTypes(Add) => "tried to add two values of different types",
|
||||
UnequalTypes(Sub) => "tried to subtract two values of different types",
|
||||
UnequalTypes(Mul) => "tried to multiply two values of different types",
|
||||
UnequalTypes(Div) => "tried to divide two values of different types",
|
||||
UnequalTypes(Rem) => {
|
||||
"tried to calculate the remainder of two integrals of different types"
|
||||
"tried to calculate the remainder of two values of different types"
|
||||
},
|
||||
UnequalTypes(BitAnd) => "tried to bitand two integrals of different types",
|
||||
UnequalTypes(BitOr) => "tried to bitor two integrals of different types",
|
||||
UnequalTypes(BitXor) => "tried to xor two integrals of different types",
|
||||
UnequalTypes(BitAnd) => "tried to bitand two values of different types",
|
||||
UnequalTypes(BitOr) => "tried to bitor two values of different types",
|
||||
UnequalTypes(BitXor) => "tried to xor two values of different types",
|
||||
UnequalTypes(_) => unreachable!(),
|
||||
Overflow(Add) => "attempted to add with overflow",
|
||||
Overflow(Sub) => "attempted to subtract with overflow",
|
||||
|
173
src/librustc_const_math/float.rs
Normal file
173
src/librustc_const_math/float.rs
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::hash;
|
||||
use std::mem::transmute;
|
||||
|
||||
use super::err::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum ConstFloat {
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
|
||||
// When the type isn't known, we have to operate on both possibilities.
|
||||
FInfer {
|
||||
f32: f32,
|
||||
f64: f64
|
||||
}
|
||||
}
|
||||
pub use self::ConstFloat::*;
|
||||
|
||||
impl ConstFloat {
|
||||
/// Description of the type, not the value
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
FInfer {..} => "float",
|
||||
F32(_) => "f32",
|
||||
F64(_) => "f64",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_nan(&self) -> bool {
|
||||
match *self {
|
||||
F32(f) => f.is_nan(),
|
||||
F64(f) => f.is_nan(),
|
||||
FInfer { f32, f64 } => f32.is_nan() || f64.is_nan()
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares the values if they are of the same type
|
||||
pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
|
||||
match (self, rhs) {
|
||||
(F64(a), F64(b)) |
|
||||
(F64(a), FInfer { f64: b, .. }) |
|
||||
(FInfer { f64: a, .. }, F64(b)) |
|
||||
(FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
|
||||
// This is pretty bad but it is the existing behavior.
|
||||
Ok(if a == b {
|
||||
Ordering::Equal
|
||||
} else if a < b {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
})
|
||||
}
|
||||
|
||||
(F32(a), F32(b)) |
|
||||
(F32(a), FInfer { f32: b, .. }) |
|
||||
(FInfer { f32: a, .. }, F32(b)) => {
|
||||
Ok(if a == b {
|
||||
Ordering::Equal
|
||||
} else if a < b {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
})
|
||||
}
|
||||
|
||||
_ => Err(CmpBetweenUnequalTypes),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that equality for `ConstFloat` means that the it is the same
|
||||
/// constant, not that the rust values are equal. In particular, `NaN
|
||||
/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
|
||||
/// are considering unequal).
|
||||
impl PartialEq for ConstFloat {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (*self, *other) {
|
||||
(F64(a), F64(b)) |
|
||||
(F64(a), FInfer { f64: b, .. }) |
|
||||
(FInfer { f64: a, .. }, F64(b)) |
|
||||
(FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
|
||||
unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
|
||||
}
|
||||
(F32(a), F32(b)) => {
|
||||
unsafe{transmute::<_,u32>(a) == transmute::<_,u32>(b)}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ConstFloat {}
|
||||
|
||||
impl hash::Hash for ConstFloat {
|
||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||
match *self {
|
||||
F64(a) | FInfer { f64: a, .. } => {
|
||||
unsafe { transmute::<_,u64>(a) }.hash(state)
|
||||
}
|
||||
F32(a) => {
|
||||
unsafe { transmute::<_,u32>(a) }.hash(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for ConstFloat {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
match *self {
|
||||
FInfer { f64, .. } => write!(fmt, "{}", f64),
|
||||
F32(f) => write!(fmt, "{}f32", f),
|
||||
F64(f) => write!(fmt, "{}f64", f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! derive_binop {
|
||||
($op:ident, $func:ident) => {
|
||||
impl ::std::ops::$op for ConstFloat {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
match (self, rhs) {
|
||||
(F32(a), F32(b)) |
|
||||
(F32(a), FInfer { f32: b, .. }) |
|
||||
(FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))),
|
||||
|
||||
(F64(a), F64(b)) |
|
||||
(FInfer { f64: a, .. }, F64(b)) |
|
||||
(F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))),
|
||||
|
||||
(FInfer { f32: a32, f64: a64 },
|
||||
FInfer { f32: b32, f64: b64 }) => Ok(FInfer {
|
||||
f32: a32.$func(b32),
|
||||
f64: a64.$func(b64)
|
||||
}),
|
||||
|
||||
_ => Err(UnequalTypes(Op::$op)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
derive_binop!(Add, add);
|
||||
derive_binop!(Sub, sub);
|
||||
derive_binop!(Mul, mul);
|
||||
derive_binop!(Div, div);
|
||||
derive_binop!(Rem, rem);
|
||||
|
||||
impl ::std::ops::Neg for ConstFloat {
|
||||
type Output = Self;
|
||||
fn neg(self) -> Self {
|
||||
match self {
|
||||
F32(f) => F32(-f),
|
||||
F64(f) => F64(-f),
|
||||
FInfer { f32, f64 } => FInfer {
|
||||
f32: -f32,
|
||||
f64: -f64
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -32,11 +32,13 @@
|
||||
|
||||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
||||
mod float;
|
||||
mod int;
|
||||
mod us;
|
||||
mod is;
|
||||
mod err;
|
||||
|
||||
pub use float::*;
|
||||
pub use int::*;
|
||||
pub use us::*;
|
||||
pub use is::*;
|
||||
|
@ -56,7 +56,7 @@ pub fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
|
||||
}
|
||||
|
||||
// Returns a zero literal operand for the appropriate type, works for
|
||||
// bool, char, integers and floats.
|
||||
// bool, char and integers.
|
||||
pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = match ty.sty {
|
||||
ty::TyBool => {
|
||||
@ -93,7 +93,6 @@ pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
|
||||
Literal::Value { value: ConstVal::Integral(val) }
|
||||
}
|
||||
ty::TyFloat(_) => Literal::Value { value: ConstVal::Float(0.0) },
|
||||
_ => {
|
||||
span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc_const_eval::ErrKind;
|
||||
use rustc_const_math::ConstInt::*;
|
||||
use rustc_const_math::ConstFloat::*;
|
||||
use rustc_const_math::ConstMathErr;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::TransNormalize;
|
||||
@ -63,7 +64,9 @@ pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
-> Const<'tcx> {
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
let val = match cv {
|
||||
ConstVal::Float(v) => C_floating_f64(v, llty),
|
||||
ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
|
||||
ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
|
||||
ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
|
||||
ConstVal::Bool(v) => C_bool(ccx, v),
|
||||
ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
|
||||
ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
|
||||
@ -81,14 +84,14 @@ pub fn from_constval<'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
|
||||
C_integral(Type::int(ccx), u, false)
|
||||
},
|
||||
ConstVal::Integral(Infer(v)) => C_integral(llty, v as u64, false),
|
||||
ConstVal::Integral(InferSigned(v)) => C_integral(llty, v as u64, true),
|
||||
ConstVal::Integral(Infer(_)) |
|
||||
ConstVal::Integral(InferSigned(_)) => bug!("MIR must not use `{:?}`", cv),
|
||||
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
||||
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
|
||||
ConstVal::Struct(_) | ConstVal::Tuple(_) |
|
||||
ConstVal::Array(..) | ConstVal::Repeat(..) |
|
||||
ConstVal::Function(_) => {
|
||||
bug!("MIR must not use {:?} (which refers to a local ID)", cv)
|
||||
bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
|
||||
}
|
||||
ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
|
||||
ConstVal::Dummy => bug!(),
|
||||
|
@ -1382,7 +1382,6 @@ fn test_classify() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustc_no_mir] // FIXME #27840 MIR NAN ends up negative.
|
||||
fn test_integer_decode() {
|
||||
assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
|
||||
assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
|
||||
@ -1391,7 +1390,11 @@ fn test_integer_decode() {
|
||||
assert_eq!((-0f32).integer_decode(), (0, -150, -1));
|
||||
assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1));
|
||||
assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1));
|
||||
assert_eq!(NAN.integer_decode(), (12582912, 105, 1));
|
||||
|
||||
// Ignore the "sign" (quiet / signalling flag) of NAN.
|
||||
// It can vary between runtime operations and LLVM folding.
|
||||
let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
|
||||
assert_eq!((nan_m, nan_e), (12582912, 105));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1277,7 +1277,6 @@ fn test_classify() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustc_no_mir] // FIXME #27840 MIR NAN ends up negative.
|
||||
fn test_integer_decode() {
|
||||
assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
|
||||
assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
|
||||
@ -1286,7 +1285,11 @@ fn test_integer_decode() {
|
||||
assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
|
||||
assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1));
|
||||
assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
|
||||
assert_eq!(NAN.integer_decode(), (6755399441055744, 972, 1));
|
||||
|
||||
// Ignore the "sign" (quiet / signalling flag) of NAN.
|
||||
// It can vary between runtime operations and LLVM folding.
|
||||
let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
|
||||
assert_eq!((nan_m, nan_e), (6755399441055744, 972));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
26
src/test/run-pass/issue-32805.rs
Normal file
26
src/test/run-pass/issue-32805.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_mir]
|
||||
fn const_mir() -> f32 { 9007199791611905.0 }
|
||||
|
||||
#[rustc_no_mir]
|
||||
fn const_old() -> f32 { 9007199791611905.0 }
|
||||
|
||||
fn main() {
|
||||
let original = "9007199791611905.0"; // (1<<53)+(1<<29)+1
|
||||
let expected = "9007200000000000";
|
||||
|
||||
assert_eq!(const_mir().to_string(), expected);
|
||||
assert_eq!(const_old().to_string(), expected);
|
||||
assert_eq!(original.parse::<f32>().unwrap().to_string(), expected);
|
||||
}
|
Loading…
Reference in New Issue
Block a user