Auto merge of #30587 - oli-obk:eager_const_eval2, r=nikomatsakis

typestrong const integers

~~It would be great if someone could run crater on this PR, as this has a high danger of breaking valid code~~ Crater ran. Good to go.

----

So this PR does a few things:

1. ~~const eval array values when const evaluating an array expression~~
2. ~~const eval repeat value when const evaluating a repeat expression~~
3. ~~const eval all struct and tuple fields when evaluating a struct/tuple expression~~
4. remove the `ConstVal::Int` and `ConstVal::Uint` variants and replace them with a single enum (`ConstInt`) which has variants for all integral types
  * `usize`/`isize` are also enums with variants for 32 and 64 bit. At creation and various usage steps there are assertions in place checking if the target bitwidth matches with the chosen enum variant
5. enum discriminants (`ty::Disr`) are now `ConstInt`
6. trans has its own `Disr` type now (newtype around `u64`)

This obviously can't be done without breaking changes (the ones that are noticable in stable)
We could probably write lints that find those situations and error on it for a cycle or two. But then again, those situations are rare and really bugs imo anyway:

```rust
let v10 = 10 as i8;
let v4 = 4 as isize;
assert_eq!(v10 << v4 as usize, 160 as i8);
 ```

stops compiling because 160 is not a valid i8

```rust
struct S<T, S> {
    a: T,
    b: u8,
    c: S
}
let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
```

stops compiling because `0xaa_aa_aa_aa` is not a valid i32

----

cc @eddyb @pnkfelix

related: https://github.com/rust-lang/rfcs/issues/1071
This commit is contained in:
bors 2016-03-14 11:38:23 -07:00
commit 01118928fc
75 changed files with 1833 additions and 1051 deletions

View File

@ -53,7 +53,7 @@ TARGET_CRATES := libc std term \
getopts collections test rand \
core alloc \
rustc_unicode rustc_bitflags \
alloc_system alloc_jemalloc
alloc_system alloc_jemalloc rustc_const_eval
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
rustc_data_structures rustc_front rustc_platform_intrinsics \
@ -91,8 +91,11 @@ DEPS_test := std getopts term native:rust_test_helpers
DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
DEPS_syntax_ext := syntax fmt_macros
DEPS_rustc_const_eval := std syntax
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
log graphviz rustc_llvm rustc_back rustc_data_structures
log graphviz rustc_llvm rustc_back rustc_data_structures\
rustc_const_eval
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
DEPS_rustc_data_structures := std log serialize
@ -103,16 +106,17 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
DEPS_rustc_front := std syntax log serialize
DEPS_rustc_lint := rustc log syntax
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_metadata := rustc rustc_front syntax rbml
DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_eval
DEPS_rustc_passes := syntax rustc core rustc_front
DEPS_rustc_mir := rustc rustc_front syntax
DEPS_rustc_mir := rustc rustc_front syntax rustc_const_eval
DEPS_rustc_resolve := arena rustc rustc_front log syntax
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
DEPS_rustc_privacy := rustc rustc_front log syntax
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \
rustc_const_eval
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_eval
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
test rustc_lint rustc_front

View File

@ -18,6 +18,7 @@ log = { path = "../liblog" }
rbml = { path = "../librbml" }
rustc_back = { path = "../librustc_back" }
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_front = { path = "../librustc_front" }
rustc_llvm = { path = "../librustc_llvm" }

View File

@ -55,6 +55,7 @@ extern crate rustc_front;
extern crate rustc_data_structures;
extern crate serialize;
extern crate collections;
extern crate rustc_const_eval;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
#[macro_use] #[no_link] extern crate rustc_bitflags;

View File

