Auto merge of #50198 - oli-obk:const_prop, r=eddyb
Remove some unused code
This commit is contained in:
commit
0d8321b5e8
14
src/Cargo.lock
generated
14
src/Cargo.lock
generated
@ -1728,7 +1728,6 @@ dependencies = [
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc_macro 0.0.0",
|
||||
"rustc_apfloat 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_target 0.0.0",
|
||||
@ -1872,15 +1871,6 @@ dependencies = [
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_const_math"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_apfloat 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_cratesio_shim"
|
||||
version = "0.0.0"
|
||||
@ -2026,7 +2016,6 @@ dependencies = [
|
||||
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_apfloat 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_target 0.0.0",
|
||||
@ -2053,7 +2042,6 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_mir 0.0.0",
|
||||
@ -2154,7 +2142,6 @@ dependencies = [
|
||||
"rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_allocator 0.0.0",
|
||||
"rustc_apfloat 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_incremental 0.0.0",
|
||||
@ -2205,7 +2192,6 @@ dependencies = [
|
||||
"fmt_macros 0.0.0",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
"rustc_platform_intrinsics 0.0.0",
|
||||
|
@ -19,7 +19,6 @@ log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||
proc_macro = { path = "../libproc_macro" }
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
serialize = { path = "../libserialize" }
|
||||
|
@ -1,44 +0,0 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
//! This module contains `HashStable` implementations for various data types
|
||||
//! from `rustc_const_math` in no particular order.
|
||||
|
||||
impl_stable_hash_for!(struct ::rustc_const_math::ConstFloat {
|
||||
ty,
|
||||
bits
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr {
|
||||
NotInRange,
|
||||
CmpBetweenUnequalTypes,
|
||||
UnequalTypes(op),
|
||||
Overflow(op),
|
||||
ShiftNegative,
|
||||
DivisionByZero,
|
||||
RemainderByZero,
|
||||
UnsignedNegation,
|
||||
ULitOutOfRange(int_ty),
|
||||
LitOutOfRange(int_ty)
|
||||
});
|
||||
|
||||
impl_stable_hash_for!(enum ::rustc_const_math::Op {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Rem,
|
||||
Shr,
|
||||
Shl,
|
||||
Neg,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor
|
||||
});
|
@ -227,27 +227,6 @@ for mir::TerminatorKind<'gcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for mir::AssertMessage<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
|
||||
match *self {
|
||||
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
|
||||
len.hash_stable(hcx, hasher);
|
||||
index.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::AssertMessage::Math(ref const_math_err) => {
|
||||
const_math_err.hash_stable(hcx, hasher);
|
||||
}
|
||||
mir::AssertMessage::GeneratorResumedAfterReturn => (),
|
||||
mir::AssertMessage::GeneratorResumedAfterPanic => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
|
@ -505,9 +505,6 @@ for ::middle::const_val::ErrKind<'gcx> {
|
||||
len.hash_stable(hcx, hasher);
|
||||
index.hash_stable(hcx, hasher);
|
||||
}
|
||||
Math(ref const_math_err) => {
|
||||
const_math_err.hash_stable(hcx, hasher);
|
||||
}
|
||||
LayoutError(ref layout_error) => {
|
||||
layout_error.hash_stable(hcx, hasher);
|
||||
}
|
||||
@ -528,16 +525,26 @@ impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
|
||||
predicates
|
||||
});
|
||||
|
||||
|
||||
impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
|
||||
for ::mir::interpret::EvalError<'gcx> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
self.kind.hash_stable(hcx, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, O: HashStable<StableHashingContext<'a>>> HashStable<StableHashingContext<'a>>
|
||||
for ::mir::interpret::EvalErrorKind<'gcx, O> {
|
||||
fn hash_stable<W: StableHasherResult>(&self,
|
||||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
use mir::interpret::EvalErrorKind::*;
|
||||
|
||||
mem::discriminant(&self.kind).hash_stable(hcx, hasher);
|
||||
mem::discriminant(&self).hash_stable(hcx, hasher);
|
||||
|
||||
match self.kind {
|
||||
match *self {
|
||||
DanglingPointerDeref |
|
||||
DoubleFree |
|
||||
InvalidMemoryAccess |
|
||||
@ -568,8 +575,12 @@ for ::mir::interpret::EvalError<'gcx> {
|
||||
TypeckError |
|
||||
DerefFunctionPointer |
|
||||
ExecuteMemory |
|
||||
ReferencedConstant |
|
||||
OverflowingMath => {}
|
||||
OverflowNeg |
|
||||
RemainderByZero |
|
||||
DivisionByZero |
|
||||
GeneratorResumedAfterReturn |
|
||||
GeneratorResumedAfterPanic |
|
||||
ReferencedConstant => {}
|
||||
MachineError(ref err) => err.hash_stable(hcx, hasher),
|
||||
FunctionPointerTyMismatch(a, b) => {
|
||||
a.hash_stable(hcx, hasher);
|
||||
@ -588,14 +599,9 @@ for ::mir::interpret::EvalError<'gcx> {
|
||||
},
|
||||
InvalidBoolOp(bop) => bop.hash_stable(hcx, hasher),
|
||||
Unimplemented(ref s) => s.hash_stable(hcx, hasher),
|
||||
ArrayIndexOutOfBounds(sp, a, b) => {
|
||||
sp.hash_stable(hcx, hasher);
|
||||
a.hash_stable(hcx, hasher);
|
||||
b.hash_stable(hcx, hasher)
|
||||
},
|
||||
Math(sp, ref err) => {
|
||||
sp.hash_stable(hcx, hasher);
|
||||
err.hash_stable(hcx, hasher)
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
len.hash_stable(hcx, hasher);
|
||||
index.hash_stable(hcx, hasher)
|
||||
},
|
||||
Intrinsic(ref s) => s.hash_stable(hcx, hasher),
|
||||
InvalidChar(c) => c.hash_stable(hcx, hasher),
|
||||
@ -668,6 +674,7 @@ for ::mir::interpret::EvalError<'gcx> {
|
||||
Layout(lay) => lay.hash_stable(hcx, hasher),
|
||||
HeapAllocNonPowerOfTwoAlignment(n) => n.hash_stable(hcx, hasher),
|
||||
PathNotFound(ref v) => v.hash_stable(hcx, hasher),
|
||||
Overflow(op) => op.hash_stable(hcx, hasher),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ mod fingerprint;
|
||||
mod caching_codemap_view;
|
||||
mod hcx;
|
||||
|
||||
mod impls_const_math;
|
||||
mod impls_cstore;
|
||||
mod impls_hir;
|
||||
mod impls_mir;
|
||||
|
@ -85,7 +85,6 @@ extern crate libc;
|
||||
extern crate rustc_target;
|
||||
#[macro_use] extern crate rustc_data_structures;
|
||||
extern crate serialize;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_errors as errors;
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate syntax;
|
||||
|
@ -11,7 +11,6 @@
|
||||
use hir::def_id::DefId;
|
||||
use ty::{self, TyCtxt, layout};
|
||||
use ty::subst::Substs;
|
||||
use rustc_const_math::*;
|
||||
use mir::interpret::{Value, PrimVal};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
@ -62,7 +61,6 @@ pub enum ErrKind<'tcx> {
|
||||
UnimplementedConstVal(&'static str),
|
||||
IndexOutOfBounds { len: u64, index: u64 },
|
||||
|
||||
Math(ConstMathErr),
|
||||
LayoutError(layout::LayoutError<'tcx>),
|
||||
|
||||
TypeckError,
|
||||
@ -76,15 +74,6 @@ pub struct FrameInfo {
|
||||
pub location: String,
|
||||
}
|
||||
|
||||
impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
|
||||
fn from(err: ConstMathErr) -> ErrKind<'tcx> {
|
||||
match err {
|
||||
ConstMathErr::UnsignedNegation => ErrKind::TypeckError,
|
||||
_ => ErrKind::Math(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ConstEvalErrDescription<'a, 'tcx: 'a> {
|
||||
Simple(Cow<'a, str>),
|
||||
@ -122,7 +111,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
|
||||
len, index)
|
||||
}
|
||||
|
||||
Math(ref err) => Simple(err.description().into_cow()),
|
||||
LayoutError(ref err) => Simple(err.to_string().into_cow()),
|
||||
|
||||
TypeckError => simple!("type-checking failed"),
|
||||
|
@ -1,4 +1,3 @@
|
||||
use std::error::Error;
|
||||
use std::{fmt, env};
|
||||
|
||||
use mir;
|
||||
@ -8,18 +7,16 @@ use super::{
|
||||
MemoryPointer, Lock, AccessKind
|
||||
};
|
||||
|
||||
use rustc_const_math::ConstMathErr;
|
||||
use syntax::codemap::Span;
|
||||
use backtrace::Backtrace;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EvalError<'tcx> {
|
||||
pub kind: EvalErrorKind<'tcx>,
|
||||
pub kind: EvalErrorKind<'tcx, u64>,
|
||||
pub backtrace: Option<Backtrace>,
|
||||
}
|
||||
|
||||
impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
|
||||
fn from(kind: EvalErrorKind<'tcx>) -> Self {
|
||||
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
|
||||
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
|
||||
let backtrace = match env::var("MIRI_BACKTRACE") {
|
||||
Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()),
|
||||
_ => None
|
||||
@ -31,8 +28,10 @@ impl<'tcx> From<EvalErrorKind<'tcx>> for EvalError<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum EvalErrorKind<'tcx> {
|
||||
pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>;
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum EvalErrorKind<'tcx, O> {
|
||||
/// This variant is used by machines to signal their own errors that do not
|
||||
/// match an existing variant
|
||||
MachineError(String),
|
||||
@ -60,10 +59,12 @@ pub enum EvalErrorKind<'tcx> {
|
||||
Unimplemented(String),
|
||||
DerefFunctionPointer,
|
||||
ExecuteMemory,
|
||||
ArrayIndexOutOfBounds(Span, u64, u64),
|
||||
Math(Span, ConstMathErr),
|
||||
BoundsCheck { len: O, index: O },
|
||||
Overflow(mir::BinOp),
|
||||
OverflowNeg,
|
||||
DivisionByZero,
|
||||
RemainderByZero,
|
||||
Intrinsic(String),
|
||||
OverflowingMath,
|
||||
InvalidChar(u128),
|
||||
StackFrameLimitReached,
|
||||
OutOfTls,
|
||||
@ -121,14 +122,16 @@ pub enum EvalErrorKind<'tcx> {
|
||||
/// Cannot compute this constant because it depends on another one
|
||||
/// which already produced an error
|
||||
ReferencedConstant,
|
||||
GeneratorResumedAfterReturn,
|
||||
GeneratorResumedAfterPanic,
|
||||
}
|
||||
|
||||
pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
|
||||
|
||||
impl<'tcx> Error for EvalError<'tcx> {
|
||||
fn description(&self) -> &str {
|
||||
impl<'tcx, O> EvalErrorKind<'tcx, O> {
|
||||
pub fn description(&self) -> &str {
|
||||
use self::EvalErrorKind::*;
|
||||
match self.kind {
|
||||
match *self {
|
||||
MachineError(ref inner) => inner,
|
||||
FunctionPointerTyMismatch(..) =>
|
||||
"tried to call a function through a function pointer of a different type",
|
||||
@ -175,14 +178,10 @@ impl<'tcx> Error for EvalError<'tcx> {
|
||||
"tried to dereference a function pointer",
|
||||
ExecuteMemory =>
|
||||
"tried to treat a memory pointer as a function pointer",
|
||||
ArrayIndexOutOfBounds(..) =>
|
||||
BoundsCheck{..} =>
|
||||
"array index out of bounds",
|
||||
Math(..) =>
|
||||
"mathematical operation failed",
|
||||
Intrinsic(..) =>
|
||||
"intrinsic failed",
|
||||
OverflowingMath =>
|
||||
"attempted to do overflowing math",
|
||||
NoMirFor(..) =>
|
||||
"mir not found",
|
||||
InvalidChar(..) =>
|
||||
@ -232,7 +231,7 @@ impl<'tcx> Error for EvalError<'tcx> {
|
||||
"the evaluated program panicked",
|
||||
ReadFromReturnPointer =>
|
||||
"tried to read from the return pointer",
|
||||
EvalErrorKind::PathNotFound(_) =>
|
||||
PathNotFound(_) =>
|
||||
"a path could not be resolved, maybe the crate is not loaded",
|
||||
UnimplementedTraitSelection =>
|
||||
"there were unresolved type arguments during trait selection",
|
||||
@ -240,14 +239,33 @@ impl<'tcx> Error for EvalError<'tcx> {
|
||||
"encountered constants with type errors, stopping evaluation",
|
||||
ReferencedConstant =>
|
||||
"referenced constant has errors",
|
||||
Overflow(mir::BinOp::Add) => "attempt to add with overflow",
|
||||
Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
|
||||
Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
|
||||
Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
|
||||
Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
|
||||
OverflowNeg => "attempt to negate with overflow",
|
||||
Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
|
||||
Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
|
||||
Overflow(op) => bug!("{:?} cannot overflow", op),
|
||||
DivisionByZero => "attempt to divide by zero",
|
||||
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
|
||||
GeneratorResumedAfterReturn => "generator resumed after completion",
|
||||
GeneratorResumedAfterPanic => "generator resumed after panicking",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> fmt::Display for EvalError<'tcx> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self.kind)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use self::EvalErrorKind::*;
|
||||
match self.kind {
|
||||
match *self {
|
||||
PointerOutOfBounds { ptr, access, allocation_size } => {
|
||||
write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}",
|
||||
if access { "memory access" } else { "pointer computed" },
|
||||
@ -275,14 +293,12 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
|
||||
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
|
||||
FunctionPointerTyMismatch(sig, got) =>
|
||||
write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
|
||||
ArrayIndexOutOfBounds(span, len, index) =>
|
||||
write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
|
||||
BoundsCheck { ref len, ref index } =>
|
||||
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
|
||||
ReallocatedWrongMemoryKind(ref old, ref new) =>
|
||||
write!(f, "tried to reallocate memory from {} to {}", old, new),
|
||||
DeallocatedWrongMemoryKind(ref old, ref new) =>
|
||||
write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
|
||||
Math(_, ref err) =>
|
||||
write!(f, "{}", err.description()),
|
||||
Intrinsic(ref err) =>
|
||||
write!(f, "{}", err),
|
||||
InvalidChar(c) =>
|
||||
|
@ -8,7 +8,7 @@ macro_rules! err {
|
||||
mod error;
|
||||
mod value;
|
||||
|
||||
pub use self::error::{EvalError, EvalResult, EvalErrorKind};
|
||||
pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
|
||||
|
||||
pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
|
||||
|
||||
@ -23,7 +23,7 @@ use std::iter;
|
||||
use syntax::ast::Mutability;
|
||||
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Lock {
|
||||
NoLock,
|
||||
WriteLock(DynamicLifetime),
|
||||
@ -31,13 +31,13 @@ pub enum Lock {
|
||||
ReadLock(Vec<DynamicLifetime>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct DynamicLifetime {
|
||||
pub frame: usize,
|
||||
pub region: Option<region::Scope>, // "None" indicates "until the function ends"
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
|
||||
pub enum AccessKind {
|
||||
Read,
|
||||
Write,
|
||||
@ -88,12 +88,12 @@ pub trait PointerArithmetic: layout::HasDataLayout {
|
||||
|
||||
fn signed_offset<'tcx>(self, val: u64, i: i64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_signed_offset(val, i as i128);
|
||||
if over { err!(OverflowingMath) } else { Ok(res) }
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
fn offset<'tcx>(self, val: u64, i: u64) -> EvalResult<'tcx, u64> {
|
||||
let (res, over) = self.overflowing_offset(val, i);
|
||||
if over { err!(OverflowingMath) } else { Ok(res) }
|
||||
if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) }
|
||||
}
|
||||
|
||||
fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 {
|
||||
|
@ -15,7 +15,6 @@
|
||||
use graphviz::IntoCow;
|
||||
use middle::const_val::ConstVal;
|
||||
use middle::region;
|
||||
use rustc_const_math::ConstMathErr;
|
||||
use rustc_data_structures::sync::{Lrc};
|
||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
||||
use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
|
||||
@ -26,7 +25,7 @@ use rustc_serialize as serialize;
|
||||
use hir::def::CtorKind;
|
||||
use hir::def_id::DefId;
|
||||
use mir::visit::MirVisitable;
|
||||
use mir::interpret::{Value, PrimVal};
|
||||
use mir::interpret::{Value, PrimVal, EvalErrorKind};
|
||||
use ty::subst::{Subst, Substs};
|
||||
use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior};
|
||||
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||
@ -43,6 +42,10 @@ use std::vec::IntoIter;
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::symbol::InternedString;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc_apfloat::Float;
|
||||
|
||||
pub use mir::interpret::AssertMessage;
|
||||
|
||||
mod cache;
|
||||
pub mod tcx;
|
||||
@ -1130,26 +1133,7 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
if !expected {
|
||||
write!(fmt, "!")?;
|
||||
}
|
||||
write!(fmt, "{:?}, ", cond)?;
|
||||
|
||||
match *msg {
|
||||
AssertMessage::BoundsCheck { ref len, ref index } => {
|
||||
write!(fmt, "{:?}, {:?}, {:?}",
|
||||
"index out of bounds: the len is {} but the index is {}",
|
||||
len, index)?;
|
||||
}
|
||||
AssertMessage::Math(ref err) => {
|
||||
write!(fmt, "{:?}", err.description())?;
|
||||
}
|
||||
AssertMessage::GeneratorResumedAfterReturn => {
|
||||
write!(fmt, "{:?}", "generator resumed after completion")?;
|
||||
}
|
||||
AssertMessage::GeneratorResumedAfterPanic => {
|
||||
write!(fmt, "{:?}", "generator resumed after panicking")?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(fmt, ")")
|
||||
write!(fmt, "{:?}, \"{:?}\")", cond, msg)
|
||||
},
|
||||
FalseEdges { .. } => write!(fmt, "falseEdges"),
|
||||
FalseUnwind { .. } => write!(fmt, "falseUnwind"),
|
||||
@ -1204,17 +1188,6 @@ impl<'tcx> TerminatorKind<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum AssertMessage<'tcx> {
|
||||
BoundsCheck {
|
||||
len: Operand<'tcx>,
|
||||
index: Operand<'tcx>
|
||||
},
|
||||
Math(ConstMathErr),
|
||||
GeneratorResumedAfterReturn,
|
||||
GeneratorResumedAfterPanic,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Statements
|
||||
|
||||
@ -1915,12 +1888,13 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
|
||||
|
||||
pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
|
||||
use ty::TypeVariants::*;
|
||||
use rustc_const_math::ConstFloat;
|
||||
match (value, &ty.sty) {
|
||||
(Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
|
||||
(Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
|
||||
(Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(fty)) =>
|
||||
write!(f, "{}", ConstFloat { bits, ty: fty }),
|
||||
(Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F32)) =>
|
||||
write!(f, "{}f32", Single::from_bits(bits)),
|
||||
(Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F64)) =>
|
||||
write!(f, "{}f64", Double::from_bits(bits)),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
|
||||
(Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
|
||||
@ -2279,8 +2253,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
||||
}
|
||||
},
|
||||
Assert { ref cond, expected, ref msg, target, cleanup } => {
|
||||
let msg = if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
|
||||
AssertMessage::BoundsCheck {
|
||||
let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
|
||||
EvalErrorKind::BoundsCheck {
|
||||
len: len.fold_with(folder),
|
||||
index: index.fold_with(folder),
|
||||
}
|
||||
@ -2329,7 +2303,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
|
||||
},
|
||||
Assert { ref cond, ref msg, .. } => {
|
||||
if cond.visit_with(visitor) {
|
||||
if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
|
||||
if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg {
|
||||
len.visit_with(visitor) || index.visit_with(visitor)
|
||||
} else {
|
||||
false
|
||||
|
@ -511,17 +511,13 @@ macro_rules! make_mir_visitor {
|
||||
fn super_assert_message(&mut self,
|
||||
msg: & $($mutability)* AssertMessage<'tcx>,
|
||||
location: Location) {
|
||||
match *msg {
|
||||
AssertMessage::BoundsCheck {
|
||||
use mir::interpret::EvalErrorKind::*;
|
||||
if let BoundsCheck {
|
||||
ref $($mutability)* len,
|
||||
ref $($mutability)* index
|
||||
} => {
|
||||
self.visit_operand(len, location);
|
||||
self.visit_operand(index, location);
|
||||
}
|
||||
AssertMessage::Math(_) => {},
|
||||
AssertMessage::GeneratorResumedAfterReturn => {},
|
||||
AssertMessage::GeneratorResumedAfterPanic => {},
|
||||
} = *msg {
|
||||
self.visit_operand(len, location);
|
||||
self.visit_operand(index, location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,7 +148,7 @@ pub const FAT_PTR_ADDR: usize = 0;
|
||||
/// - For a slice, this is the length.
|
||||
pub const FAT_PTR_EXTRA: usize = 1;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum LayoutError<'tcx> {
|
||||
Unknown(Ty<'tcx>),
|
||||
SizeOverflow(Ty<'tcx>)
|
||||
|
@ -473,9 +473,19 @@ impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> {
|
||||
|
||||
impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
|
||||
type Lifted = interpret::EvalError<'tcx>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
Some(interpret::EvalError {
|
||||
kind: tcx.lift(&self.kind)?,
|
||||
backtrace: self.backtrace.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
|
||||
type Lifted = interpret::EvalErrorKind<'tcx, <O as Lift<'tcx>>::Lifted>;
|
||||
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
|
||||
use ::mir::interpret::EvalErrorKind::*;
|
||||
let kind = match self.kind {
|
||||
Some(match *self {
|
||||
MachineError(ref err) => MachineError(err.clone()),
|
||||
FunctionPointerTyMismatch(a, b) => FunctionPointerTyMismatch(
|
||||
tcx.lift(&a)?,
|
||||
@ -504,10 +514,11 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
|
||||
Unimplemented(ref s) => Unimplemented(s.clone()),
|
||||
DerefFunctionPointer => DerefFunctionPointer,
|
||||
ExecuteMemory => ExecuteMemory,
|
||||
ArrayIndexOutOfBounds(sp, a, b) => ArrayIndexOutOfBounds(sp, a, b),
|
||||
Math(sp, ref err) => Math(sp, err.clone()),
|
||||
BoundsCheck { ref len, ref index } => BoundsCheck {
|
||||
len: tcx.lift(len)?,
|
||||
index: tcx.lift(index)?,
|
||||
},
|
||||
Intrinsic(ref s) => Intrinsic(s.clone()),
|
||||
OverflowingMath => OverflowingMath,
|
||||
InvalidChar(c) => InvalidChar(c),
|
||||
StackFrameLimitReached => StackFrameLimitReached,
|
||||
OutOfTls => OutOfTls,
|
||||
@ -568,10 +579,12 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> {
|
||||
UnimplementedTraitSelection => UnimplementedTraitSelection,
|
||||
TypeckError => TypeckError,
|
||||
ReferencedConstant => ReferencedConstant,
|
||||
};
|
||||
Some(interpret::EvalError {
|
||||
kind: kind,
|
||||
backtrace: self.backtrace.clone(),
|
||||
OverflowNeg => OverflowNeg,
|
||||
Overflow(op) => Overflow(op),
|
||||
DivisionByZero => DivisionByZero,
|
||||
RemainderByZero => RemainderByZero,
|
||||
GeneratorResumedAfterReturn => GeneratorResumedAfterReturn,
|
||||
GeneratorResumedAfterPanic => GeneratorResumedAfterPanic,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -585,7 +598,6 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
|
||||
NonConstPath => NonConstPath,
|
||||
UnimplementedConstVal(s) => UnimplementedConstVal(s),
|
||||
IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index },
|
||||
Math(ref e) => Math(e.clone()),
|
||||
|
||||
LayoutError(ref e) => {
|
||||
return tcx.lift(e).map(LayoutError)
|
||||
|
@ -20,7 +20,7 @@ use std::ops::Neg;
|
||||
pub struct DoubleFloat<F>(F, F);
|
||||
pub type DoubleDouble = DoubleFloat<ieee::Double>;
|
||||
|
||||
// These are legacy semantics for the Fallback, inaccrurate implementation of
|
||||
// These are legacy semantics for the Fallback, inaccurate implementation of
|
||||
// IBM double-double, if the accurate DoubleDouble doesn't handle the
|
||||
// operation. It's equivalent to having an IEEE number with consecutive 106
|
||||
// bits of mantissa and 11 bits of exponent.
|
||||
|
@ -1,14 +0,0 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_const_math"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "rustc_const_math"
|
||||
path = "lib.rs"
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
serialize = { path = "../libserialize" }
|
||||
syntax = { path = "../libsyntax" }
|
@ -1,87 +0,0 @@
|
||||
// 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 syntax::ast;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum ConstMathErr {
|
||||
NotInRange,
|
||||
CmpBetweenUnequalTypes,
|
||||
UnequalTypes(Op),
|
||||
Overflow(Op),
|
||||
ShiftNegative,
|
||||
DivisionByZero,
|
||||
RemainderByZero,
|
||||
UnsignedNegation,
|
||||
ULitOutOfRange(ast::UintTy),
|
||||
LitOutOfRange(ast::IntTy),
|
||||
}
|
||||
pub use self::ConstMathErr::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, RustcEncodable, RustcDecodable)]
|
||||
pub enum Op {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Rem,
|
||||
Shr,
|
||||
Shl,
|
||||
Neg,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
}
|
||||
|
||||
impl ConstMathErr {
|
||||
pub fn description(&self) -> &'static str {
|
||||
use self::Op::*;
|
||||
match *self {
|
||||
NotInRange => "inferred value out of range",
|
||||
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 values 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) => "attempt to add with overflow",
|
||||
Overflow(Sub) => "attempt to subtract with overflow",
|
||||
Overflow(Mul) => "attempt to multiply with overflow",
|
||||
Overflow(Div) => "attempt to divide with overflow",
|
||||
Overflow(Rem) => "attempt to calculate the remainder with overflow",
|
||||
Overflow(Neg) => "attempt to negate with overflow",
|
||||
Overflow(Shr) => "attempt to shift right with overflow",
|
||||
Overflow(Shl) => "attempt to shift left with overflow",
|
||||
Overflow(_) => unreachable!(),
|
||||
ShiftNegative => "attempt to shift by a negative amount",
|
||||
DivisionByZero => "attempt to divide by zero",
|
||||
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
|
||||
UnsignedNegation => "unary negation of unsigned integer",
|
||||
ULitOutOfRange(ast::UintTy::U8) => "literal out of range for u8",
|
||||
ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16",
|
||||
ULitOutOfRange(ast::UintTy::U32) => "literal out of range for u32",
|
||||
ULitOutOfRange(ast::UintTy::U64) => "literal out of range for u64",
|
||||
ULitOutOfRange(ast::UintTy::U128) => "literal out of range for u128",
|
||||
ULitOutOfRange(ast::UintTy::Usize) => "literal out of range for usize",
|
||||
LitOutOfRange(ast::IntTy::I8) => "literal out of range for i8",
|
||||
LitOutOfRange(ast::IntTy::I16) => "literal out of range for i16",
|
||||
LitOutOfRange(ast::IntTy::I32) => "literal out of range for i32",
|
||||
LitOutOfRange(ast::IntTy::I64) => "literal out of range for i64",
|
||||
LitOutOfRange(ast::IntTy::I128) => "literal out of range for i128",
|
||||
LitOutOfRange(ast::IntTy::Isize) => "literal out of range for isize",
|
||||
}
|
||||
}
|
||||
}
|
@ -1,213 +0,0 @@
|
||||
// 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::num::ParseFloatError;
|
||||
|
||||
use syntax::ast;
|
||||
|
||||
use rustc_apfloat::{Float, FloatConvert, Status};
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
|
||||
use super::err::*;
|
||||
|
||||
// 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).
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
|
||||
pub struct ConstFloat {
|
||||
pub ty: ast::FloatTy,
|
||||
|
||||
// This is a bit inefficient but it makes conversions below more
|
||||
// ergonomic, and all of this will go away once `miri` is merged.
|
||||
pub bits: u128,
|
||||
}
|
||||
|
||||
impl ConstFloat {
|
||||
/// Description of the type, not the value
|
||||
pub fn description(&self) -> &'static str {
|
||||
self.ty.ty_to_string()
|
||||
}
|
||||
|
||||
/// Compares the values if they are of the same type
|
||||
pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
|
||||
match (self.ty, rhs.ty) {
|
||||
(ast::FloatTy::F64, ast::FloatTy::F64) => {
|
||||
let a = Double::from_bits(self.bits);
|
||||
let b = Double::from_bits(rhs.bits);
|
||||
// This is pretty bad but it is the existing behavior.
|
||||
Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater))
|
||||
}
|
||||
|
||||
(ast::FloatTy::F32, ast::FloatTy::F32) => {
|
||||
let a = Single::from_bits(self.bits);
|
||||
let b = Single::from_bits(rhs.bits);
|
||||
Ok(a.partial_cmp(&b).unwrap_or(Ordering::Greater))
|
||||
}
|
||||
|
||||
_ => Err(CmpBetweenUnequalTypes),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_i128(input: i128, ty: ast::FloatTy) -> Self {
|
||||
let bits = match ty {
|
||||
ast::FloatTy::F32 => Single::from_i128(input).value.to_bits(),
|
||||
ast::FloatTy::F64 => Double::from_i128(input).value.to_bits()
|
||||
};
|
||||
ConstFloat { bits, ty }
|
||||
}
|
||||
|
||||
pub fn from_u128(input: u128, ty: ast::FloatTy) -> Self {
|
||||
let bits = match ty {
|
||||
ast::FloatTy::F32 => Single::from_u128(input).value.to_bits(),
|
||||
ast::FloatTy::F64 => Double::from_u128(input).value.to_bits()
|
||||
};
|
||||
ConstFloat { bits, ty }
|
||||
}
|
||||
|
||||
pub fn from_str(num: &str, ty: ast::FloatTy) -> Result<Self, ParseFloatError> {
|
||||
let bits = match ty {
|
||||
ast::FloatTy::F32 => {
|
||||
let rust_bits = num.parse::<f32>()?.to_bits() as u128;
|
||||
let apfloat = num.parse::<Single>().unwrap_or_else(|e| {
|
||||
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e);
|
||||
});
|
||||
let apfloat_bits = apfloat.to_bits();
|
||||
assert!(rust_bits == apfloat_bits,
|
||||
"apfloat::ieee::Single gave different result for `{}`: \
|
||||
{}({:#x}) vs Rust's {}({:#x})",
|
||||
num, apfloat, apfloat_bits,
|
||||
Single::from_bits(rust_bits), rust_bits);
|
||||
apfloat_bits
|
||||
}
|
||||
ast::FloatTy::F64 => {
|
||||
let rust_bits = num.parse::<f64>()?.to_bits() as u128;
|
||||
let apfloat = num.parse::<Double>().unwrap_or_else(|e| {
|
||||
panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e);
|
||||
});
|
||||
let apfloat_bits = apfloat.to_bits();
|
||||
assert!(rust_bits == apfloat_bits,
|
||||
"apfloat::ieee::Double gave different result for `{}`: \
|
||||
{}({:#x}) vs Rust's {}({:#x})",
|
||||
num, apfloat, apfloat_bits,
|
||||
Double::from_bits(rust_bits), rust_bits);
|
||||
apfloat_bits
|
||||
}
|
||||
};
|
||||
Ok(ConstFloat { bits, ty })
|
||||
}
|
||||
|
||||
pub fn to_i128(self, width: usize) -> Option<i128> {
|
||||
assert!(width <= 128);
|
||||
let r = match self.ty {
|
||||
ast::FloatTy::F32 => Single::from_bits(self.bits).to_i128(width),
|
||||
ast::FloatTy::F64 => Double::from_bits(self.bits).to_i128(width)
|
||||
};
|
||||
if r.status.intersects(Status::INVALID_OP) {
|
||||
None
|
||||
} else {
|
||||
Some(r.value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_u128(self, width: usize) -> Option<u128> {
|
||||
assert!(width <= 128);
|
||||
let r = match self.ty {
|
||||
ast::FloatTy::F32 => Single::from_bits(self.bits).to_u128(width),
|
||||
ast::FloatTy::F64 => Double::from_bits(self.bits).to_u128(width)
|
||||
};
|
||||
if r.status.intersects(Status::INVALID_OP) {
|
||||
None
|
||||
} else {
|
||||
Some(r.value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert(self, to: ast::FloatTy) -> Self {
|
||||
let bits = match (self.ty, to) {
|
||||
(ast::FloatTy::F32, ast::FloatTy::F32) |
|
||||
(ast::FloatTy::F64, ast::FloatTy::F64) => return self,
|
||||
|
||||
(ast::FloatTy::F32, ast::FloatTy::F64) => {
|
||||
Double::to_bits(Single::from_bits(self.bits).convert(&mut false).value)
|
||||
}
|
||||
(ast::FloatTy::F64, ast::FloatTy::F32) => {
|
||||
Single::to_bits(Double::from_bits(self.bits).convert(&mut false).value)
|
||||
}
|
||||
};
|
||||
ConstFloat { bits, ty: to }
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for ConstFloat {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
match self.ty {
|
||||
ast::FloatTy::F32 => write!(fmt, "{:#}", Single::from_bits(self.bits))?,
|
||||
ast::FloatTy::F64 => write!(fmt, "{:#}", Double::from_bits(self.bits))?,
|
||||
}
|
||||
write!(fmt, "{}", self.ty)
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for ConstFloat {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
::std::fmt::Display::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
let bits = match (self.ty, rhs.ty) {
|
||||
(ast::FloatTy::F32, ast::FloatTy::F32) =>{
|
||||
let a = Single::from_bits(self.bits);
|
||||
let b = Single::from_bits(rhs.bits);
|
||||
a.$func(b).value.to_bits()
|
||||
}
|
||||
(ast::FloatTy::F64, ast::FloatTy::F64) => {
|
||||
let a = Double::from_bits(self.bits);
|
||||
let b = Double::from_bits(rhs.bits);
|
||||
a.$func(b).value.to_bits()
|
||||
}
|
||||
_ => return Err(UnequalTypes(Op::$op)),
|
||||
};
|
||||
Ok(ConstFloat { bits, ty: self.ty })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
let bits = match self.ty {
|
||||
ast::FloatTy::F32 => (-Single::from_bits(self.bits)).to_bits(),
|
||||
ast::FloatTy::F64 => (-Double::from_bits(self.bits)).to_bits(),
|
||||
};
|
||||
ConstFloat { bits, ty: self.ty }
|
||||
}
|
||||
}
|
||||
|
||||
/// This is `f32::MAX + (0.5 ULP)` as an integer. Numbers greater or equal to this
|
||||
/// are rounded to infinity when converted to `f32`.
|
||||
///
|
||||
/// NB: Computed as maximum significand with an extra 1 bit added (for the half ULP)
|
||||
/// shifted by the maximum exponent (accounting for normalization).
|
||||
pub const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1)
|
||||
<< (Single::MAX_EXP - Single::PRECISION as i16);
|
@ -1,31 +0,0 @@
|
||||
// Copyright 2012-2013 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.
|
||||
|
||||
//! Rusty Mathematics
|
||||
//!
|
||||
//! # Note
|
||||
//!
|
||||
//! This API is completely unstable and subject to change.
|
||||
|
||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
|
||||
extern crate rustc_apfloat;
|
||||
|
||||
extern crate syntax;
|
||||
|
||||
extern crate serialize as rustc_serialize; // used by deriving
|
||||
|
||||
mod float;
|
||||
mod err;
|
||||
|
||||
pub use float::*;
|
||||
pub use err::{ConstMathErr, Op};
|
@ -16,7 +16,6 @@ log = "0.4"
|
||||
log_settings = "0.1.1"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
serialize = { path = "../libserialize" }
|
||||
|
@ -18,7 +18,7 @@ use rustc::infer::InferCtxt;
|
||||
use rustc::ty::{self, ParamEnv, TyCtxt};
|
||||
use rustc::ty::maps::Providers;
|
||||
use rustc::lint::builtin::UNUSED_MUT;
|
||||
use rustc::mir::{AssertMessage, AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||
use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
|
||||
use rustc::mir::{ClearCrossCrate, Local, Location, Place, Mir, Mutability, Operand};
|
||||
use rustc::mir::{Projection, ProjectionElem, Rvalue, Field, Statement, StatementKind};
|
||||
use rustc::mir::{Terminator, TerminatorKind};
|
||||
@ -586,18 +586,14 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
|
||||
cleanup: _,
|
||||
} => {
|
||||
self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state);
|
||||
match *msg {
|
||||
AssertMessage::BoundsCheck { ref len, ref index } => {
|
||||
self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
|
||||
self.consume_operand(
|
||||
ContextKind::Assert.new(loc),
|
||||
(index, span),
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
AssertMessage::Math(_ /*const_math_err*/) => {}
|
||||
AssertMessage::GeneratorResumedAfterReturn => {}
|
||||
AssertMessage::GeneratorResumedAfterPanic => {}
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
if let BoundsCheck { ref len, ref index } = *msg {
|
||||
self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state);
|
||||
self.consume_operand(
|
||||
ContextKind::Assert.new(loc),
|
||||
(index, span),
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
|
||||
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::*;
|
||||
use rustc::traits::query::NoSolution;
|
||||
use rustc::traits::{self, Normalized, TraitEngine};
|
||||
@ -928,7 +929,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
|
||||
}
|
||||
|
||||
if let AssertMessage::BoundsCheck { ref len, ref index } = *msg {
|
||||
if let BoundsCheck { ref len, ref index } = *msg {
|
||||
if len.ty(mir, tcx) != tcx.types.usize {
|
||||
span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use build::expr::category::Category;
|
||||
use hair::*;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
@ -73,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Operand::Copy(Place::Local(idx)),
|
||||
Operand::Copy(len.clone())));
|
||||
|
||||
let msg = AssertMessage::BoundsCheck {
|
||||
let msg = BoundsCheck {
|
||||
len: Operand::Move(len),
|
||||
index: Operand::Copy(Place::Local(idx))
|
||||
};
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
//! See docs in build/expr/mod.rs
|
||||
|
||||
use rustc_const_math::{ConstMathErr, Op};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
||||
@ -21,7 +20,7 @@ use rustc::middle::const_val::ConstVal;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
|
||||
use syntax_pos::Span;
|
||||
|
||||
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
@ -86,9 +85,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
this.cfg.push_assign(block, source_info, &is_min,
|
||||
Rvalue::BinaryOp(BinOp::Eq, arg.to_copy(), minval));
|
||||
|
||||
let err = ConstMathErr::Overflow(Op::Neg);
|
||||
block = this.assert(block, Operand::Move(is_min), false,
|
||||
AssertMessage::Math(err), expr_span);
|
||||
EvalErrorKind::OverflowNeg, expr_span);
|
||||
}
|
||||
block.and(Rvalue::UnaryOp(op, arg))
|
||||
}
|
||||
@ -311,19 +309,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
let val = result_value.clone().field(val_fld, ty);
|
||||
let of = result_value.field(of_fld, bool_ty);
|
||||
|
||||
let err = ConstMathErr::Overflow(match op {
|
||||
BinOp::Add => Op::Add,
|
||||
BinOp::Sub => Op::Sub,
|
||||
BinOp::Mul => Op::Mul,
|
||||
BinOp::Shl => Op::Shl,
|
||||
BinOp::Shr => Op::Shr,
|
||||
_ => {
|
||||
bug!("MIR build_binary_op: {:?} is not checkable", op)
|
||||
}
|
||||
});
|
||||
let err = EvalErrorKind::Overflow(op);
|
||||
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(err), span);
|
||||
err, span);
|
||||
|
||||
block.and(Rvalue::Use(Operand::Move(val)))
|
||||
} else {
|
||||
@ -332,11 +321,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
// and 2. there are two possible failure cases, divide-by-zero and overflow.
|
||||
|
||||
let (zero_err, overflow_err) = if op == BinOp::Div {
|
||||
(ConstMathErr::DivisionByZero,
|
||||
ConstMathErr::Overflow(Op::Div))
|
||||
(EvalErrorKind::DivisionByZero,
|
||||
EvalErrorKind::Overflow(op))
|
||||
} else {
|
||||
(ConstMathErr::RemainderByZero,
|
||||
ConstMathErr::Overflow(Op::Rem))
|
||||
(EvalErrorKind::RemainderByZero,
|
||||
EvalErrorKind::Overflow(op))
|
||||
};
|
||||
|
||||
// Check for / 0
|
||||
@ -346,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Rvalue::BinaryOp(BinOp::Eq, rhs.to_copy(), zero));
|
||||
|
||||
block = self.assert(block, Operand::Move(is_zero), false,
|
||||
AssertMessage::Math(zero_err), span);
|
||||
zero_err, span);
|
||||
|
||||
// We only need to check for the overflow in one case:
|
||||
// MIN / -1, and only for signed values.
|
||||
@ -371,7 +360,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||
Rvalue::BinaryOp(BinOp::BitAnd, is_neg_1, is_min));
|
||||
|
||||
block = self.assert(block, Operand::Move(of), false,
|
||||
AssertMessage::Math(overflow_err), span);
|
||||
overflow_err, span);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,9 @@ use syntax::ast::{self, LitKind};
|
||||
use syntax::attr;
|
||||
use syntax::symbol::Symbol;
|
||||
use rustc::hir;
|
||||
use rustc_const_math::ConstFloat;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
use hair::pattern::parse_float;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
||||
@ -170,12 +170,11 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
neg: bool,
|
||||
) -> Literal<'tcx> {
|
||||
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
|
||||
let tcx = self.tcx.global_tcx();
|
||||
|
||||
let parse_float = |num: &str, fty| -> ConstFloat {
|
||||
ConstFloat::from_str(num, fty).unwrap_or_else(|_| {
|
||||
let parse_float = |num, fty| -> Value {
|
||||
parse_float(num, fty, neg).unwrap_or_else(|_| {
|
||||
// FIXME(#31407) this is only necessary because float parsing is buggy
|
||||
tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
|
||||
self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
|
||||
})
|
||||
};
|
||||
|
||||
@ -213,26 +212,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
||||
},
|
||||
LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
|
||||
LitKind::Float(n, fty) => {
|
||||
let n = n.as_str();
|
||||
let mut f = parse_float(&n, fty);
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
let bits = f.bits;
|
||||
Value::ByVal(PrimVal::Bytes(bits))
|
||||
parse_float(n, fty)
|
||||
}
|
||||
LitKind::FloatUnsuffixed(n) => {
|
||||
let fty = match ty.sty {
|
||||
ty::TyFloat(fty) => fty,
|
||||
_ => bug!()
|
||||
};
|
||||
let n = n.as_str();
|
||||
let mut f = parse_float(&n, fty);
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
let bits = f.bits;
|
||||
Value::ByVal(PrimVal::Bytes(bits))
|
||||
parse_float(n, fty)
|
||||
}
|
||||
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
|
||||
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
|
||||
|
@ -28,13 +28,13 @@ use rustc::hir::def::{Def, CtorKind};
|
||||
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc_const_math::ConstFloat;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::symbol::Symbol;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PatternError {
|
||||
@ -1053,24 +1053,22 @@ pub fn compare_const_vals<'a, 'tcx>(
|
||||
b: &ConstVal,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<Ordering> {
|
||||
use rustc_const_math::ConstFloat;
|
||||
trace!("compare_const_vals: {:?}, {:?}", a, b);
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
match (a, b) {
|
||||
(&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
|
||||
&ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
|
||||
use ::rustc_apfloat::Float;
|
||||
match ty.sty {
|
||||
ty::TyFloat(ty) => {
|
||||
let l = ConstFloat {
|
||||
bits: a,
|
||||
ty,
|
||||
};
|
||||
let r = ConstFloat {
|
||||
bits: b,
|
||||
ty,
|
||||
};
|
||||
// FIXME(oli-obk): report cmp errors?
|
||||
l.try_cmp(r).ok()
|
||||
ty::TyFloat(ast::FloatTy::F32) => {
|
||||
let l = ::rustc_apfloat::ieee::Single::from_bits(a);
|
||||
let r = ::rustc_apfloat::ieee::Single::from_bits(b);
|
||||
l.partial_cmp(&r)
|
||||
},
|
||||
ty::TyFloat(ast::FloatTy::F64) => {
|
||||
let l = ::rustc_apfloat::ieee::Double::from_bits(a);
|
||||
let r = ::rustc_apfloat::ieee::Double::from_bits(b);
|
||||
l.partial_cmp(&r)
|
||||
},
|
||||
ty::TyInt(_) => {
|
||||
let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
|
||||
@ -1148,26 +1146,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||
Value::ByVal(PrimVal::Bytes(n))
|
||||
},
|
||||
LitKind::Float(n, fty) => {
|
||||
let n = n.as_str();
|
||||
let mut f = parse_float(&n, fty)?;
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
let bits = f.bits;
|
||||
Value::ByVal(PrimVal::Bytes(bits))
|
||||
parse_float(n, fty, neg)?
|
||||
}
|
||||
LitKind::FloatUnsuffixed(n) => {
|
||||
let fty = match ty.sty {
|
||||
ty::TyFloat(fty) => fty,
|
||||
_ => bug!()
|
||||
};
|
||||
let n = n.as_str();
|
||||
let mut f = parse_float(&n, fty)?;
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
let bits = f.bits;
|
||||
Value::ByVal(PrimVal::Bytes(bits))
|
||||
parse_float(n, fty, neg)?
|
||||
}
|
||||
LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
|
||||
LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
|
||||
@ -1175,7 +1161,36 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
||||
Ok(ConstVal::Value(lit))
|
||||
}
|
||||
|
||||
fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
|
||||
-> Result<ConstFloat, ()> {
|
||||
ConstFloat::from_str(num, fty).map_err(|_| ())
|
||||
pub fn parse_float(
|
||||
num: Symbol,
|
||||
fty: ast::FloatTy,
|
||||
neg: bool,
|
||||
) -> Result<Value, ()> {
|
||||
let num = num.as_str();
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc_apfloat::Float;
|
||||
let bits = match fty {
|
||||
ast::FloatTy::F32 => {
|
||||
num.parse::<f32>().map_err(|_| ())?;
|
||||
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
|
||||
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
|
||||
});
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
f.to_bits()
|
||||
}
|
||||
ast::FloatTy::F64 => {
|
||||
num.parse::<f64>().map_err(|_| ())?;
|
||||
let mut f = num.parse::<Double>().unwrap_or_else(|e| {
|
||||
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
|
||||
});
|
||||
if neg {
|
||||
f = -f;
|
||||
}
|
||||
f.to_bits()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Value::ByVal(PrimVal::Bytes(bits)))
|
||||
}
|
||||
|
@ -2,10 +2,9 @@ use rustc::ty::Ty;
|
||||
use rustc::ty::layout::LayoutOf;
|
||||
use syntax::ast::{FloatTy, IntTy, UintTy};
|
||||
|
||||
use rustc_const_math::ConstFloat;
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use super::{EvalContext, Machine};
|
||||
use rustc::mir::interpret::{PrimVal, EvalResult, MemoryPointer, PointerArithmetic};
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc_apfloat::Float;
|
||||
|
||||
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
@ -50,8 +49,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
Ok(PrimVal::Bytes(v))
|
||||
}
|
||||
|
||||
TyFloat(fty) if signed => Ok(PrimVal::Bytes(ConstFloat::from_i128(v as i128, fty).bits)),
|
||||
TyFloat(fty) => Ok(PrimVal::Bytes(ConstFloat::from_u128(v, fty).bits)),
|
||||
TyFloat(FloatTy::F32) if signed => Ok(PrimVal::Bytes(Single::from_i128(v as i128).value.to_bits())),
|
||||
TyFloat(FloatTy::F64) if signed => Ok(PrimVal::Bytes(Double::from_i128(v as i128).value.to_bits())),
|
||||
TyFloat(FloatTy::F32) => Ok(PrimVal::Bytes(Single::from_u128(v).value.to_bits())),
|
||||
TyFloat(FloatTy::F64) => Ok(PrimVal::Bytes(Double::from_u128(v).value.to_bits())),
|
||||
|
||||
TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
|
||||
TyChar => err!(InvalidChar(v)),
|
||||
|
@ -513,7 +513,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
||||
// it emits in debug mode) is performance, but it doesn't cost us any performance in miri.
|
||||
// If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops,
|
||||
// we have to go back to just ignoring the overflow here.
|
||||
return err!(OverflowingMath);
|
||||
return err!(Overflow(bin_op));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_const_math::ConstFloat;
|
||||
use syntax::ast::FloatTy;
|
||||
use std::cmp::Ordering;
|
||||
use rustc::ty::layout::LayoutOf;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
use rustc_apfloat::Float;
|
||||
|
||||
use super::{EvalContext, Place, Machine, ValTy};
|
||||
|
||||
@ -125,31 +126,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
return err!(Unimplemented(msg));
|
||||
}
|
||||
|
||||
let float_op = |op, l, r, ty| {
|
||||
let l = ConstFloat {
|
||||
bits: l,
|
||||
ty,
|
||||
};
|
||||
let r = ConstFloat {
|
||||
bits: r,
|
||||
ty,
|
||||
};
|
||||
match op {
|
||||
Eq => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Equal),
|
||||
Ne => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Equal),
|
||||
Lt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Less),
|
||||
Le => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Greater),
|
||||
Gt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Greater),
|
||||
Ge => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Less),
|
||||
Add => PrimVal::Bytes((l + r).unwrap().bits),
|
||||
Sub => PrimVal::Bytes((l - r).unwrap().bits),
|
||||
Mul => PrimVal::Bytes((l * r).unwrap().bits),
|
||||
Div => PrimVal::Bytes((l / r).unwrap().bits),
|
||||
Rem => PrimVal::Bytes((l % r).unwrap().bits),
|
||||
_ => bug!("invalid float op: `{:?}`", op),
|
||||
}
|
||||
};
|
||||
|
||||
if left_layout.abi.is_signed() {
|
||||
let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
|
||||
Lt => Some(i128::lt),
|
||||
@ -164,7 +140,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
return Ok((PrimVal::from_bool(op(&l, &r)), false));
|
||||
}
|
||||
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
|
||||
Rem | Div if r == 0 => return Ok((PrimVal::Bytes(l), true)),
|
||||
Div if r == 0 => return err!(DivisionByZero),
|
||||
Rem if r == 0 => return err!(RemainderByZero),
|
||||
Div => Some(i128::overflowing_div),
|
||||
Rem => Some(i128::overflowing_rem),
|
||||
Add => Some(i128::overflowing_add),
|
||||
@ -199,7 +176,31 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
if let ty::TyFloat(fty) = left_ty.sty {
|
||||
return Ok((float_op(bin_op, l, r, fty), false));
|
||||
macro_rules! float_math {
|
||||
($ty:path) => {{
|
||||
let l = <$ty>::from_bits(l);
|
||||
let r = <$ty>::from_bits(r);
|
||||
let val = match bin_op {
|
||||
Eq => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Equal),
|
||||
Ne => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Equal),
|
||||
Lt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Less),
|
||||
Le => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Greater),
|
||||
Gt => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) == Ordering::Greater),
|
||||
Ge => PrimVal::from_bool(l.partial_cmp(&r).unwrap_or(Ordering::Greater) != Ordering::Less),
|
||||
Add => PrimVal::Bytes((l + r).value.to_bits()),
|
||||
Sub => PrimVal::Bytes((l - r).value.to_bits()),
|
||||
Mul => PrimVal::Bytes((l * r).value.to_bits()),
|
||||
Div => PrimVal::Bytes((l / r).value.to_bits()),
|
||||
Rem => PrimVal::Bytes((l % r).value.to_bits()),
|
||||
_ => bug!("invalid float op: `{:?}`", bin_op),
|
||||
};
|
||||
return Ok((val, false));
|
||||
}};
|
||||
}
|
||||
match fty {
|
||||
FloatTy::F32 => float_math!(Single),
|
||||
FloatTy::F64 => float_math!(Double),
|
||||
}
|
||||
}
|
||||
|
||||
// only ints left
|
||||
@ -221,7 +222,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
Add => u128::overflowing_add,
|
||||
Sub => u128::overflowing_sub,
|
||||
Mul => u128::overflowing_mul,
|
||||
Rem | Div if r == 0 => return Ok((PrimVal::Bytes(l), true)),
|
||||
Div if r == 0 => return err!(DivisionByZero),
|
||||
Rem if r == 0 => return err!(RemainderByZero),
|
||||
Div => u128::overflowing_div,
|
||||
Rem => u128::overflowing_rem,
|
||||
_ => bug!(),
|
||||
@ -269,7 +271,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
(Neg, ty::TyFloat(FloatTy::F32)) => Single::to_bits(-Single::from_bits(bytes)),
|
||||
(Neg, ty::TyFloat(FloatTy::F64)) => Double::to_bits(-Double::from_bits(bytes)),
|
||||
|
||||
(Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowingMath),
|
||||
(Neg, _) if bytes == (1 << (size - 1)) => return err!(OverflowNeg),
|
||||
(Neg, _) => (-(bytes as i128)) as u128,
|
||||
};
|
||||
|
||||
|
@ -148,23 +148,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||
if expected == cond_val {
|
||||
self.goto_block(target);
|
||||
} else {
|
||||
use rustc::mir::AssertMessage::*;
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
return match *msg {
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
let span = terminator.source_info.span;
|
||||
let len = self.eval_operand_to_primval(len)
|
||||
.expect("can't eval len")
|
||||
.to_u64()?;
|
||||
let index = self.eval_operand_to_primval(index)
|
||||
.expect("can't eval index")
|
||||
.to_u64()?;
|
||||
err!(ArrayIndexOutOfBounds(span, len, index))
|
||||
}
|
||||
Math(ref err) => {
|
||||
err!(Math(terminator.source_info.span, err.clone()))
|
||||
err!(BoundsCheck { len, index })
|
||||
}
|
||||
Overflow(op) => Err(Overflow(op).into()),
|
||||
OverflowNeg => Err(OverflowNeg.into()),
|
||||
DivisionByZero => Err(DivisionByZero.into()),
|
||||
RemainderByZero => Err(RemainderByZero.into()),
|
||||
GeneratorResumedAfterReturn |
|
||||
GeneratorResumedAfterPanic => unimplemented!(),
|
||||
_ => bug!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,6 @@ extern crate rustc_errors;
|
||||
extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
extern crate rustc_target;
|
||||
extern crate rustc_const_math;
|
||||
extern crate core; // for NonZero
|
||||
extern crate log_settings;
|
||||
extern crate rustc_apfloat;
|
||||
extern crate byteorder;
|
||||
|
@ -328,7 +328,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||
} else {
|
||||
if overflow {
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
let mut err = EvalErrorKind::OverflowingMath.into();
|
||||
let mut err = EvalErrorKind::Overflow(op).into();
|
||||
ecx.report(&mut err, false, Some(span));
|
||||
return None;
|
||||
}
|
||||
@ -478,12 +478,12 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
|
||||
.hir
|
||||
.as_local_node_id(self.source.def_id)
|
||||
.expect("some part of a failing const eval must be local");
|
||||
use rustc::mir::AssertMessage::*;
|
||||
use rustc::mir::interpret::EvalErrorKind::*;
|
||||
let msg = match msg {
|
||||
// Need proper const propagator for these
|
||||
GeneratorResumedAfterReturn |
|
||||
GeneratorResumedAfterPanic => return,
|
||||
Math(ref err) => err.description().to_owned(),
|
||||
Overflow(_) |
|
||||
OverflowNeg |
|
||||
DivisionByZero |
|
||||
RemainderByZero => msg.description().to_owned(),
|
||||
BoundsCheck { ref len, ref index } => {
|
||||
let len = self.eval_operand(len).expect("len must be const");
|
||||
let len = match len.0 {
|
||||
@ -504,6 +504,8 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
|
||||
index,
|
||||
)
|
||||
},
|
||||
// Need proper const propagator for these
|
||||
_ => return,
|
||||
};
|
||||
self.tcx.lint_node(
|
||||
::rustc::lint::builtin::CONST_ERR,
|
||||
|
@ -738,12 +738,17 @@ fn create_generator_resume_function<'a, 'tcx>(
|
||||
|
||||
let mut cases = create_cases(mir, &transform, |point| Some(point.resume));
|
||||
|
||||
use rustc::mir::interpret::EvalErrorKind::{
|
||||
GeneratorResumedAfterPanic,
|
||||
GeneratorResumedAfterReturn,
|
||||
};
|
||||
|
||||
// Jump to the entry point on the 0 state
|
||||
cases.insert(0, (0, BasicBlock::new(0)));
|
||||
// Panic when resumed on the returned (1) state
|
||||
cases.insert(1, (1, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterReturn)));
|
||||
cases.insert(1, (1, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn)));
|
||||
// Panic when resumed on the poisoned (2) state
|
||||
cases.insert(2, (2, insert_panic_block(tcx, mir, AssertMessage::GeneratorResumedAfterPanic)));
|
||||
cases.insert(2, (2, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic)));
|
||||
|
||||
insert_switch(tcx, mir, cases, &transform, TerminatorKind::Unreachable);
|
||||
|
||||
|
@ -12,7 +12,6 @@ crate-type = ["dylib"]
|
||||
log = "0.4"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_mir = { path = "../librustc_mir"}
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
@ -23,7 +23,6 @@
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_data_structures;
|
||||
|
||||
#[macro_use]
|
||||
|
@ -18,6 +18,7 @@ use rustc::mir::{Place, PlaceElem, PlaceProjection};
|
||||
use rustc::mir::{Mir, Operand, ProjectionElem};
|
||||
use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
|
||||
use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
use rustc::mir::visit as mir_visit;
|
||||
use rustc::ty::{self, ClosureSubsts, TyCtxt};
|
||||
use rustc::util::nodemap::{FxHashMap};
|
||||
@ -133,14 +134,18 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
|
||||
location: Location) {
|
||||
self.record("AssertMessage", msg);
|
||||
self.record(match *msg {
|
||||
AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
|
||||
AssertMessage::Math(..) => "AssertMessage::Math",
|
||||
AssertMessage::GeneratorResumedAfterReturn => {
|
||||
EvalErrorKind::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
|
||||
EvalErrorKind::Overflow(..) => "AssertMessage::Overflow",
|
||||
EvalErrorKind::OverflowNeg => "AssertMessage::OverflowNeg",
|
||||
EvalErrorKind::DivisionByZero => "AssertMessage::DivisionByZero",
|
||||
EvalErrorKind::RemainderByZero => "AssertMessage::RemainderByZero",
|
||||
EvalErrorKind::GeneratorResumedAfterReturn => {
|
||||
"AssertMessage::GeneratorResumedAfterReturn"
|
||||
}
|
||||
AssertMessage::GeneratorResumedAfterPanic => {
|
||||
EvalErrorKind::GeneratorResumedAfterPanic => {
|
||||
"AssertMessage::GeneratorResumedAfterPanic"
|
||||
}
|
||||
_ => bug!(),
|
||||
}, msg);
|
||||
self.super_assert_message(msg, location);
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ rustc-demangle = "0.1.4"
|
||||
rustc_allocator = { path = "../librustc_allocator" }
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_incremental = { path = "../librustc_incremental" }
|
||||
|
@ -43,7 +43,6 @@ extern crate rustc_mir;
|
||||
extern crate rustc_allocator;
|
||||
extern crate rustc_apfloat;
|
||||
extern crate rustc_target;
|
||||
extern crate rustc_const_math;
|
||||
#[macro_use] extern crate rustc_data_structures;
|
||||
extern crate rustc_demangle;
|
||||
extern crate rustc_incremental;
|
||||
|
@ -13,6 +13,7 @@ use rustc::middle::lang_items;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc::ty::layout::{self, LayoutOf};
|
||||
use rustc::mir;
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode};
|
||||
use base;
|
||||
use callee;
|
||||
@ -311,10 +312,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
// checked operation, just a comparison with the minimum
|
||||
// value, so we have to check for the assert message.
|
||||
if !bx.cx.check_overflow {
|
||||
use rustc_const_math::ConstMathErr::Overflow;
|
||||
use rustc_const_math::Op::Neg;
|
||||
|
||||
if let mir::AssertMessage::Math(Overflow(Neg)) = *msg {
|
||||
if let mir::interpret::EvalErrorKind::OverflowNeg = *msg {
|
||||
const_cond = Some(expected);
|
||||
}
|
||||
}
|
||||
@ -354,7 +352,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
|
||||
// Put together the arguments to the panic entry point.
|
||||
let (lang_item, args) = match *msg {
|
||||
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
|
||||
EvalErrorKind::BoundsCheck { ref len, ref index } => {
|
||||
let len = self.trans_operand(&mut bx, len).immediate();
|
||||
let index = self.trans_operand(&mut bx, index).immediate();
|
||||
|
||||
@ -366,26 +364,8 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
|
||||
(lang_items::PanicBoundsCheckFnLangItem,
|
||||
vec![file_line_col, index, len])
|
||||
}
|
||||
mir::AssertMessage::Math(ref err) => {
|
||||
let msg_str = Symbol::intern(err.description()).as_str();
|
||||
let msg_str = C_str_slice(bx.cx, msg_str);
|
||||
let msg_file_line_col = C_struct(bx.cx,
|
||||
&[msg_str, filename, line, col],
|
||||
false);
|
||||
let msg_file_line_col = consts::addr_of(bx.cx,
|
||||
msg_file_line_col,
|
||||
align,
|
||||
"panic_loc");
|
||||
(lang_items::PanicFnLangItem,
|
||||
vec![msg_file_line_col])
|
||||
}
|
||||
mir::AssertMessage::GeneratorResumedAfterReturn |
|
||||
mir::AssertMessage::GeneratorResumedAfterPanic => {
|
||||
let str = if let mir::AssertMessage::GeneratorResumedAfterReturn = *msg {
|
||||
"generator resumed after completion"
|
||||
} else {
|
||||
"generator resumed after panicking"
|
||||
};
|
||||
_ => {
|
||||
let str = msg.description();
|
||||
let msg_str = Symbol::intern(str).as_str();
|
||||
let msg_str = C_str_slice(bx.cx, msg_str);
|
||||
let msg_file_line_col = C_struct(bx.cx,
|
||||
|
@ -15,7 +15,6 @@ use rustc::ty::layout::{self, LayoutOf};
|
||||
use rustc::mir;
|
||||
use rustc::middle::lang_items::ExchangeMallocFnLangItem;
|
||||
use rustc_apfloat::{ieee, Float, Status, Round};
|
||||
use rustc_const_math::MAX_F32_PLUS_HALF_ULP;
|
||||
use std::{u128, i128};
|
||||
|
||||
use base;
|
||||
@ -805,6 +804,10 @@ fn cast_int_to_float(bx: &Builder,
|
||||
if is_u128_to_f32 {
|
||||
// All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity,
|
||||
// and for everything else LLVM's uitofp works just fine.
|
||||
use rustc_apfloat::ieee::Single;
|
||||
use rustc_apfloat::Float;
|
||||
const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1)
|
||||
<< (Single::MAX_EXP - Single::PRECISION as i16);
|
||||
let max = C_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP);
|
||||
let overflow = bx.icmp(llvm::IntUGE, x, max);
|
||||
let infinity_bits = C_u32(bx.cx, ieee::Single::INFINITY.to_bits() as u32);
|
||||
|
@ -15,7 +15,6 @@ syntax = { path = "../libsyntax" }
|
||||
arena = { path = "../libarena" }
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_const_math = { path = "../librustc_const_math" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
|
@ -92,7 +92,6 @@ extern crate syntax_pos;
|
||||
extern crate arena;
|
||||
#[macro_use] extern crate rustc;
|
||||
extern crate rustc_platform_intrinsics as intrinsics;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_errors as errors;
|
||||
extern crate rustc_target;
|
||||
|
@ -31,7 +31,6 @@ extern crate getopts;
|
||||
extern crate env_logger;
|
||||
extern crate rustc;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_const_math;
|
||||
extern crate rustc_trans_utils;
|
||||
extern crate rustc_driver;
|
||||
extern crate rustc_resolve;
|
||||
|
@ -2,7 +2,7 @@ error[E0080]: constant evaluation error
|
||||
--> $DIR/index_out_of_bound.rs:11:19
|
||||
|
|
||||
LL | static FOO: i32 = [][0];
|
||||
| ^^^^^ index out of bounds: the len is 0 but the index is 0 at $DIR/index_out_of_bound.rs:11:19: 11:24
|
||||
| ^^^^^ index out of bounds: the len is 0 but the index is 0
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -2,7 +2,7 @@ warning: constant evaluation error
|
||||
--> $DIR/promoted_errors.rs:14:20
|
||||
|
|
||||
LL | println!("{}", 0u32 - 1);
|
||||
| ^^^^^^^^ attempted to do overflowing math
|
||||
| ^^^^^^^^ attempt to subtract with overflow
|
||||
|
|
||||
= note: #[warn(const_err)] on by default
|
||||
|
||||
@ -10,13 +10,13 @@ warning: constant evaluation error
|
||||
--> $DIR/promoted_errors.rs:14:20
|
||||
|
|
||||
LL | println!("{}", 0u32 - 1);
|
||||
| ^^^^^^^^ attempted to do overflowing math
|
||||
| ^^^^^^^^ attempt to subtract with overflow
|
||||
|
||||
warning: constant evaluation error
|
||||
--> $DIR/promoted_errors.rs:17:14
|
||||
|
|
||||
LL | let _x = 0u32 - 1;
|
||||
| ^^^^^^^^ attempted to do overflowing math
|
||||
| ^^^^^^^^ attempt to subtract with overflow
|
||||
|
||||
warning: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:19:20
|
||||
@ -28,7 +28,7 @@ warning: constant evaluation error
|
||||
--> $DIR/promoted_errors.rs:19:20
|
||||
|
|
||||
LL | println!("{}", 1/(1-1));
|
||||
| ^^^^^^^ attempted to do overflowing math
|
||||
| ^^^^^^^ attempt to divide by zero
|
||||
|
||||
warning: attempt to divide by zero
|
||||
--> $DIR/promoted_errors.rs:22:14
|
||||
@ -40,11 +40,11 @@ warning: constant evaluation error
|
||||
--> $DIR/promoted_errors.rs:22:14
|
||||
|
|
||||
LL | let _x = 1/(1-1);
|
||||
| ^^^^^^^ attempted to do overflowing math
|
||||
| ^^^^^^^ attempt to divide by zero
|
||||
|
||||
warning: constant evaluation error
|
||||
--> $DIR/promoted_errors.rs:25:20
|
||||
|
|
||||
LL | println!("{}", 1/(false as u32));
|
||||
| ^^^^^^^^^^^^^^^^ attempted to do overflowing math
|
||||
| ^^^^^^^^^^^^^^^^ attempt to divide by zero
|
||||
|
||||
|
@ -15,7 +15,6 @@ enum Enum {
|
||||
//~| const_err
|
||||
//~| const_err
|
||||
//~| const_err
|
||||
//~| divide by zero
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -24,7 +24,7 @@ warning: constant evaluation error
|
||||
--> $DIR/E0080.rs:14:9
|
||||
|
|
||||
LL | Y = (1 / 0) //~ ERROR E0080
|
||||
| ^^^^^^^ attempted to do overflowing math
|
||||
| ^^^^^^^ attempt to divide by zero
|
||||
|
||||
error[E0080]: constant evaluation error
|
||||
--> $DIR/E0080.rs:14:9
|
||||
|
Loading…
x
Reference in New Issue
Block a user