@ -476,7 +476,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
Some(Def::AssociatedConst(did)) |
Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
Some(pat.id), None) {
Some(const_expr) => {
Some((const_expr, _const_ty)) => {
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
if let Some(ref mut renaming_map) = self.renaming_map {

File diff suppressed because it is too large Load Diff

View File

@ -342,8 +342,12 @@ pub struct TyCtxt<'tcx> {
/// FIXME(arielb1): why is this separate from populated_external_types?
pub populated_external_primitive_impls: RefCell<DefIdSet>,
/// These caches are used by const_eval when decoding external constants.
pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
/// Cache used by const_eval when decoding external constants.
/// Contains `None` when the constant has been fetched but doesn't exist.
/// Constains `Some(expr_id, type)` otherwise.
/// `type` is `None` in case it's not a primitive type
pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
/// Cache used by const_eval when decoding extern const fns
pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),

View File

@ -50,6 +50,8 @@ use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use rustc_const_eval::ConstInt;
use rustc_front::hir;
use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};
use rustc_front::intravisit::Visitor;
@ -100,8 +102,7 @@ mod ivar;
mod structural_impls;
mod sty;
pub type Disr = u64;
pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
pub type Disr = ConstInt;
// Data types
@ -1580,7 +1581,7 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
/// Asserts this is a struct and returns the struct's unique
/// variant.
pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> {
assert!(self.adt_kind() == AdtKind::Struct);
assert_eq!(self.adt_kind(), AdtKind::Struct);
&self.variants[0]
}

View File

@ -21,7 +21,8 @@ use middle::traits;
use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use middle::ty::{Disr, ParameterEnvironment};
use middle::ty::TypeVariants::*;
use util::num::ToPrimitive;
use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize};
use std::cmp;
use std::hash::{Hash, SipHasher, Hasher};
@ -34,11 +35,9 @@ use rustc_front::hir;
pub trait IntTypeExt {
fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>;
fn i64_to_disr(&self, val: i64) -> Option<Disr>;
fn u64_to_disr(&self, val: u64) -> Option<Disr>;
fn disr_incr(&self, val: Disr) -> Option<Disr>;
fn disr_string(&self, val: Disr) -> String;
fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
fn assert_ty_matches(&self, val: Disr);
fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr;
}
impl IntTypeExt for attr::IntType {
@ -57,98 +56,48 @@ impl IntTypeExt for attr::IntType {
}
}
fn i64_to_disr(&self, val: i64) -> Option<Disr> {
fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr {
match *self {
SignedInt(ast::IntTy::I8) => val.to_i8() .map(|v| v as Disr),
SignedInt(ast::IntTy::I16) => val.to_i16() .map(|v| v as Disr),
SignedInt(ast::IntTy::I32) => val.to_i32() .map(|v| v as Disr),
SignedInt(ast::IntTy::I64) => val.to_i64() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U8) => val.to_u8() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::Us) |
SignedInt(ast::IntTy::Is) => unreachable!(),
SignedInt(ast::IntTy::I8) => ConstInt::I8(0),
SignedInt(ast::IntTy::I16) => ConstInt::I16(0),
SignedInt(ast::IntTy::I32) => ConstInt::I32(0),
SignedInt(ast::IntTy::I64) => ConstInt::I64(0),
SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
_ => unreachable!(),
},
UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0),
UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
_ => unreachable!(),
},
}
}
fn u64_to_disr(&self, val: u64) -> Option<Disr> {
match *self {
SignedInt(ast::IntTy::I8) => val.to_i8() .map(|v| v as Disr),
SignedInt(ast::IntTy::I16) => val.to_i16() .map(|v| v as Disr),
SignedInt(ast::IntTy::I32) => val.to_i32() .map(|v| v as Disr),
SignedInt(ast::IntTy::I64) => val.to_i64() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U8) => val.to_u8() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
UnsignedInt(ast::UintTy::Us) |
SignedInt(ast::IntTy::Is) => unreachable!(),
fn assert_ty_matches(&self, val: Disr) {
match (*self, val) {
(SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
(SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
(SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
(SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
(SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
(UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
(UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
(UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
(UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
(UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
_ => panic!("disr type mismatch: {:?} vs {:?}", self, val),
}
}
fn disr_incr(&self, val: Disr) -> Option<Disr> {
macro_rules! add1 {
($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
}
match *self {
// SignedInt repr means we *want* to reinterpret the bits
// treating the highest bit of Disr as a sign-bit, so
// cast to i64 before range-checking.
SignedInt(ast::IntTy::I8) => add1!((val as i64).to_i8()),
SignedInt(ast::IntTy::I16) => add1!((val as i64).to_i16()),
SignedInt(ast::IntTy::I32) => add1!((val as i64).to_i32()),
SignedInt(ast::IntTy::I64) => add1!(Some(val as i64)),
UnsignedInt(ast::UintTy::U8) => add1!(val.to_u8()),
UnsignedInt(ast::UintTy::U16) => add1!(val.to_u16()),
UnsignedInt(ast::UintTy::U32) => add1!(val.to_u32()),
UnsignedInt(ast::UintTy::U64) => add1!(Some(val)),
UnsignedInt(ast::UintTy::Us) |
SignedInt(ast::IntTy::Is) => unreachable!(),
}
}
// This returns a String because (1.) it is only used for
// rendering an error message and (2.) a string can represent the
// full range from `i64::MIN` through `u64::MAX`.
fn disr_string(&self, val: Disr) -> String {
match *self {
SignedInt(ast::IntTy::I8) => format!("{}", val as i8 ),
SignedInt(ast::IntTy::I16) => format!("{}", val as i16),
SignedInt(ast::IntTy::I32) => format!("{}", val as i32),
SignedInt(ast::IntTy::I64) => format!("{}", val as i64),
UnsignedInt(ast::UintTy::U8) => format!("{}", val as u8 ),
UnsignedInt(ast::UintTy::U16) => format!("{}", val as u16),
UnsignedInt(ast::UintTy::U32) => format!("{}", val as u32),
UnsignedInt(ast::UintTy::U64) => format!("{}", val as u64),
UnsignedInt(ast::UintTy::Us) |
SignedInt(ast::IntTy::Is) => unreachable!(),
}
}
fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
macro_rules! add1 {
($e:expr) => { ($e).wrapping_add(1) as Disr }
}
let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
match *self {
SignedInt(ast::IntTy::I8) => add1!(val as i8 ),
SignedInt(ast::IntTy::I16) => add1!(val as i16),
SignedInt(ast::IntTy::I32) => add1!(val as i32),
SignedInt(ast::IntTy::I64) => add1!(val as i64),
UnsignedInt(ast::UintTy::U8) => add1!(val as u8 ),
UnsignedInt(ast::UintTy::U16) => add1!(val as u16),
UnsignedInt(ast::UintTy::U32) => add1!(val as u32),
UnsignedInt(ast::UintTy::U64) => add1!(val as u64),
UnsignedInt(ast::UintTy::Us) |
SignedInt(ast::IntTy::Is) => unreachable!(),
}
self.assert_ty_matches(val);
(val + ConstInt::Infer(1)).ok()
}
}
@ -266,13 +215,11 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Returns `(normalized_type, ty)`, where `normalized_type` is the
/// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
/// and `ty` is the original type (i.e. may include `isize` or
/// `usize`).
pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
-> (attr::IntType, Ty<'tcx>) {
let repr_type = match opt_hint {
/// Returns the IntType representation.
/// This used to ensure `int_ty` doesn't contain `usize` and `isize`
/// by converting them to their actual types. That doesn't happen anymore.
pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
match opt_hint {
// Feed in the given type
Some(&attr::ReprInt(_, int_t)) => int_t,
// ... but provide sensible default if none provided
@ -280,18 +227,7 @@ impl<'tcx> TyCtxt<'tcx> {
// NB. Historically `fn enum_variants` generate i64 here, while
// rustc_typeck::check would generate isize.
_ => SignedInt(ast::IntTy::Is),
};
let repr_type_ty = repr_type.to_ty(self);
let repr_type = match repr_type {
SignedInt(ast::IntTy::Is) =>
SignedInt(self.sess.target.int_type),
UnsignedInt(ast::UintTy::Us) =>
UnsignedInt(self.sess.target.uint_type),
other => other
};
(repr_type, repr_type_ty)
}
}
/// Returns the deeply last field of nested structures, or the same type,
@ -335,15 +271,16 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
let hint = UncheckedExprHint(self.types.usize);
match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
Ok(val) => {
let found = match val {
ConstVal::Uint(count) => return count as usize,
ConstVal::Int(count) if count >= 0 => return count as usize,
const_val => const_val.description(),
};
Ok(ConstVal::Integral(ConstInt::Usize(count))) => {
let val = count.as_u64(self.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
val as usize
},
Ok(const_val) => {
span_err!(self.sess, count_expr.span, E0306,
"expected positive integer for repeat count, found {}",
found);
"expected positive integer for repeat count, found {}",
const_val.description());
0
}
Err(err) => {
let err_msg = match count_expr.node {
@ -360,9 +297,9 @@ impl<'tcx> TyCtxt<'tcx> {
};
span_err!(self.sess, count_expr.span, E0307,
"expected constant integer for repeat count, {}", err_msg);
0
}
}
0
}
/// Given a set of predicates that apply to an object type, returns

View File

@ -10,6 +10,7 @@
use graphviz::IntoCow;
use middle::const_eval::ConstVal;
use rustc_const_eval::{ConstUsize, ConstInt};
use middle::def_id::DefId;
use middle::subst::Substs;
use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
@ -851,13 +852,12 @@ pub struct Constant<'tcx> {
pub struct TypedConstVal<'tcx> {
pub ty: Ty<'tcx>,
pub span: Span,
pub value: ConstVal
pub value: ConstUsize,
}
impl<'tcx> Debug for TypedConstVal<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
try!(write!(fmt, "const "));
fmt_const_val(fmt, &self.value)
write!(fmt, "const {}", ConstInt::Usize(self.value))
}
}
@ -897,8 +897,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
use middle::const_eval::ConstVal::*;
match *const_val {
Float(f) => write!(fmt, "{:?}", f),
Int(n) => write!(fmt, "{:?}", n),
Uint(n) => write!(fmt, "{:?}", n),
Integral(n) => write!(fmt, "{}", n),
Str(ref s) => write!(fmt, "{:?}", s),
ByteStr(ref bytes) => {
let escaped: String = bytes
@ -911,6 +910,8 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
write!(fmt, "{}", node_to_string(node_id)),
Char(c) => write!(fmt, "{:?}", c),
Dummy => unreachable!(),
}
}

View File

@ -14,7 +14,6 @@
*/
use mir::repr::*;
use middle::const_eval::ConstVal;
use middle::subst::{Subst, Substs};
use middle::ty::{self, AdtDef, Ty, TyCtxt};
use rustc_front::hir;
@ -144,12 +143,10 @@ impl<'tcx> Mir<'tcx> {
match *rvalue {
Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
Rvalue::Repeat(ref operand, ref count) => {
if let ConstVal::Uint(u) = count.value {
let op_ty = self.operand_ty(tcx, operand);
Some(tcx.mk_array(op_ty, u as usize))
} else {
None
}
let op_ty = self.operand_ty(tcx, operand);
let count = count.value.as_u64(tcx.sess.target.uint_type);
assert_eq!(count as usize as u64, count);
Some(tcx.mk_array(op_ty, count as usize))
}
Rvalue::Ref(reg, bk, ref lv) => {
let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);

View File

@ -0,0 +1,14 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_const_eval"
version = "0.0.0"
[lib]
name = "rustc_const_eval"
path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
log = { path = "../liblog" }
serialize = { path = "../libserialize" }
syntax = { path = "../libsyntax" }

View File

@ -0,0 +1,85 @@
// 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)]
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)]
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 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",
UnequalTypes(Rem) => {
"tried to calculate the remainder of two integrals 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(_) => unreachable!(),
Overflow(Add) => "attempted to add with overflow",
Overflow(Sub) => "attempted to subtract with overflow",
Overflow(Mul) => "attempted to multiply with overflow",
Overflow(Div) => "attempted to divide with overflow",
Overflow(Rem) => "attempted to calculate the remainder with overflow",
Overflow(Neg) => "attempted to negate with overflow",
Overflow(Shr) => "attempted to shift right with overflow",
Overflow(Shl) => "attempted to shift left with overflow",
Overflow(_) => unreachable!(),
ShiftNegative => "attempted to shift by a negative amount",
DivisionByZero => "attempted to divide by zero",
RemainderByZero => "attempted 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::Us) => "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::Is) => "literal out of range for isize",
}
}
}

View File

@ -0,0 +1,569 @@
// 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 syntax::attr::IntType;
use syntax::ast::{IntTy, UintTy};
use super::is::*;
use super::us::*;
use super::err::*;
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
pub enum ConstInt {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
Isize(ConstIsize),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
Usize(ConstUsize),
Infer(u64),
InferSigned(i64),
}
pub use self::ConstInt::*;
macro_rules! bounds {
($($t:ident $min:ident $max:ident)*) => {
mod as_u64 {
$(
#[allow(dead_code)]
pub const $min: u64 = ::std::$t::MIN as u64;
#[allow(dead_code)]
pub const $max: u64 = ::std::$t::MAX as u64;
)*
}
mod as_i64 {
$(
#[allow(dead_code)]
pub const $min: i64 = ::std::$t::MIN as i64;
#[allow(dead_code)]
pub const $max: i64 = ::std::$t::MAX as i64;
)*
}
}
}
bounds!{
i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX isize IMIN IMAX
u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX usize UMIN UMAX
}
impl ConstInt {
/// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
/// the other value. If both values have no type, don't do anything
pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
let inferred = match (self, other) {
(InferSigned(_), InferSigned(_))
| (Infer(_), Infer(_)) => self, // no inference possible
// kindof wrong, you could have had values > I64MAX during computation of a
(Infer(a @ 0...as_u64::I64MAX), InferSigned(_)) => InferSigned(a as i64),
(Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
(_, InferSigned(_))
| (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
(Infer(a @ 0...as_u64::I8MAX), I8(_)) => I8(a as i64 as i8),
(Infer(a @ 0...as_u64::I16MAX), I16(_)) => I16(a as i64 as i16),
(Infer(a @ 0...as_u64::I32MAX), I32(_)) => I32(a as i64 as i32),
(Infer(a @ 0...as_u64::I64MAX), I64(_)) => I64(a as i64),
(Infer(a @ 0...as_u64::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
(Infer(a @ 0...as_u64::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
(Infer(a @ 0...as_u64::U8MAX), U8(_)) => U8(a as u8),
(Infer(a @ 0...as_u64::U16MAX), U16(_)) => U16(a as u16),
(Infer(a @ 0...as_u64::U32MAX), U32(_)) => U32(a as u32),
(Infer(a), U64(_)) => U64(a),
(Infer(a @ 0...as_u64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
(Infer(a), Usize(Us64(_))) => Usize(Us64(a)),
(Infer(_), _) => return Err(ConstMathErr::NotInRange),
(InferSigned(a @ as_i64::I8MIN...as_i64::I8MAX), I8(_)) => I8(a as i8),
(InferSigned(a @ as_i64::I16MIN...as_i64::I16MAX), I16(_)) => I16(a as i16),
(InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), I32(_)) => I32(a as i32),
(InferSigned(a), I64(_)) => I64(a),
(InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), Isize(Is32(_))) => {
Isize(Is32(a as i32))
},
(InferSigned(a), Isize(Is64(_))) => Isize(Is64(a)),
(InferSigned(a @ 0...as_i64::U8MAX), U8(_)) => U8(a as u8),
(InferSigned(a @ 0...as_i64::U16MAX), U16(_)) => U16(a as u16),
(InferSigned(a @ 0...as_i64::U32MAX), U32(_)) => U32(a as u32),
(InferSigned(a @ 0...as_i64::I64MAX), U64(_)) => U64(a as u64),
(InferSigned(a @ 0...as_i64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
(InferSigned(a @ 0...as_i64::I64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
(InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
_ => self, // already known types
};
Ok((inferred, other))
}
/// Turn this value into an `Infer` or an `InferSigned`
pub fn erase_type(self) -> Self {
match self {
Infer(i) => Infer(i),
InferSigned(i) if i < 0 => InferSigned(i),
I8(i) if i < 0 => InferSigned(i as i64),
I16(i) if i < 0 => InferSigned(i as i64),
I32(i) if i < 0 => InferSigned(i as i64),
I64(i) if i < 0 => InferSigned(i as i64),
Isize(Is32(i)) if i < 0 => InferSigned(i as i64),
Isize(Is64(i)) if i < 0 => InferSigned(i as i64),
InferSigned(i) => Infer(i as u64),
I8(i) => Infer(i as u64),
I16(i) => Infer(i as u64),
I32(i) => Infer(i as u64),
I64(i) => Infer(i as u64),
Isize(Is32(i)) => Infer(i as u64),
Isize(Is64(i)) => Infer(i as u64),
U8(i) => Infer(i as u64),
U16(i) => Infer(i as u64),
U32(i) => Infer(i as u64),
U64(i) => Infer(i as u64),
Usize(Us32(i)) => Infer(i as u64),
Usize(Us64(i)) => Infer(i),
}
}
/// Description of the type, not the value
pub fn description(&self) -> &'static str {
match *self {
Infer(_) => "not yet inferred integral",
InferSigned(_) => "not yet inferred signed integral",
I8(_) => "i8",
I16(_) => "i16",
I32(_) => "i32",
I64(_) => "i64",
Isize(_) => "isize",
U8(_) => "u8",
U16(_) => "u16",
U32(_) => "u32",
U64(_) => "u64",
Usize(_) => "usize",
}
}
/// Erases the type and returns a u64.
/// This is not the same as `-5i8 as u64` but as `-5i8 as i64 as u64`
pub fn to_u64_unchecked(self) -> u64 {
match self.erase_type() {
ConstInt::Infer(i) => i,
ConstInt::InferSigned(i) => i as u64,
_ => unreachable!(),
}
}
/// Converts the value to a `u32` if it's in the range 0...std::u32::MAX
pub fn to_u32(&self) -> Option<u32> {
match *self {
I8(v) if v >= 0 => Some(v as u32),
I16(v) if v >= 0 => Some(v as u32),
I32(v) if v >= 0 => Some(v as u32),
InferSigned(v)
| Isize(Is64(v))
| I64(v) if v >= 0 && v <= ::std::u32::MAX as i64 => Some(v as u32),
Isize(Is32(v)) if v >= 0 => Some(v as u32),
U8(v) => Some(v as u32),
U16(v) => Some(v as u32),
U32(v) => Some(v),
Infer(v)
| Usize(Us64(v))
| U64(v) if v <= ::std::u32::MAX as u64 => Some(v as u32),
Usize(Us32(v)) => Some(v),
_ => None,
}
}
/// Converts the value to a `u64` if it's >= 0
pub fn to_u64(&self) -> Option<u64> {
match *self {
Infer(v) => Some(v),
InferSigned(v) if v >= 0 => Some(v as u64),
I8(v) if v >= 0 => Some(v as u64),
I16(v) if v >= 0 => Some(v as u64),
I32(v) if v >= 0 => Some(v as u64),
I64(v) if v >= 0 => Some(v as u64),
Isize(Is32(v)) if v >= 0 => Some(v as u64),
Isize(Is64(v)) if v >= 0 => Some(v as u64),
U8(v) => Some(v as u64),
U16(v) => Some(v as u64),
U32(v) => Some(v as u64),
U64(v) => Some(v),
Usize(Us32(v)) => Some(v as u64),
Usize(Us64(v)) => Some(v),
_ => None,
}
}
pub fn is_negative(&self) -> bool {
match *self {
I8(v) => v < 0,
I16(v) => v < 0,
I32(v) => v < 0,
I64(v) => v < 0,
Isize(Is32(v)) => v < 0,
Isize(Is64(v)) => v < 0,
InferSigned(v) => v < 0,
_ => false,
}
}
/// Compares the values if they are of the same type
pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
match try!(self.infer(rhs)) {
(I8(a), I8(b)) => Ok(a.cmp(&b)),
(I16(a), I16(b)) => Ok(a.cmp(&b)),
(I32(a), I32(b)) => Ok(a.cmp(&b)),
(I64(a), I64(b)) => Ok(a.cmp(&b)),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)),
(U8(a), U8(b)) => Ok(a.cmp(&b)),
(U16(a), U16(b)) => Ok(a.cmp(&b)),
(U32(a), U32(b)) => Ok(a.cmp(&b)),
(U64(a), U64(b)) => Ok(a.cmp(&b)),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
(Infer(a), Infer(b)) => Ok(a.cmp(&b)),
(InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
_ => Err(CmpBetweenUnequalTypes),
}
}
/// Adds 1 to the value and wraps around if the maximum for the type is reached
pub fn wrap_incr(self) -> Self {
macro_rules! add1 {
($e:expr) => { ($e).wrapping_add(1) }
}
match self {
ConstInt::I8(i) => ConstInt::I8(add1!(i)),
ConstInt::I16(i) => ConstInt::I16(add1!(i)),
ConstInt::I32(i) => ConstInt::I32(add1!(i)),
ConstInt::I64(i) => ConstInt::I64(add1!(i)),
ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))),
ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))),
ConstInt::U8(i) => ConstInt::U8(add1!(i)),
ConstInt::U16(i) => ConstInt::U16(add1!(i)),
ConstInt::U32(i) => ConstInt::U32(add1!(i)),
ConstInt::U64(i) => ConstInt::U64(add1!(i)),
ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
}
}
pub fn int_type(self) -> Option<IntType> {
match self {
ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
_ => None,
}
}
}
impl ::std::cmp::PartialOrd for ConstInt {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.try_cmp(*other).ok()
}
}
impl ::std::cmp::Ord for ConstInt {
fn cmp(&self, other: &Self) -> Ordering {
self.try_cmp(*other).unwrap()
}
}
impl ::std::fmt::Display for ConstInt {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
match *self {
Infer(i) => write!(fmt, "{}", i),
InferSigned(i) => write!(fmt, "{}", i),
I8(i) => write!(fmt, "{}i8", i),
I16(i) => write!(fmt, "{}i16", i),
I32(i) => write!(fmt, "{}i32", i),
I64(i) => write!(fmt, "{}i64", i),
Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i),
Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i),
U8(i) => write!(fmt, "{}u8", i),
U16(i) => write!(fmt, "{}u16", i),
U32(i) => write!(fmt, "{}u32", i),
U64(i) => write!(fmt, "{}u64", i),
Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i),
Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i),
}
}
}
macro_rules! overflowing {
($e:expr, $err:expr) => {{
if $e.1 {
return Err(Overflow($err));
} else {
$e.0
}
}}
}
macro_rules! impl_binop {
($op:ident, $func:ident, $checked_func:ident) => {
impl ::std::ops::$op for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
match try!(self.infer(rhs)) {
(I8(a), I8(b)) => a.$checked_func(b).map(I8),
(I16(a), I16(b)) => a.$checked_func(b).map(I16),
(I32(a), I32(b)) => a.$checked_func(b).map(I32),
(I64(a), I64(b)) => a.$checked_func(b).map(I64),
(Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize),
(Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize),
(U8(a), U8(b)) => a.$checked_func(b).map(U8),
(U16(a), U16(b)) => a.$checked_func(b).map(U16),
(U32(a), U32(b)) => a.$checked_func(b).map(U32),
(U64(a), U64(b)) => a.$checked_func(b).map(U64),
(Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
(Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
(Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
(InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
_ => return Err(UnequalTypes(Op::$op)),
}.ok_or(Overflow(Op::$op))
}
}
}
}
macro_rules! derive_binop {
($op:ident, $func:ident) => {
impl ::std::ops::$op for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
match try!(self.infer(rhs)) {
(I8(a), I8(b)) => Ok(I8(a.$func(b))),
(I16(a), I16(b)) => Ok(I16(a.$func(b))),
(I32(a), I32(b)) => Ok(I32(a.$func(b))),
(I64(a), I64(b)) => Ok(I64(a.$func(b))),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))),
(U8(a), U8(b)) => Ok(U8(a.$func(b))),
(U16(a), U16(b)) => Ok(U16(a.$func(b))),
(U32(a), U32(b)) => Ok(U32(a.$func(b))),
(U64(a), U64(b)) => Ok(U64(a.$func(b))),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
(Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
_ => Err(UnequalTypes(Op::$op)),
}
}
}
}
}
impl_binop!(Add, add, checked_add);
impl_binop!(Sub, sub, checked_sub);
impl_binop!(Mul, mul, checked_mul);
derive_binop!(BitAnd, bitand);
derive_binop!(BitOr, bitor);
derive_binop!(BitXor, bitxor);
fn check_division(
lhs: ConstInt,
rhs: ConstInt,
op: Op,
zerr: ConstMathErr,
) -> Result<(), ConstMathErr> {
match (lhs, rhs) {
(I8(_), I8(0)) => Err(zerr),
(I16(_), I16(0)) => Err(zerr),
(I32(_), I32(0)) => Err(zerr),
(I64(_), I64(0)) => Err(zerr),
(Isize(_), Isize(Is32(0))) => Err(zerr),
(Isize(_), Isize(Is64(0))) => Err(zerr),
(InferSigned(_), InferSigned(0)) => Err(zerr),
(U8(_), U8(0)) => Err(zerr),
(U16(_), U16(0)) => Err(zerr),
(U32(_), U32(0)) => Err(zerr),
(U64(_), U64(0)) => Err(zerr),
(Usize(_), Usize(Us32(0))) => Err(zerr),
(Usize(_), Usize(Us64(0))) => Err(zerr),
(Infer(_), Infer(0)) => Err(zerr),
(I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
(I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
(I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)),
(I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)),
(Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
(Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
(InferSigned(::std::i64::MIN), InferSigned(-1)) => Err(Overflow(op)),
_ => Ok(()),
}
}
impl ::std::ops::Div for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
let (lhs, rhs) = try!(self.infer(rhs));
try!(check_division(lhs, rhs, Op::Div, DivisionByZero));
match (lhs, rhs) {
(I8(a), I8(b)) => Ok(I8(a/b)),
(I16(a), I16(b)) => Ok(I16(a/b)),
(I32(a), I32(b)) => Ok(I32(a/b)),
(I64(a), I64(b)) => Ok(I64(a/b)),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
(U8(a), U8(b)) => Ok(U8(a/b)),
(U16(a), U16(b)) => Ok(U16(a/b)),
(U32(a), U32(b)) => Ok(U32(a/b)),
(U64(a), U64(b)) => Ok(U64(a/b)),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
(Infer(a), Infer(b)) => Ok(Infer(a/b)),
_ => Err(UnequalTypes(Op::Div)),
}
}
}
impl ::std::ops::Rem for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
let (lhs, rhs) = try!(self.infer(rhs));
// should INT_MIN%-1 be zero or an error?
try!(check_division(lhs, rhs, Op::Rem, RemainderByZero));
match (lhs, rhs) {
(I8(a), I8(b)) => Ok(I8(a%b)),
(I16(a), I16(b)) => Ok(I16(a%b)),
(I32(a), I32(b)) => Ok(I32(a%b)),
(I64(a), I64(b)) => Ok(I64(a%b)),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
(U8(a), U8(b)) => Ok(U8(a%b)),
(U16(a), U16(b)) => Ok(U16(a%b)),
(U32(a), U32(b)) => Ok(U32(a%b)),
(U64(a), U64(b)) => Ok(U64(a%b)),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
(Infer(a), Infer(b)) => Ok(Infer(a%b)),
_ => Err(UnequalTypes(Op::Rem)),
}
}
}
impl ::std::ops::Shl<ConstInt> for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
let b = try!(rhs.to_u32().ok_or(ShiftNegative));
match self {
I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))),
I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))),
I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))),
I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))),
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))),
U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))),
U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))),
U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))),
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
}
}
}
impl ::std::ops::Shr<ConstInt> for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
let b = try!(rhs.to_u32().ok_or(ShiftNegative));
match self {
I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shl))),
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),
U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))),
U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))),
U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))),
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
}
}
}
impl ::std::ops::Neg for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn neg(self) -> Result<Self, ConstMathErr> {
match self {
I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))),
I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))),
I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))),
I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))),
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))),
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))),
U8(0) => Ok(U8(0)),
U16(0) => Ok(U16(0)),
U32(0) => Ok(U32(0)),
U64(0) => Ok(U64(0)),
Usize(Us32(0)) => Ok(Usize(Us32(0))),
Usize(Us64(0)) => Ok(Usize(Us64(0))),
U8(_) => Err(UnsignedNegation),
U16(_) => Err(UnsignedNegation),
U32(_) => Err(UnsignedNegation),
U64(_) => Err(UnsignedNegation),
Usize(_) => Err(UnsignedNegation),
Infer(a @ 0...as_u64::I64MAX) => Ok(InferSigned(-(a as i64))),
Infer(_) => Err(Overflow(Op::Neg)),
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
}
}
}
impl ::std::ops::Not for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn not(self) -> Result<Self, ConstMathErr> {
match self {
I8(a) => Ok(I8(!a)),
I16(a) => Ok(I16(!a)),
I32(a) => Ok(I32(!a)),
I64(a) => Ok(I64(!a)),
Isize(Is32(a)) => Ok(Isize(Is32(!a))),
Isize(Is64(a)) => Ok(Isize(Is64(!a))),
U8(a) => Ok(U8(!a)),
U16(a) => Ok(U16(!a)),
U32(a) => Ok(U32(!a)),
U64(a) => Ok(U64(!a)),
Usize(Us32(a)) => Ok(Usize(Us32(!a))),
Usize(Us64(a)) => Ok(Usize(Us64(!a))),
Infer(a) => Ok(Infer(!a)),
InferSigned(a) => Ok(InferSigned(!a)),
}
}
}

View File

@ -0,0 +1,39 @@
// 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;
use super::err::*;
/// Depending on the target only one variant is ever used in a compilation.
/// Anything else is an error. This invariant is checked at several locations
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
pub enum ConstIsize {
Is32(i32),
Is64(i64),
}
pub use self::ConstIsize::*;
impl ConstIsize {
pub fn as_i64(self, target_int_ty: ast::IntTy) -> i64 {
match (self, target_int_ty) {
(Is32(i), ast::IntTy::I32) => i as i64,
(Is64(i), ast::IntTy::I64) => i,
_ => panic!("got invalid isize size for target"),
}
}
pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result<Self, ConstMathErr> {
match target_int_ty {
ast::IntTy::I32 if i as i32 as i64 == i => Ok(Is32(i as i32)),
ast::IntTy::I32 => Err(LitOutOfRange(ast::IntTy::Is)),
ast::IntTy::I64 => Ok(Is64(i)),
_ => unreachable!(),
}
}
}

View File

@ -0,0 +1,42 @@
// 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.
#![crate_name = "rustc_const_eval"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![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/")]
#![feature(rustc_private)]
#![feature(staged_api)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate serialize as rustc_serialize; // used by deriving
mod int;
mod us;
mod is;
mod err;
pub use int::*;
pub use us::*;
pub use is::*;
pub use err::ConstMathErr;

View File

@ -0,0 +1,39 @@
// 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;
use super::err::*;
/// Depending on the target only one variant is ever used in a compilation.
/// Anything else is an error. This invariant is checked at several locations
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
pub enum ConstUsize {
Us32(u32),
Us64(u64),
}
pub use self::ConstUsize::*;
impl ConstUsize {
pub fn as_u64(self, target_uint_ty: ast::UintTy) -> u64 {
match (self, target_uint_ty) {
(Us32(i), ast::UintTy::U32) => i as u64,
(Us64(i), ast::UintTy::U64) => i,
_ => panic!("got invalid usize size for target"),
}
}
pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result<Self, ConstMathErr> {
match target_uint_ty {
ast::UintTy::U32 if i as u32 as u64 == i => Ok(Us32(i as u32)),
ast::UintTy::U32 => Err(ULitOutOfRange(ast::UintTy::Us)),
ast::UintTy::U64 => Ok(Us64(i)),
_ => unreachable!(),
}
}
}

View File

@ -143,8 +143,11 @@ impl LateLintPass for TypeLimits {
else { false }
} else {
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
Ok(ConstVal::Uint(shift)) => { shift >= bits },
Ok(ConstVal::Integral(i)) => {
i.is_negative() || i.to_u64()
.map(|i| i >= bits)
.unwrap_or(true)
},
_ => { false }
}
};

View File

@ -15,6 +15,7 @@ rbml = { path = "../librbml" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_bitflags = { path = "../librustc_bitflags" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_front = { path = "../librustc_front" }
rustc_llvm = { path = "../librustc_llvm" }
serialize = { path = "../libserialize" }

View File

@ -35,6 +35,8 @@ use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
use rustc_const_eval::ConstInt;
use rustc::mir;
use rustc::mir::visit::MutVisitor;
@ -198,7 +200,7 @@ fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
reader::tagged_docs(d, tag_items_data_item_reexport)
}
fn variant_disr_val(d: rbml::Doc) -> Option<ty::Disr> {
fn variant_disr_val(d: rbml::Doc) -> Option<u64> {
reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
reader::with_doc_data(val_doc, |data| {
str::from_utf8(data).ok().and_then(|s| s.parse().ok())
@ -396,7 +398,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
did: did,
name: item_name(intr, item),
fields: get_variant_fields(intr, cdata, item, tcx),
disr_val: disr,
disr_val: ConstInt::Infer(disr),
kind: expect_variant_kind(item_family(item), tcx),
}
}).collect()
@ -432,7 +434,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
did: did,
name: item_name(intr, doc),
fields: get_variant_fields(intr, cdata, doc, tcx),
disr_val: 0,
disr_val: ConstInt::Infer(0),
kind: expect_variant_kind(item_family(doc), tcx),
}
}

View File

@ -26,6 +26,7 @@ use middle::dependency_format::Linkage;
use middle::stability;
use middle::subst;
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::util::IntTypeExt;
use rustc::back::svh::Svh;
use rustc::front::map::{LinkedPath, PathElem, PathElems};
@ -238,7 +239,8 @@ fn encode_symbol(ecx: &EncodeContext,
fn encode_disr_val(_: &EncodeContext,
rbml_w: &mut Encoder,
disr_val: ty::Disr) {
rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_string());
// convert to u64 so just the number is printed, without any type info
rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
}
fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
@ -262,13 +264,14 @@ fn encode_struct_fields(rbml_w: &mut Encoder,
fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
id: NodeId,
did: DefId,
vis: hir::Visibility,
index: &mut CrateIndex<'tcx>) {
debug!("encode_enum_variant_info(id={})", id);
let mut disr_val = 0;
let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id));
debug!("encode_enum_variant_info(did={:?})", did);
let repr_hints = ecx.tcx.lookup_repr_hints(did);
let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
let mut disr_val = repr_type.initial_discriminant(&ecx.tcx);
let def = ecx.tcx.lookup_adt_def(did);
for variant in &def.variants {
let vid = variant.did;
let variant_node_id = ecx.local_id(vid);
@ -290,7 +293,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
ty::VariantKind::Unit => 'w',
});
encode_name(rbml_w, variant.name);
encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
encode_parent_item(rbml_w, did);
encode_visibility(rbml_w, vis);
let attrs = ecx.tcx.get_attrs(vid);
@ -313,7 +316,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path));
rbml_w.end_tag();
disr_val = disr_val.wrapping_add(1);
disr_val = disr_val.wrap_incr();
}
}
@ -1035,7 +1038,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
encode_enum_variant_info(ecx,
rbml_w,
item.id,
def_id,
vis,
index);
}

View File

@ -36,6 +36,7 @@ extern crate rustc;
extern crate rustc_back;
extern crate rustc_front;
extern crate rustc_llvm;
extern crate rustc_const_eval;
pub use rustc::middle;

View File

@ -13,6 +13,7 @@ graphviz = { path = "../libgraphviz" }
log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_front = { path = "../librustc_front" }
syntax = { path = "../libsyntax" }

View File

@ -269,7 +269,7 @@ enum TestKind<'tcx> {
// test length of the slice is equal to len
Len {
len: usize,
len: u64,
op: BinOp,
},
}

View File

@ -84,7 +84,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
};
Test {
span: match_pair.pattern.span,
kind: TestKind::Len { len: len, op: op },
kind: TestKind::Len { len: len as u64, op: op },
}
}

View File

@ -46,7 +46,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
Operand::Constant(constant)
}
pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> {
pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: u64) -> Lvalue<'tcx> {
let usize_ty = self.hir.usize_ty();
let temp = self.temp(usize_ty);
self.cfg.push_assign_constant(

View File

@ -94,6 +94,8 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
use rustc::mir::repr::*;
use syntax::codemap::{Span, DUMMY_SP};
use syntax::parse::token::intern_and_get_ident;
use rustc::middle::const_eval::ConstVal;
use rustc_const_eval::ConstInt;
pub struct Scope<'tcx> {
extent: CodeExtent,
@ -517,7 +519,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}, Constant {
span: span,
ty: self.hir.tcx().types.u32,
literal: self.hir.usize_literal(span_lines.line)
literal: Literal::Value {
value: ConstVal::Integral(ConstInt::U32(span_lines.line as u32)),
},
})
}

View File

@ -10,12 +10,13 @@
use hair::*;
use rustc_data_structures::fnv::FnvHashMap;
use rustc_const_eval::ConstInt;
use hair::cx::Cx;
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::front::map;
use rustc::middle::def::Def;
use rustc::middle::const_eval;
use rustc::middle::const_eval::{self, ConstVal};
use rustc::middle::region::CodeExtent;
use rustc::middle::pat_util;
use rustc::middle::ty::{self, VariantDef, Ty};
@ -227,28 +228,37 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
}
}
hir::ExprUnary(op, ref arg) => {
hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
if cx.tcx.is_method_call(self.id) {
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
PassArgs::ByValue, arg.to_ref(), vec![])
} else {
// FIXME overflow
let op = match op {
hir::UnOp::UnNot => UnOp::Not,
hir::UnOp::UnNeg => UnOp::Neg,
hir::UnOp::UnDeref => {
cx.tcx.sess.span_bug(
self.span,
"UnDeref should have been handled elsewhere");
}
};
ExprKind::Unary {
op: op,
op: UnOp::Not,
arg: arg.to_ref(),
}
}
}
hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
if cx.tcx.is_method_call(self.id) {
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
PassArgs::ByValue, arg.to_ref(), vec![])
} else {
// FIXME runtime-overflow
if let hir::ExprLit(_) = arg.node {
ExprKind::Literal {
literal: cx.const_eval_literal(self),
}
} else {
ExprKind::Unary {
op: UnOp::Neg,
arg: arg.to_ref(),
}
}
}
}
hir::ExprStruct(_, ref fields, ref base) => {
match expr_ty.sty {
ty::TyStruct(adt, substs) => {
@ -338,7 +348,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
count: TypedConstVal {
ty: cx.tcx.expr_ty(c),
span: c.span,
value: const_eval::eval_const_expr(cx.tcx, c)
value: match const_eval::eval_const_expr(cx.tcx, c) {
ConstVal::Integral(ConstInt::Usize(u)) => u,
other => panic!("constant evaluation of repeat count yielded {:?}", other),
},
}
},
hir::ExprRet(ref v) =>

View File

@ -24,6 +24,7 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
use syntax::codemap::Span;
use syntax::parse::token;
use rustc_front::hir;
use rustc_const_eval::{ConstInt, ConstUsize};
#[derive(Copy, Clone)]
pub struct Cx<'a, 'tcx: 'a> {
@ -50,8 +51,11 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
self.tcx.types.usize
}
pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
Literal::Value { value: ConstVal::Uint(value as u64) }
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val))},
Err(_) => panic!("usize literal out of range for target"),
}
}
pub fn bool_ty(&mut self) -> Ty<'tcx> {

View File

@ -87,7 +87,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
Def::Const(def_id) | Def::AssociatedConst(def_id) =>
match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
Some(pat.id), None) {
Some(const_expr) => {
Some((const_expr, _const_ty)) => {
let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
pat.span);
return self.to_pattern(&pat);

View File

@ -31,6 +31,7 @@ extern crate rustc_data_structures;
extern crate rustc_front;
extern crate rustc_back;
extern crate syntax;
extern crate rustc_const_eval;
pub mod build;
pub mod graphviz;

View File

@ -604,7 +604,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
}
Some(Def::Const(did)) |
Some(Def::AssociatedConst(did)) => {
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
if let Some((expr, _ty)) = const_eval::lookup_const_by_id(v.tcx, did,
Some(e.id),
None) {
let inner = v.global_expr(Mode::Const, expr);

View File

@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" }
log = { path = "../liblog" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_front = { path = "../librustc_front" }
rustc_llvm = { path = "../librustc_llvm" }

View File

@ -50,6 +50,7 @@ pub extern crate rustc_llvm as llvm;
extern crate rustc_mir;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate serialize;
extern crate rustc_const_eval;
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

View File

@ -1035,7 +1035,7 @@ fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
match ity {
attr::UnsignedInt(_) => {
assert!(min <= discr);
assert!(discr <= max)
assert!(discr <= max);
},
attr::SignedInt(_) => {
assert!(min.0 as i64 <= discr.0 as i64);

View File

@ -15,15 +15,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
use middle::const_qualif::ConstQualif;
use middle::cstore::LOCAL_CRATE;
use middle::const_eval::{self, ConstVal, ConstEvalErr};
use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
use middle::const_eval::{const_int_checked_mul, const_uint_checked_mul};
use middle::const_eval::{const_int_checked_div, const_uint_checked_div};
use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
use middle::const_eval::{self, ConstEvalErr};
use middle::def::Def;
use middle::def_id::DefId;
use trans::{adt, closure, debuginfo, expr, inline, machine};
@ -42,9 +34,10 @@ use trans::Disr;
use middle::subst::Substs;
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
use middle::ty::{self, Ty};
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::cast::{CastTy,IntTy};
use util::nodemap::NodeMap;
use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize};
use rustc_front::hir;
@ -234,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) {
Some(ref expr) => expr,
Some((ref expr, _ty)) => expr,
None => {
ccx.sess().span_bug(ref_expr.span, "constant item not found")
}
@ -469,35 +462,70 @@ fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
// Catch this up front by looking for ExprLit directly,
// and just accepting it.
if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
let result = match t.sty {
ty::TyInt(int_type) => {
let input = match const_to_opt_int(te) {
Some(v) => v,
None => return Ok(()),
};
const_int_checked_neg(
input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
}
ty::TyUint(uint_type) => {
let input = match const_to_opt_uint(te) {
Some(v) => v,
None => return Ok(()),
};
const_uint_checked_neg(
input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
}
_ => return Ok(()),
let cval = match to_const_int(te, t, cx.tcx()) {
Some(v) => v,
None => return Ok(()),
};
const_err(cx, e, result, trueconst)
match -cval {
Ok(_) => return Ok(()),
Err(err) => const_err(cx, e, Err(err), trueconst),
}
} else {
Ok(())
}
}
fn to_const_int(value: ValueRef, t: Ty, tcx: &TyCtxt) -> Option<ConstInt> {
match t.sty {
ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
ast::IntTy::I8 => {
assert_eq!(input as i8 as i64, input);
Some(ConstInt::I8(input as i8))
},
ast::IntTy::I16 => {
assert_eq!(input as i16 as i64, input);
Some(ConstInt::I16(input as i16))
},
ast::IntTy::I32 => {
assert_eq!(input as i32 as i64, input);
Some(ConstInt::I32(input as i32))
},
ast::IntTy::I64 => {
Some(ConstInt::I64(input))
},
ast::IntTy::Is => {
ConstIsize::new(input, tcx.sess.target.int_type)
.ok().map(ConstInt::Isize)
},
}),
ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
ast::UintTy::U8 => {
assert_eq!(input as u8 as u64, input);
Some(ConstInt::U8(input as u8))
},
ast::UintTy::U16 => {
assert_eq!(input as u16 as u64, input);
Some(ConstInt::U16(input as u16))
},
ast::UintTy::U32 => {
assert_eq!(input as u32 as u64, input);
Some(ConstInt::U32(input as u32))
},
ast::UintTy::U64 => {
Some(ConstInt::U64(input))
},
ast::UintTy::Us => {
ConstUsize::new(input, tcx.sess.target.uint_type)
.ok().map(ConstInt::Usize)
},
}),
_ => None,
}
}
fn const_err(cx: &CrateContext,
e: &hir::Expr,
result: Result<ConstVal, ConstEvalErr>,
result: Result<ConstInt, ConstMathErr>,
trueconst: TrueConst)
-> Result<(), ConstEvalFailure> {
match (result, trueconst) {
@ -506,10 +534,12 @@ fn const_err(cx: &CrateContext,
Ok(())
},
(Err(err), TrueConst::Yes) => {
let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
cx.tcx().sess.span_err(e.span, &err.description());
Err(Compiletime(err))
},
(Err(err), TrueConst::No) => {
let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
cx.tcx().sess.span_warn(e.span, &err.description());
Err(Runtime(err))
},
@ -520,46 +550,18 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
te1: ValueRef, te2: ValueRef,
trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() };
let result = match t.sty {
ty::TyInt(int_type) => {
let (lhs, rhs) = match (const_to_opt_int(te1),
const_to_opt_int(te2)) {
(Some(v1), Some(v2)) => (v1, v2),
_ => return Ok(()),
};
let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
match b.node {
hir::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
hir::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
hir::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
hir::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
hir::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
hir::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
_ => return Ok(()),
}
}
ty::TyUint(uint_type) => {
let (lhs, rhs) = match (const_to_opt_uint(te1),
const_to_opt_uint(te2)) {
(Some(v1), Some(v2)) => (v1, v2),
_ => return Ok(()),
};
let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
match b.node {
hir::BiAdd => const_uint_checked_add(lhs, rhs, e, opt_ety),
hir::BiSub => const_uint_checked_sub(lhs, rhs, e, opt_ety),
hir::BiMul => const_uint_checked_mul(lhs, rhs, e, opt_ety),
hir::BiDiv => const_uint_checked_div(lhs, rhs, e, opt_ety),
hir::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
hir::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
hir::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
_ => return Ok(()),
}
}
let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) {
(Some(v1), Some(v2)) => (v1, v2),
_ => return Ok(()),
};
let result = match b.node {
hir::BiAdd => lhs + rhs,
hir::BiSub => lhs - rhs,
hir::BiMul => lhs * rhs,
hir::BiDiv => lhs / rhs,
hir::BiRem => lhs % rhs,
hir::BiShl => lhs << rhs,
hir::BiShr => lhs >> rhs,
_ => return Ok(()),
};
const_err(cx, e, result, trueconst)

View File

@ -1597,7 +1597,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
llvm::LLVMDIBuilderCreateEnumerator(
DIB(cx),
name.as_ptr(),
v.disr_val as u64)
v.disr_val.to_u64_unchecked())
}
})
.collect();

View File

@ -26,7 +26,7 @@ impl ::std::ops::BitAnd for Disr {
impl From<::middle::ty::Disr> for Disr {
fn from(i: ::middle::ty::Disr) -> Disr {
Disr(i)
Disr(i.to_u64_unchecked())
}
}

View File

@ -12,6 +12,7 @@ use back::abi;
use llvm::ValueRef;
use middle::ty::{Ty, TypeFoldable};
use rustc::middle::const_eval::{self, ConstVal};
use rustc_const_eval::ConstInt::*;
use rustc::mir::repr as mir;
use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
C_str_slice, C_nil, C_undef};
@ -19,6 +20,7 @@ use trans::consts;
use trans::expr;
use trans::inline;
use trans::type_of;
use trans::type_::Type;
use super::operand::{OperandRef, OperandValue};
use super::MirContext;
@ -63,8 +65,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
match *cv {
ConstVal::Float(v) => C_floating_f64(v, llty),
ConstVal::Bool(v) => C_bool(ccx, v),
ConstVal::Int(v) => C_integral(llty, v as u64, true),
ConstVal::Uint(v) => C_integral(llty, v, false),
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),
ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
ConstVal::Integral(Isize(v)) => {
let i = v.as_i64(ccx.tcx().sess.target.int_type);
C_integral(Type::int(ccx), i as u64, true)
},
ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
ConstVal::Integral(Usize(v)) => {
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::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(id) | ConstVal::Tuple(id) |
@ -74,6 +92,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
expr::trans(bcx, expr).datum.val
})
},
ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
ConstVal::Dummy => unreachable!(),
ConstVal::Function(_) => C_nil(ccx)
}
}
@ -99,7 +119,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs))
.expect("def was const, but lookup_const_by_id failed");
.expect("def was const, but lookup_const_by_id failed").0;
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
let d = bcx.with_block(|bcx| {

View File

@ -11,6 +11,8 @@
use llvm::ValueRef;
use rustc::middle::ty::{self, Ty};
use middle::ty::cast::{CastTy, IntTy};
use middle::const_eval::ConstVal;
use rustc_const_eval::ConstInt;
use rustc::mir::repr as mir;
use trans::asm;
@ -95,7 +97,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
mir::Rvalue::Repeat(ref elem, ref count) => {
let tr_elem = self.trans_operand(&bcx, elem);
let size = self.trans_constval(&bcx, &count.value, count.ty).immediate();
let count = ConstVal::Integral(ConstInt::Usize(count.value));
let size = self.trans_constval(&bcx, &count, bcx.tcx().types.usize).immediate();
let bcx = bcx.map_block(|block| {
let base = expr::get_dataptr(block, dest.llval);
tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {

View File

@ -15,5 +15,6 @@ arena = { path = "../libarena" }
fmt_macros = { path = "../libfmt_macros" }
rustc = { path = "../librustc" }
rustc_back = { path = "../librustc_back" }
rustc_const_eval = { path = "../librustc_const_eval" }
rustc_front = { path = "../librustc_front" }
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }

View File

@ -65,6 +65,8 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::FnvHashSet;
use rustc_const_eval::ConstInt;
use syntax::{abi, ast};
use syntax::codemap::{Span, Pos};
use syntax::errors::DiagnosticBuilder;
@ -1680,22 +1682,16 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
hir::TyFixedLengthVec(ref ty, ref e) => {
let hint = UncheckedExprHint(tcx.types.usize);
match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
Ok(r) => {
match r {
ConstVal::Int(i) =>
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
i as usize),
ConstVal::Uint(i) =>
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
i as usize),
_ => {
span_err!(tcx.sess, ast_ty.span, E0249,
"expected constant integer expression \
for array length");
this.tcx().types.err
}
}
}
Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
let i = i.as_u64(tcx.sess.target.uint_type);
assert_eq!(i as usize as u64, i);
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty), i as usize)
},
Ok(val) => {
span_err!(tcx.sess, ast_ty.span, E0249,
"expected usize value for array length, got {}", val.description());
this.tcx().types.err
},
Err(ref r) => {
let mut err = struct_span_err!(tcx.sess, r.span, E0250,
"array length constant evaluation error: {}",

View File

@ -94,7 +94,7 @@ use middle::pat_util::{self, pat_id_map};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
use middle::traits::{self, report_fulfillment_errors};
use middle::ty::{GenericPredicates, TypeScheme};
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
use middle::ty::{ParamTy, ParameterEnvironment};
use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
use middle::ty::{MethodCall, MethodCallee};
@ -102,7 +102,7 @@ use middle::ty::adjustment;
use middle::ty::error::TypeError;
use middle::ty::fold::{TypeFolder, TypeFoldable};
use middle::ty::relate::TypeRelation;
use middle::ty::util::Representability;
use middle::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic;
use rscope::{ElisionFailureInfo, RegionScope};
use session::{Session, CompileResult};
@ -4076,34 +4076,6 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
sp: Span,
vs: &'tcx [hir::Variant],
id: ast::NodeId) {
// disr_in_range should be removed once we have forced type hints for consts
fn disr_in_range(ccx: &CrateCtxt,
ty: attr::IntType,
disr: ty::Disr) -> bool {
fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
match ty {
ast::UintTy::U8 => disr as u8 as Disr == disr,
ast::UintTy::U16 => disr as u16 as Disr == disr,
ast::UintTy::U32 => disr as u32 as Disr == disr,
ast::UintTy::U64 => disr as u64 as Disr == disr,
ast::UintTy::Us => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
}
}
fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
match ty {
ast::IntTy::I8 => disr as i8 as Disr == disr,
ast::IntTy::I16 => disr as i16 as Disr == disr,
ast::IntTy::I32 => disr as i32 as Disr == disr,
ast::IntTy::I64 => disr as i64 as Disr == disr,
ast::IntTy::Is => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
}
}
match ty {
attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
}
}
fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
vs: &'tcx [hir::Variant],
id: ast::NodeId,
@ -4117,7 +4089,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
let inh = static_inherited_fields(ccx, &tables);
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
let (_, repr_type_ty) = ccx.tcx.enum_repr_type(Some(&hint));
let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(&ccx.tcx);
for v in vs {
if let Some(ref e) = v.node.disr_expr {
check_const_with_ty(&fcx, e.span, e, repr_type_ty);
@ -4142,23 +4114,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
}
None => {}
}
// Check for unrepresentable discriminant values
match hint {
attr::ReprAny | attr::ReprExtern => {
disr_vals.push(current_disr_val);
}
attr::ReprInt(sp, ity) => {
if !disr_in_range(ccx, ity, current_disr_val) {
let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082,
"discriminant value outside specified type");
span_note!(&mut err, sp,
"discriminant type specified here");
err.emit();
}
}
// Error reported elsewhere.
attr::ReprSimd | attr::ReprPacked => {}
}
disr_vals.push(current_disr_val);
}
}

View File

@ -81,6 +81,8 @@ use util::common::{ErrorReported, MemoizationMap};
use util::nodemap::{FnvHashMap, FnvHashSet};
use write_ty_to_tcx;
use rustc_const_eval::ConstInt;
use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc;
@ -1012,7 +1014,7 @@ fn convert_struct_def<'tcx>(tcx: &TyCtxt<'tcx>,
tcx.intern_adt_def(
did,
ty::AdtKind::Struct,
vec![convert_struct_variant(tcx, ctor_id, it.name, 0, def)]
vec![convert_struct_variant(tcx, ctor_id, it.name, ConstInt::Infer(0), def)]
)
}
@ -1021,24 +1023,39 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
def: &hir::EnumDef)
-> ty::AdtDefMaster<'tcx>
{
fn print_err(tcx: &TyCtxt, span: Span, ty: ty::Ty, cv: ConstVal) {
span_err!(tcx.sess, span, E0079, "mismatched types: expected `{}` got `{}`",
ty, cv.description());
}
fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>,
repr_ty: Ty<'tcx>,
repr_ty: attr::IntType,
e: &hir::Expr) -> Option<ty::Disr> {
debug!("disr expr, checking {}", pprust::expr_to_string(e));
let hint = UncheckedExprHint(repr_ty);
let ty_hint = repr_ty.to_ty(tcx);
let hint = UncheckedExprHint(ty_hint);
match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
Ok(ConstVal::Int(val)) => Some(val as ty::Disr),
Ok(ConstVal::Uint(val)) => Some(val as ty::Disr),
Ok(_) => {
let sign_desc = if repr_ty.is_signed() {
"signed"
} else {
"unsigned"
};
span_err!(tcx.sess, e.span, E0079,
"expected {} integer constant",
sign_desc);
Ok(ConstVal::Integral(i)) => {
// FIXME: eval_const_expr_partial should return an error if the hint is wrong
match (repr_ty, i) {
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => Some(i),
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => Some(i),
(attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => Some(i),
(attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => Some(i),
(attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => Some(i),
(attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => Some(i),
(attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => Some(i),
(attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => Some(i),
(attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => Some(i),
(attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i),
(_, i) => {
print_err(tcx, e.span, ty_hint, ConstVal::Integral(i));
None
},
}
},
Ok(cv) => {
print_err(tcx, e.span, ty_hint, cv);
None
},
Err(err) => {
@ -1057,16 +1074,11 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
fn report_discrim_overflow(tcx: &TyCtxt,
variant_span: Span,
variant_name: &str,
repr_type: attr::IntType,
prev_val: ty::Disr) {
let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
let computed_value = repr_type.disr_string(computed_value);
let prev_val = repr_type.disr_string(prev_val);
let repr_type = repr_type.to_ty(tcx);
span_err!(tcx.sess, variant_span, E0370,
"enum discriminant overflowed on value after {}: {}; \
"enum discriminant overflowed on value after {}; \
set explicitly via {} = {} if that is desired outcome",
prev_val, repr_type, variant_name, computed_value);
prev_val, variant_name, prev_val.wrap_incr());
}
fn next_disr(tcx: &TyCtxt,
@ -1076,12 +1088,11 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
if let Some(prev_disr_val) = prev_disr_val {
let result = repr_type.disr_incr(prev_disr_val);
if let None = result {
report_discrim_overflow(tcx, v.span, &v.node.name.as_str(),
repr_type, prev_disr_val);
report_discrim_overflow(tcx, v.span, &v.node.name.as_str(), prev_disr_val);
}
result
} else {
Some(ty::INITIAL_DISCRIMINANT_VALUE)
Some(repr_type.initial_discriminant(tcx))
}
}
fn convert_enum_variant<'tcx>(tcx: &TyCtxt<'tcx>,
@ -1095,17 +1106,19 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
}
let did = tcx.map.local_def_id(it.id);
let repr_hints = tcx.lookup_repr_hints(did);
let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0));
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
let mut prev_disr = None;
let variants = def.variants.iter().map(|v| {
let disr = match v.node.disr_expr {
Some(ref e) => evaluate_disr_expr(tcx, repr_type_ty, e),
Some(ref e) => evaluate_disr_expr(tcx, repr_type, e),
None => next_disr(tcx, v, repr_type, prev_disr)
}.unwrap_or(repr_type.disr_wrap_incr(prev_disr));
}.unwrap_or_else(|| {
prev_disr.map(ty::Disr::wrap_incr)
.unwrap_or(repr_type.initial_discriminant(tcx))
});
let v = convert_enum_variant(tcx, v, disr);
prev_disr = Some(disr);
v
convert_enum_variant(tcx, v, disr)
}).collect();
tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
}

View File

@ -91,6 +91,7 @@ extern crate rustc;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_front;
extern crate rustc_back;
extern crate rustc_const_eval;
pub use rustc::dep_graph;
pub use rustc::front;

View File

@ -337,7 +337,7 @@ pub fn build_impl(cx: &DocContext,
let type_scheme = tcx.lookup_item_type(did);
let default = if assoc_const.has_value {
Some(const_eval::lookup_const_by_id(tcx, did, None, None)
.unwrap().span.to_src(cx))
.unwrap().0.span.to_src(cx))
} else {
None
};
@ -479,7 +479,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
use rustc::middle::const_eval;
use rustc_front::print::pprust;
let expr = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
let (expr, ty) = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
panic!("expected lookup_const_by_id to succeed for {:?}", did);
});
debug!("converting constant expr {:?} to snippet", expr);
@ -487,7 +487,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
debug!("got snippet {}", sn);
clean::Constant {
type_: tcx.lookup_item_type(did).ty.clean(cx),
type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.lookup_item_type(did).ty.clean(cx)),
expr: sn
}
}

View File

@ -16,6 +16,7 @@
#[macro_use] extern crate rustc;
extern crate rustc_front;
extern crate rustc_plugin;
extern crate rustc_const_eval;
extern crate syntax;
use rustc::mir::transform::{self, MirPass};
@ -23,6 +24,7 @@ use rustc::mir::repr::{Mir, Literal};
use rustc::mir::visit::MutVisitor;
use rustc::middle::ty;
use rustc::middle::const_eval::ConstVal;
use rustc_const_eval::ConstInt;
use rustc_plugin::Registry;
use syntax::ast::NodeId;
@ -40,8 +42,10 @@ struct Visitor;
impl<'tcx> MutVisitor<'tcx> for Visitor {
fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
if let Literal::Value { value: ConstVal::Int(ref mut i @ 11) } = *literal {
*i = 42;
if let Literal::Value { ref mut value } = *literal {
if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
*i = 42;
}
}
}
}

View File

@ -25,9 +25,9 @@ fn main() {
//~^ WARN attempted to add with overflow
//~^^ WARN attempted to add with overflow
let c = 200u8 * 4;
//~^ WARN attempted to mul with overflow
//~^ WARN attempted to multiply with overflow
let d = 42u8 - (42u8 + 1);
//~^ WARN attempted to sub with overflow
//~^ WARN attempted to subtract with overflow
let _e = BLA;
black_box(a);
black_box(b);

View File

@ -21,10 +21,11 @@ const NEG_128: i8 = -128;
const NEG_NEG_128: i8 = -NEG_128;
//~^ ERROR constant evaluation error: attempted to negate with overflow
//~| ERROR attempted to negate with overflow
//~| ERROR attempted to negate with overflow
fn main() {
match -128i8 {
NEG_NEG_128 => println!("A"),
NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
_ => println!("B"),
}
}

View File

@ -36,4 +36,3 @@ fn main() {
fn foo<T:fmt::Debug>(x: T) {
println!("{:?}", x);
}

View File

@ -21,8 +21,9 @@ use std::{u8, u16, u32, u64, usize};
const A_I8_T
: [u32; (i8::MAX as i8 + 1u8) as usize]
//~^ ERROR mismatched types
//~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
//~^ ERROR mismatched types:
//~| expected `i8`,
//~| found `u8` [E0250]
= [0; (i8::MAX as usize) + 1];
fn main() {

View File

@ -23,84 +23,84 @@ const VALS_I8: (i8, i8, i8, i8) =
(-i8::MIN,
//~^ ERROR attempted to negate with overflow
i8::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
i8::MAX + 1,
//~^ ERROR attempted to add with overflow
i8::MIN * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
const VALS_I16: (i16, i16, i16, i16) =
(-i16::MIN,
//~^ ERROR attempted to negate with overflow
i16::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
i16::MAX + 1,
//~^ ERROR attempted to add with overflow
i16::MIN * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
const VALS_I32: (i32, i32, i32, i32) =
(-i32::MIN,
//~^ ERROR attempted to negate with overflow
i32::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
i32::MAX + 1,
//~^ ERROR attempted to add with overflow
i32::MIN * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
const VALS_I64: (i64, i64, i64, i64) =
(-i64::MIN,
//~^ ERROR attempted to negate with overflow
i64::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
i64::MAX + 1,
//~^ ERROR attempted to add with overflow
i64::MAX * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
const VALS_U8: (u8, u8, u8, u8) =
(-(u8::MIN as i8) as u8,
u8::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
u8::MAX + 1,
//~^ ERROR attempted to add with overflow
u8::MAX * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
const VALS_U16: (u16, u16, u16, u16) =
(-(u16::MIN as i16) as u16,
u16::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
u16::MAX + 1,
//~^ ERROR attempted to add with overflow
u16::MAX * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
const VALS_U32: (u32, u32, u32, u32) =
(-(u32::MIN as i32) as u32,
u32::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
u32::MAX + 1,
//~^ ERROR attempted to add with overflow
u32::MAX * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
const VALS_U64: (u64, u64, u64, u64) =
(-(u64::MIN as i64) as u64,
u64::MIN - 1,
//~^ ERROR attempted to sub with overflow
//~^ ERROR attempted to subtract with overflow
u64::MAX + 1,
//~^ ERROR attempted to add with overflow
u64::MAX * 2,
//~^ ERROR attempted to mul with overflow
//~^ ERROR attempted to multiply with overflow
);
fn main() {

View File

@ -8,32 +8,30 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
const X: usize = 42 && 39; //~ ERROR: can't do this op on unsigned integrals
const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
const X1: usize = 42 || 39; //~ ERROR: can't do this op on unsigned integrals
const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
// FIXME: the error should be `on signed integrals`
const X2: usize = -42 || -39; //~ ERROR: can't do this op on unsigned integrals
const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
// FIXME: the error should be `on signed integrals`
const X3: usize = -42 && -39; //~ ERROR: can't do this op on unsigned integrals
const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
const Y: usize = 42.0 == 42.0;
const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
const Y1: usize = 42.0 >= 42.0;
const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
const Y2: usize = 42.0 <= 42.0;
const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
const Y3: usize = 42.0 > 42.0;
const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
const Y4: usize = 42.0 < 42.0;
const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
const Y5: usize = 42.0 != 42.0;
const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
fn main() {
let _ = ARR;

View File

@ -15,7 +15,7 @@
const ONE: usize = 1;
const TWO: usize = 2;
const LEN: usize = ONE - TWO;
//~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
fn main() {
let a: [i8; LEN] = unimplemented!();

View File

@ -16,5 +16,5 @@ const TWO: usize = 2;
fn main() {
let a: [i8; ONE - TWO] = unimplemented!();
//~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
}

View File

@ -11,7 +11,7 @@
// Test spans of errors
const TUP: (usize,) = 5 << 64;
//~^ ERROR: attempted left shift with overflow [E0250]
//~^ ERROR: attempted to shift left with overflow [E0250]
const ARR: [i32; TUP.0] = [];
fn main() {

View File

@ -24,7 +24,7 @@ fn f_i8() {
enum A {
Ok = i8::MAX - 1,
Ok2,
OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
}
}
@ -33,7 +33,7 @@ fn f_u8() {
enum A {
Ok = u8::MAX - 1,
Ok2,
OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
}
}

View File

@ -22,7 +22,7 @@ fn f_i8() {
enum A {
Ok = i8::MAX - 1,
Ok2,
OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
}
let x = A::Ok;
@ -33,7 +33,7 @@ fn f_u8() {
enum A {
Ok = u8::MAX - 1,
Ok2,
OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
}
let x = A::Ok;

View File

@ -9,46 +9,32 @@
// except according to those terms.
#[repr(u8)] //~ NOTE discriminant type specified here
#[repr(u8)]
enum Eu8 {
Au8 = 23,
Bu8 = 223,
Cu8 = -23, //~ ERROR discriminant value outside specified type
Cu8 = -23, //~ ERROR unary negation of unsigned integer
}
#[repr(i8)] //~ NOTE discriminant type specified here
enum Ei8 {
Ai8 = 23,
Bi8 = -23,
Ci8 = 223, //~ ERROR discriminant value outside specified type
}
#[repr(u16)] //~ NOTE discriminant type specified here
#[repr(u16)]
enum Eu16 {
Au16 = 23,
Bu16 = 55555,
Cu16 = -22333, //~ ERROR discriminant value outside specified type
Cu16 = -22333, //~ ERROR unary negation of unsigned integer
}
#[repr(i16)] //~ NOTE discriminant type specified here
enum Ei16 {
Ai16 = 23,
Bi16 = -22333,
Ci16 = 55555, //~ ERROR discriminant value outside specified type
}
#[repr(u32)] //~ NOTE discriminant type specified here
#[repr(u32)]
enum Eu32 {
Au32 = 23,
Bu32 = 3_000_000_000,
Cu32 = -2_000_000_000, //~ ERROR discriminant value outside specified type
Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
}
#[repr(i32)] //~ NOTE discriminant type specified here
enum Ei32 {
Ai32 = 23,
Bi32 = -2_000_000_000,
Ci32 = 3_000_000_000, //~ ERROR discriminant value outside specified type
#[repr(u64)]
enum Eu64 {
Au32 = 23,
Bu32 = 3_000_000_000,
Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
}
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a

View File

@ -0,0 +1,47 @@
// Copyright 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.
#![deny(overflowing_literals)]
#![allow(dead_code)]
#[repr(i8)]
enum Ei8 {
Ai8 = 23,
Bi8 = -23,
Ci8 = 223, //~ ERROR literal out of range for i8
}
#[repr(i16)]
enum Ei16 {
Ai16 = 23,
Bi16 = -22333,
Ci16 = 55555, //~ ERROR literal out of range for i16
}
#[repr(i32)]
enum Ei32 {
Ai32 = 23,
Bi32 = -2_000_000_000,
Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32
}
#[repr(i64)]
enum Ei64 {
Ai64 = 23,
Bi64 = -9223372036854775808,
Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64
}
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
// little counterintuitive, but since the discriminant can store all the bits, and extracting it
// with a cast requires specifying the signedness, there is no loss of information in those cases.
// This also applies to isize and usize on 64-bit targets.
pub fn main() { }

View File

@ -10,7 +10,8 @@
enum test {
div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
rem_zero = 1%0 //~ERROR constant evaluation error: attempted remainder with a divisor of zero
rem_zero = 1%0,
//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
}
fn main() {}

View File

@ -21,22 +21,7 @@ const _MAX: usize = -1;
//~| HELP use a cast or the `!` operator
fn main() {
let a = -1;
//~^ ERROR unary negation of unsigned integer
//~| HELP use a cast or the `!` operator
let _b : u8 = a; // for infering variable a to u8.
-a;
//~^ ERROR unary negation of unsigned integer
//~| HELP use a cast or the `!` operator
let _d = -1u8;
//~^ ERROR unary negation of unsigned integer
//~| HELP use a cast or the `!` operator
for _ in -10..10u8 {}
//~^ ERROR unary negation of unsigned integer
//~| HELP use a cast or the `!` operator
let x = 5u8;
let _y = -x; //~ ERROR unary negation of unsigned integer
-S; // should not trigger the gate; issue 26840
}

View File

@ -0,0 +1,31 @@
// 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.
// Test that negating unsigned integers doesn't compile
struct S;
impl std::ops::Neg for S {
type Output = u32;
fn neg(self) -> u32 { 0 }
}
fn main() {
let a = -1;
//~^ ERROR unary negation of unsigned integer
let _b : u8 = a; // for infering variable a to u8.
let _d = -1u8;
//~^ ERROR unary negation of unsigned integer
for _ in -10..10u8 {}
//~^ ERROR unary negation of unsigned integer
-S; // should not trigger the gate; issue 26840
}

View File

@ -12,12 +12,12 @@ const N: isize = 1;
enum Foo {
A = 1,
B = 1, //~ ERROR discriminant value `1` already exists
B = 1, //~ ERROR discriminant value `1isize` already exists
//~^^ NOTE conflicting
C = 0,
D, //~ ERROR discriminant value `1` already exists
D, //~ ERROR discriminant value `1isize` already exists
//~^^^^^ NOTE conflicting
E = N, //~ ERROR discriminant value `1` already exists
E = N, //~ ERROR discriminant value `1isize` already exists
//~^^^^^^^ NOTE conflicting
}

View File

@ -35,23 +35,23 @@ fn main() {
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
//~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow
//~^ ERROR attempted to calculate the remainder with overflow
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow
//~^ ERROR attempted to calculate the remainder with overflow
assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow
//~^ ERROR attempted to calculate the remainder with overflow
assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow
//~^ ERROR attempted to calculate the remainder with overflow
assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
//~^ ERROR attempted remainder with overflow
//~^ ERROR attempted to calculate the remainder with overflow
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero
//~^ ERROR attempted to calculate the remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero
//~^ ERROR attempted to calculate the remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero
//~^ ERROR attempted to calculate the remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero
//~^ ERROR attempted to calculate the remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
//~^ ERROR attempted remainder with a divisor of zero
//~^ ERROR attempted to calculate the remainder with a divisor of zero
}

View File

@ -10,13 +10,13 @@
enum Foo {
A = 1i64,
//~^ ERROR mismatched types
//~| expected `isize`
//~| found `i64`
//~^ ERROR mismatched types:
//~| expected `isize`,
//~| found `i64` [E0080]
B = 2u8
//~^ ERROR mismatched types
//~| expected `isize`
//~| found `u8`
//~^ ERROR mismatched types:
//~| expected `isize`,
//~| found `u8` [E0080]
}
fn main() {}

View File

@ -24,11 +24,6 @@ fn bar() -> i8 {
return 123;
}
fn baz() -> bool {
128 > bar() //~ ERROR comparison is useless due to type limits
//~^ WARNING literal out of range for i8
}
fn bleh() {
let u = 42u8;
let _ = u > 255; //~ ERROR comparison is useless due to type limits
@ -40,11 +35,3 @@ fn bleh() {
let _ = u >= 0; //~ ERROR comparison is useless due to type limits
let _ = 0 <= u; //~ ERROR comparison is useless due to type limits
}
fn qux() {
let mut i = 1i8;
while 200 != i { //~ ERROR comparison is useless due to type limits
//~^ WARNING literal out of range for i8
i += 1;
}
}

View File

@ -0,0 +1,24 @@
// Copyright 2012 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.
#![allow(dead_code)]
// compile-flags: -D unused-comparisons
fn main() { }
fn bar() -> i8 {
return 123;
}
fn baz() -> bool {
128 > bar() //~ ERROR comparison is useless due to type limits
//~| WARN literal out of range for i8
}

View File

@ -0,0 +1,22 @@
// Copyright 2012 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.
#![allow(dead_code)]
// compile-flags: -D unused-comparisons
fn main() { }
fn qux() {
let mut i = 1i8;
while 200 != i { //~ ERROR comparison is useless due to type limits
//~| WARN literal out of range for i8
i += 1;
}
}

View File

@ -25,7 +25,6 @@ fn main() {
let x2: i8 = -128; // should be OK
let x1: i8 = 128; //~ error: literal out of range for i8
let x2: i8 = --128; //~ error: literal out of range for i8
let x3: i8 = -129; //~ error: literal out of range for i8
let x3: i8 = -(129); //~ error: literal out of range for i8
@ -54,9 +53,4 @@ fn main() {
let x = 18446744073709551615_i64; //~ error: literal out of range for i64
let x: i64 = -9223372036854775809; //~ error: literal out of range for i64
let x = -9223372036854775809_i64; //~ error: literal out of range for i64
let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
let x = 3.40282348e+38_f32; //~ error: literal out of range for f32
let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
let x = 1.7976931348623159e+308_f64; //~ error: literal out of range for f64
}

View File

@ -0,0 +1,22 @@
// Copyright 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.
//
#![deny(overflowing_literals)]
#[allow(unused_variables)]
fn main() {
let x2: i8 = --128; //~ error: literal out of range for i8
let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
let x = 3.40282348e+38_f32; //~ error: literal out of range for f32
let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
let x = 1.7976931348623159e+308_f64; //~ error: literal out of range for f64
}

View File

@ -43,13 +43,17 @@ fn main() {
let f = [0; -4_isize];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `isize`
//~| ERROR expected positive integer for repeat count, found negative integer [E0306]
//~| found `isize` [E0308]
//~| ERROR mismatched types:
//~| expected `usize`,
//~| found `isize` [E0307]
let f = [0_usize; -1_isize];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `isize`
//~| ERROR expected positive integer for repeat count, found negative integer [E0306]
//~| found `isize` [E0308]
//~| ERROR mismatched types
//~| expected `usize`
//~| found `isize` [E0307]
struct G {
g: (),
}

View File

@ -10,7 +10,7 @@
// A very basic test of const fn functionality.
#![feature(const_fn)]
#![feature(const_fn, const_indexing)]
const fn add(x: u32, y: u32) -> u32 {
x + y
@ -24,6 +24,14 @@ const unsafe fn div(x: u32, y: u32) -> u32 {
x / y
}
const fn generic<T>(t: T) -> T {
t
}
const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
t[0]
}
const SUM: u32 = add(44, 22);
const DIFF: u32 = sub(44, 22);
const DIV: u32 = unsafe{div(44, 22)};
@ -36,4 +44,6 @@ fn main() {
assert_eq!(DIV, 2);
let _: [&'static str; sub(100, 99) as usize] = ["hi"];
let _: [&'static str; generic(1)] = ["hi"];
let _: [&'static str; generic_arr([1])] = ["hi"];
}

View File

@ -0,0 +1,42 @@
// 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(stmt_expr_attributes)]
#[deny(const_err)]
fn main() {
#[cfg(target_pointer_width = "32")]
const I: isize = -2147483648isize;
#[cfg(target_pointer_width = "64")]
const I: isize = -9223372036854775808isize;
assert_eq!(::std::i32::MIN as u64, 0xffffffff80000000);
assert_eq!(-2147483648isize as u64, 0xffffffff80000000);
assert_eq!(::std::i64::MIN as u64, 0x8000000000000000);
#[cfg(target_pointer_width = "64")]
assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000);
#[cfg(target_pointer_width = "32")]
assert_eq!(-9223372036854775808isize as u64, 0);
const J: usize = ::std::i32::MAX as usize;
const K: usize = -1i32 as u32 as usize;
const L: usize = ::std::i32::MIN as usize;
const M: usize = ::std::i64::MIN as usize;
match 5 {
J => {},
K => {},
L => {},
M => {},
_ => {}
}
match 5 {
I => {},
_ => {}
}
}

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(stmt_expr_attributes)]
use std::mem::size_of;
@ -46,11 +47,6 @@ enum Ei64 {
Bi64 = 0x8000_0000
}
enum Eu64 {
Au64 = 0,
Bu64 = 0x8000_0000_0000_0000
}
pub fn main() {
assert_eq!(size_of::<Ei8>(), 1);
assert_eq!(size_of::<Eu8>(), 1);
@ -58,6 +54,8 @@ pub fn main() {
assert_eq!(size_of::<Eu16>(), 2);
assert_eq!(size_of::<Ei32>(), 4);
assert_eq!(size_of::<Eu32>(), 4);
#[cfg(target_pointer_width = "64")]
assert_eq!(size_of::<Ei64>(), 8);
assert_eq!(size_of::<Eu64>(), 8);
#[cfg(target_pointer_width = "32")]
assert_eq!(size_of::<Ei64>(), 4);
}

View File

@ -0,0 +1,25 @@
// Copyright 2012 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::fmt;
use std::{i8, i16, i32, i64, isize};
use std::{u8, u16, u32, u64, usize};
const A_I8_T
: [u32; (i8::MAX as i8 - 1i8) as usize]
= [0; (i8::MAX as usize) - 1];
fn main() {
foo(&A_I8_T[..]);
}
fn foo<T:fmt::Debug>(x: T) {
println!("{:?}", x);
}