typestrong constant integers

This commit is contained in:
Oliver Schneider 2015-12-16 18:44:15 +01:00
parent 3ac4076ac0
commit 7bde56e149
65 changed files with 1617 additions and 920 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

@ -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

@ -23,10 +23,9 @@ use middle::subst::Subst;
use middle::def_id::DefId;
use middle::pat_util::def_to_path;
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::util::IntTypeExt;
use middle::astconv_util::ast_ty_to_prim_ty;
use util::num::ToPrimitive;
use util::nodemap::NodeMap;
use session::Session;
use graphviz::IntoCow;
use syntax::ast;
@ -43,10 +42,20 @@ use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
use std::hash;
use std::mem::transmute;
use std::{i8, i16, i32, i64, u8, u16, u32, u64};
use std::rc::Rc;
fn lookup_variant_by_id<'a>(tcx: &'a TyCtxt,
use rustc_const_eval::*;
macro_rules! math {
($e:expr, $op:expr) => {
match $op {
Ok(val) => val,
Err(e) => signal!($e, Math(e)),
}
}
}
fn lookup_variant_by_id<'a>(tcx: &'a ty::TyCtxt,
enum_def: DefId,
variant_def: DefId)
-> Option<&'a Expr> {
@ -248,8 +257,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId)
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ConstVal {
Float(f64),
Int(i64),
Uint(u64),
Integral(ConstInt),
Str(InternedString),
ByteStr(Rc<Vec<u8>>),
Bool(bool),
@ -258,14 +266,14 @@ pub enum ConstVal {
Function(DefId),
Array(ast::NodeId, u64),
Repeat(ast::NodeId, u64),
Char(char),
}
impl hash::Hash for ConstVal {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match *self {
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
Int(a) => a.hash(state),
Uint(a) => a.hash(state),
Integral(a) => a.hash(state),
Str(ref a) => a.hash(state),
ByteStr(ref a) => a.hash(state),
Bool(a) => a.hash(state),
@ -274,6 +282,7 @@ impl hash::Hash for ConstVal {
Function(a) => a.hash(state),
Array(a, n) => { a.hash(state); n.hash(state) },
Repeat(a, n) => { a.hash(state); n.hash(state) },
Char(c) => c.hash(state),
}
}
}
@ -286,8 +295,7 @@ impl PartialEq for ConstVal {
fn eq(&self, other: &ConstVal) -> bool {
match (self, other) {
(&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
(&Int(a), &Int(b)) => a == b,
(&Uint(a), &Uint(b)) => a == b,
(&Integral(a), &Integral(b)) => a == b,
(&Str(ref a), &Str(ref b)) => a == b,
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
(&Bool(a), &Bool(b)) => a == b,
@ -296,6 +304,7 @@ impl PartialEq for ConstVal {
(&Function(a), &Function(b)) => a == b,
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
(&Char(a), &Char(b)) => a == b,
_ => false,
}
}
@ -307,9 +316,7 @@ impl ConstVal {
pub fn description(&self) -> &'static str {
match *self {
Float(_) => "float",
Int(i) if i < 0 => "negative integer",
Int(_) => "positive integer",
Uint(_) => "unsigned integer",
Integral(i) => i.description(),
Str(_) => "string literal",
ByteStr(_) => "byte string literal",
Bool(_) => "boolean",
@ -318,6 +325,7 @@ impl ConstVal {
Function(_) => "function definition",
Array(..) => "array",
Repeat(..) => "repeat",
Char(..) => "char",
}
}
}
@ -402,7 +410,6 @@ pub enum ErrKind {
CannotCast,
CannotCastTo(&'static str),
InvalidOpForInts(hir::BinOp_),
InvalidOpForUInts(hir::BinOp_),
InvalidOpForBools(hir::BinOp_),
InvalidOpForFloats(hir::BinOp_),
InvalidOpForIntUint(hir::BinOp_),
@ -442,6 +449,13 @@ pub enum ErrKind {
MiscCatchAll,
IndexOpFeatureGated,
Math(ConstMathErr),
}
impl From<ConstMathErr> for ErrKind {
fn from(err: ConstMathErr) -> ErrKind {
Math(err)
}
}
impl ConstEvalErr {
@ -451,8 +465,7 @@ impl ConstEvalErr {
match self.kind {
CannotCast => "can't cast this type".into_cow(),
CannotCastTo(s) => format!("can't cast this type to {}", s).into_cow(),
InvalidOpForInts(_) => "can't do this op on signed integrals".into_cow(),
InvalidOpForUInts(_) => "can't do this op on unsigned integrals".into_cow(),
InvalidOpForInts(_) => "can't do this op on integrals".into_cow(),
InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
InvalidOpForFloats(_) => "can't do this op on floats".into_cow(),
InvalidOpForIntUint(..) => "can't do this op on an isize and usize".into_cow(),
@ -492,6 +505,7 @@ impl ConstEvalErr {
MiscBinaryOp => "bad operands for binary".into_cow(),
MiscCatchAll => "unsupported constant expr".into_cow(),
IndexOpFeatureGated => "the index operation on const values is unstable".into_cow(),
Math(ref err) => err.description().into_cow(),
}
}
}
@ -536,276 +550,12 @@ impl<'tcx> EvalHint<'tcx> {
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IntTy { I8, I16, I32, I64 }
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum UintTy { U8, U16, U32, U64 }
impl IntTy {
pub fn from(tcx: &TyCtxt, t: ast::IntTy) -> IntTy {
let t = if let ast::IntTy::Is = t {
tcx.sess.target.int_type
} else {
t
};
match t {
ast::IntTy::Is => unreachable!(),
ast::IntTy::I8 => IntTy::I8,
ast::IntTy::I16 => IntTy::I16,
ast::IntTy::I32 => IntTy::I32,
ast::IntTy::I64 => IntTy::I64,
}
}
}
impl UintTy {
pub fn from(tcx: &TyCtxt, t: ast::UintTy) -> UintTy {
let t = if let ast::UintTy::Us = t {
tcx.sess.target.uint_type
} else {
t
};
match t {
ast::UintTy::Us => unreachable!(),
ast::UintTy::U8 => UintTy::U8,
ast::UintTy::U16 => UintTy::U16,
ast::UintTy::U32 => UintTy::U32,
ast::UintTy::U64 => UintTy::U64,
}
}
}
macro_rules! signal {
($e:expr, $exn:expr) => {
return Err(ConstEvalErr { span: $e.span, kind: $exn })
}
}
// The const_{int,uint}_checked_{neg,add,sub,mul,div,shl,shr} family
// of functions catch and signal overflow errors during constant
// evaluation.
//
// They all take the operator's arguments (`a` and `b` if binary), the
// overall expression (`e`) and, if available, whole expression's
// concrete type (`opt_ety`).
//
// If the whole expression's concrete type is None, then this is a
// constant evaluation happening before type check (e.g. in the check
// to confirm that a pattern range's left-side is not greater than its
// right-side). We do not do arithmetic modulo the type's bitwidth in
// such a case; we just do 64-bit arithmetic and assume that later
// passes will do it again with the type information, and thus do the
// overflow checks then.
pub fn const_int_checked_neg<'a>(
a: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
let (min,max) = match opt_ety {
// (-i8::MIN is itself not an i8, etc, but this is an easy way
// to allow literals to pass the check. Of course that does
// not work for i64::MIN.)
Some(IntTy::I8) => (-(i8::MAX as i64), -(i8::MIN as i64)),
Some(IntTy::I16) => (-(i16::MAX as i64), -(i16::MIN as i64)),
Some(IntTy::I32) => (-(i32::MAX as i64), -(i32::MIN as i64)),
None | Some(IntTy::I64) => (-i64::MAX, -(i64::MIN+1)),
};
let oflo = a < min || a > max;
if oflo {
signal!(e, NegateWithOverflow(a));
} else {
Ok(Int(-a))
}
}
pub fn const_uint_checked_neg<'a>(
a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
// This always succeeds, and by definition, returns `(!a)+1`.
Ok(Uint((!a).wrapping_add(1)))
}
fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> ConstVal {
let mask = match opt_ety {
Some(UintTy::U8) => u8::MAX as u64,
Some(UintTy::U16) => u16::MAX as u64,
Some(UintTy::U32) => u32::MAX as u64,
None | Some(UintTy::U64) => u64::MAX,
};
Uint(!a & mask)
}
macro_rules! overflow_checking_body {
($a:ident, $b:ident, $ety:ident, $overflowing_op:ident,
lhs: $to_8_lhs:ident $to_16_lhs:ident $to_32_lhs:ident,
rhs: $to_8_rhs:ident $to_16_rhs:ident $to_32_rhs:ident $to_64_rhs:ident,
$EnumTy:ident $T8: ident $T16: ident $T32: ident $T64: ident,
$result_type: ident) => { {
let (a,b,opt_ety) = ($a,$b,$ety);
match opt_ety {
Some($EnumTy::$T8) => match (a.$to_8_lhs(), b.$to_8_rhs()) {
(Some(a), Some(b)) => {
let (a, oflo) = a.$overflowing_op(b);
(a as $result_type, oflo)
}
(None, _) | (_, None) => (0, true)
},
Some($EnumTy::$T16) => match (a.$to_16_lhs(), b.$to_16_rhs()) {
(Some(a), Some(b)) => {
let (a, oflo) = a.$overflowing_op(b);
(a as $result_type, oflo)
}
(None, _) | (_, None) => (0, true)
},
Some($EnumTy::$T32) => match (a.$to_32_lhs(), b.$to_32_rhs()) {
(Some(a), Some(b)) => {
let (a, oflo) = a.$overflowing_op(b);
(a as $result_type, oflo)
}
(None, _) | (_, None) => (0, true)
},
None | Some($EnumTy::$T64) => match b.$to_64_rhs() {
Some(b) => a.$overflowing_op(b),
None => (0, true),
}
}
} }
}
macro_rules! int_arith_body {
($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
overflow_checking_body!(
$a, $b, $ety, $overflowing_op,
lhs: to_i8 to_i16 to_i32,
rhs: to_i8 to_i16 to_i32 to_i64, IntTy I8 I16 I32 I64, i64)
}
}
macro_rules! uint_arith_body {
($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
overflow_checking_body!(
$a, $b, $ety, $overflowing_op,
lhs: to_u8 to_u16 to_u32,
rhs: to_u8 to_u16 to_u32 to_u64, UintTy U8 U16 U32 U64, u64)
}
}
macro_rules! int_shift_body {
($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
overflow_checking_body!(
$a, $b, $ety, $overflowing_op,
lhs: to_i8 to_i16 to_i32,
rhs: to_u32 to_u32 to_u32 to_u32, IntTy I8 I16 I32 I64, i64)
}
}
macro_rules! uint_shift_body {
($a:ident, $b:ident, $ety:ident, $overflowing_op:ident) => {
overflow_checking_body!(
$a, $b, $ety, $overflowing_op,
lhs: to_u8 to_u16 to_u32,
rhs: to_u32 to_u32 to_u32 to_u32, UintTy U8 U16 U32 U64, u64)
}
}
macro_rules! pub_fn_checked_op {
{$fn_name:ident ($a:ident : $a_ty:ty, $b:ident : $b_ty:ty,.. $WhichTy:ident) {
$ret_oflo_body:ident $overflowing_op:ident
$const_ty:ident $signal_exn:expr
}} => {
pub fn $fn_name<'a>($a: $a_ty,
$b: $b_ty,
e: &'a Expr,
opt_ety: Option<$WhichTy>) -> EvalResult {
let (ret, oflo) = $ret_oflo_body!($a, $b, opt_ety, $overflowing_op);
if !oflo { Ok($const_ty(ret)) } else { signal!(e, $signal_exn) }
}
}
}
pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
int_arith_body overflowing_add Int AddiWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
int_arith_body overflowing_sub Int SubiWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
int_arith_body overflowing_mul Int MuliWithOverflow(a, b)
}}
pub fn const_int_checked_div<'a>(
a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
if b == 0 { signal!(e, DivideByZero); }
let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div);
if !oflo { Ok(Int(ret)) } else { signal!(e, DivideWithOverflow) }
}
pub fn const_int_checked_rem<'a>(
a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
if b == 0 { signal!(e, ModuloByZero); }
let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem);
if !oflo { Ok(Int(ret)) } else { signal!(e, ModuloWithOverflow) }
}
pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
int_shift_body overflowing_shl Int ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
int_shift_body overflowing_shl Int ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
int_shift_body overflowing_shr Int ShiftRightWithOverflow
}}
pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
int_shift_body overflowing_shr Int ShiftRightWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
uint_arith_body overflowing_add Uint AdduWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
uint_arith_body overflowing_sub Uint SubuWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
uint_arith_body overflowing_mul Uint MuluWithOverflow(a, b)
}}
pub fn const_uint_checked_div<'a>(
a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
if b == 0 { signal!(e, DivideByZero); }
let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div);
if !oflo { Ok(Uint(ret)) } else { signal!(e, DivideWithOverflow) }
}
pub fn const_uint_checked_rem<'a>(
a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
if b == 0 { signal!(e, ModuloByZero); }
let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem);
if !oflo { Ok(Uint(ret)) } else { signal!(e, ModuloWithOverflow) }
}
pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
}}
/// Evaluate a constant expression in a context where the expression isn't
/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
/// but a few places need to evaluate constants during type-checking, like
@ -833,34 +583,57 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
tcx.expr_ty_opt(e)
}
};
// If type of expression itself is int or uint, normalize in these
// bindings so that isize/usize is mapped to a type with an
// inherently known bitwidth.
let expr_int_type = ety.and_then(|ty| {
if let ty::TyInt(t) = ty.sty {
Some(IntTy::from(tcx, t)) } else { None }
});
let expr_uint_type = ety.and_then(|ty| {
if let ty::TyUint(t) = ty.sty {
Some(UintTy::from(tcx, t)) } else { None }
});
let result = match e.node {
hir::ExprUnary(hir::UnNeg, ref inner) => {
// unary neg literals already got their sign during creation
if let hir::ExprLit(ref lit) = inner.node {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
match (&lit.node, ety.map(|t| &t.sty)) {
(&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
return Ok(Integral(I8(::std::i8::MIN)))
},
(&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
return Ok(Integral(I16(::std::i16::MIN)))
},
(&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
return Ok(Integral(I32(::std::i32::MIN)))
},
(&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
return Ok(Integral(I64(::std::i64::MIN)))
},
(&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
(&LitKind::Int(n, Signed(IntTy::Is)), _) => {
match tcx.sess.target.int_type {
IntTy::I32 => if n == I32_OVERFLOW {
return Ok(Integral(Isize(Is32(::std::i32::MIN))));
},
IntTy::I64 => if n == I64_OVERFLOW {
return Ok(Integral(Isize(Is64(::std::i64::MIN))));
},
_ => unreachable!(),
}
},
_ => {},
}
}
match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
Float(f) => Float(-f),
Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
Uint(i) => {
try!(const_uint_checked_neg(i, e, expr_uint_type))
}
Integral(i) => Integral(math!(e, -i)),
const_val => signal!(e, NegateOn(const_val)),
}
}
hir::ExprUnary(hir::UnNot, ref inner) => {
match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
Int(i) => Int(!i),
Uint(i) => const_uint_not(i, expr_uint_type),
Integral(i) => Integral(math!(e, !i)),
Bool(b) => Bool(!b),
const_val => signal!(e, NotOn(const_val)),
}
@ -870,6 +643,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
hir::BiShl | hir::BiShr => ty_hint.checked_or(tcx.types.usize),
_ => ty_hint
};
// technically, if we don't have type hints, but integral eval
// gives us a type through a type-suffix, cast or const def type
// we need to re-eval the other value of the BinOp if it was
// not inferred
match (try!(eval_const_expr_partial(tcx, &a, ty_hint, fn_args)),
try!(eval_const_expr_partial(tcx, &b, b_ty, fn_args))) {
(Float(a), Float(b)) => {
@ -888,63 +665,28 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
_ => signal!(e, InvalidOpForFloats(op.node)),
}
}
(Int(a), Int(b)) => {
(Integral(a), Integral(b)) => {
use std::cmp::Ordering::*;
match op.node {
hir::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
hir::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
hir::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
hir::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
hir::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
hir::BiBitAnd => Int(a & b),
hir::BiBitOr => Int(a | b),
hir::BiBitXor => Int(a ^ b),
hir::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
hir::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
hir::BiEq => Bool(a == b),
hir::BiLt => Bool(a < b),
hir::BiLe => Bool(a <= b),
hir::BiNe => Bool(a != b),
hir::BiGe => Bool(a >= b),
hir::BiGt => Bool(a > b),
hir::BiAdd => Integral(math!(e, a + b)),
hir::BiSub => Integral(math!(e, a - b)),
hir::BiMul => Integral(math!(e, a * b)),
hir::BiDiv => Integral(math!(e, a / b)),
hir::BiRem => Integral(math!(e, a % b)),
hir::BiBitAnd => Integral(math!(e, a & b)),
hir::BiBitOr => Integral(math!(e, a | b)),
hir::BiBitXor => Integral(math!(e, a ^ b)),
hir::BiShl => Integral(math!(e, a << b)),
hir::BiShr => Integral(math!(e, a >> b)),
hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
_ => signal!(e, InvalidOpForInts(op.node)),
}
}
(Uint(a), Uint(b)) => {
match op.node {
hir::BiAdd => try!(const_uint_checked_add(a,b,e,expr_uint_type)),
hir::BiSub => try!(const_uint_checked_sub(a,b,e,expr_uint_type)),
hir::BiMul => try!(const_uint_checked_mul(a,b,e,expr_uint_type)),
hir::BiDiv => try!(const_uint_checked_div(a,b,e,expr_uint_type)),
hir::BiRem => try!(const_uint_checked_rem(a,b,e,expr_uint_type)),
hir::BiBitAnd => Uint(a & b),
hir::BiBitOr => Uint(a | b),
hir::BiBitXor => Uint(a ^ b),
hir::BiShl => try!(const_uint_checked_shl(a,b,e,expr_uint_type)),
hir::BiShr => try!(const_uint_checked_shr(a,b,e,expr_uint_type)),
hir::BiEq => Bool(a == b),
hir::BiLt => Bool(a < b),
hir::BiLe => Bool(a <= b),
hir::BiNe => Bool(a != b),
hir::BiGe => Bool(a >= b),
hir::BiGt => Bool(a > b),
_ => signal!(e, InvalidOpForUInts(op.node)),
}
}
// shifts can have any integral type as their rhs
(Int(a), Uint(b)) => {
match op.node {
hir::BiShl => try!(const_int_checked_shl_via_uint(a,b,e,expr_int_type)),
hir::BiShr => try!(const_int_checked_shr_via_uint(a,b,e,expr_int_type)),
_ => signal!(e, InvalidOpForIntUint(op.node)),
}
}
(Uint(a), Int(b)) => {
match op.node {
hir::BiShl => try!(const_uint_checked_shl_via_int(a,b,e,expr_uint_type)),
hir::BiShr => try!(const_uint_checked_shr_via_int(a,b,e,expr_uint_type)),
_ => signal!(e, InvalidOpForUintInt(op.node)),
}
}
(Bool(a), Bool(b)) => {
Bool(match op.node {
hir::BiAnd => a && b,
@ -962,7 +704,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
}
}
hir::ExprCast(ref base, ref target_ty) => {
let ety = ety.or_else(|| ast_ty_to_prim_ty(tcx, &target_ty))
let ety = ast_ty_to_prim_ty(tcx, &target_ty).or_else(|| ety)
.unwrap_or_else(|| {
tcx.sess.span_fatal(target_ty.span,
"target type not found for const cast")
@ -971,9 +713,6 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
let base_hint = if let ExprTypeChecked = ty_hint {
ExprTypeChecked
} else {
// FIXME (#23833): the type-hint can cause problems,
// e.g. `(i8::MAX + 1_i8) as u32` feeds in `u32` as result
// type to the sum, and thus no overflow is signaled.
match tcx.expr_ty_opt(&base) {
Some(t) => UncheckedExprHint(t),
None => ty_hint
@ -1103,10 +842,28 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
let mut call_args = NodeMap();
for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
let arg_hint = match ty_hint {
ExprTypeChecked => ExprTypeChecked,
UncheckedExprNoHint | UncheckedExprHint(_) => {
if let Some(hint) = tcx.ast_ty_to_ty_cache.borrow().get(&arg.ty.id) {
let mut new_ty_hint = UncheckedExprHint(hint);
for t in hint.walk() {
if let ty::TypeVariants::TyParam(_) = t.sty {
// found a generic argument, but we are in typeck
new_ty_hint = UncheckedExprNoHint;
break;
}
}
new_ty_hint
} else {
UncheckedExprNoHint
}
},
};
let arg_val = try!(eval_const_expr_partial(
tcx,
arg_expr,
sub_ty_hint,
arg_hint,
fn_args
));
debug!("const call arg: {:?}", arg);
@ -1116,7 +873,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
debug!("const call({:?})", call_args);
try!(eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args)))
},
hir::ExprLit(ref lit) => lit_to_const(tcx.sess, e.span, &lit, ety),
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety, lit.span) {
Ok(val) => val,
Err(err) => signal!(e, Math(err)),
},
hir::ExprBlock(ref block) => {
match block.expr {
Some(ref expr) => try!(eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)),
@ -1134,14 +894,15 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
let arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
let idx_hint = ty_hint.checked_or(tcx.types.usize);
let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
Int(i) if i >= 0 => i as u64,
Int(_) => signal!(idx, IndexNegative),
Uint(i) => i,
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
Integral(_) => unreachable!(),
_ => signal!(idx, IndexNotInt),
};
assert_eq!(idx as usize as u64, idx);
match arr {
Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
Array(v, _) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
assert_eq!(n as usize as u64, n);
try!(eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args))
} else {
unreachable!()
@ -1155,13 +916,13 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
fn_args,
)),
ByteStr(ref data) if idx as usize >= data.len()
=> signal!(e, IndexOutOfBounds),
ByteStr(data) => Uint(data[idx as usize] as u64),
ByteStr(ref data) if idx >= data.len() as u64 => signal!(e, IndexOutOfBounds),
ByteStr(data) => {
Integral(U8(data[idx as usize]))
},
Str(ref s) if idx as usize >= s.len()
=> signal!(e, IndexOutOfBounds),
Str(_) => unimplemented!(), // there's no const_char type
Str(ref s) if idx as usize >= s.len() => signal!(e, IndexOutOfBounds),
Str(_) => unimplemented!(), // FIXME: return a const char
_ => signal!(e, IndexedNonVec),
}
}
@ -1171,9 +932,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
Repeat(
e.id,
match try!(eval_const_expr_partial(tcx, &n, len_hint, fn_args)) {
Int(i) if i >= 0 => i as u64,
Int(_) => signal!(e, RepeatCountNotNatural),
Uint(i) => i,
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
Integral(_) => signal!(e, RepeatCountNotNatural),
_ => signal!(e, RepeatCountNotInt),
},
)
@ -1184,7 +944,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
if let Tuple(tup_id) = c {
if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
if index.node < fields.len() {
return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args)
return eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args)
} else {
signal!(e, TupleIndexOutOfBounds);
}
@ -1205,7 +965,7 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
// if the idents are compared run-pass/issue-19244 fails
if let Some(f) = fields.iter().find(|f| f.name.node
== field_name.node) {
return eval_const_expr_partial(tcx, &f.expr, base_hint, fn_args)
return eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args)
} else {
signal!(e, MissingStructField);
}
@ -1289,100 +1049,155 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a TyCtxt<'tcx>,
}
}
fn cast_const<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstVal, ty: Ty) -> CastResult {
macro_rules! convert_val {
($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
match val {
Bool(b) => Ok($const_type(b as u64 as $intermediate_ty as $target_ty)),
Uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
Int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
Float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
_ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
}
}
}
// Issue #23890: If isize/usize, then dispatch to appropriate target representation type
match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
(&ty::TyInt(ast::IntTy::Is), ast::IntTy::I32, _) => return convert_val!(i32, Int, i64),
(&ty::TyInt(ast::IntTy::Is), ast::IntTy::I64, _) => return convert_val!(i64, Int, i64),
(&ty::TyInt(ast::IntTy::Is), _, _) => panic!("unexpected target.int_type"),
(&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U32) => return convert_val!(u32, Uint, u64),
(&ty::TyUint(ast::UintTy::Us), _, ast::UintTy::U64) => return convert_val!(u64, Uint, u64),
(&ty::TyUint(ast::UintTy::Us), _, _) => panic!("unexpected target.uint_type"),
_ => {}
}
fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
let v = val.to_u64_unchecked();
match ty.sty {
ty::TyInt(ast::IntTy::Is) => unreachable!(),
ty::TyUint(ast::UintTy::Us) => unreachable!(),
ty::TyInt(ast::IntTy::I8) => convert_val!(i8, Int, i64),
ty::TyInt(ast::IntTy::I16) => convert_val!(i16, Int, i64),
ty::TyInt(ast::IntTy::I32) => convert_val!(i32, Int, i64),
ty::TyInt(ast::IntTy::I64) => convert_val!(i64, Int, i64),
ty::TyUint(ast::UintTy::U8) => convert_val!(u8, Uint, u64),
ty::TyUint(ast::UintTy::U16) => convert_val!(u16, Uint, u64),
ty::TyUint(ast::UintTy::U32) => convert_val!(u32, Uint, u64),
ty::TyUint(ast::UintTy::U64) => convert_val!(u64, Uint, u64),
ty::TyFloat(ast::FloatTy::F32) => convert_val!(f32, Float, f64),
ty::TyFloat(ast::FloatTy::F64) => convert_val!(f64, Float, f64),
_ => Err(ErrKind::CannotCast),
ty::TyBool if v == 0 => Ok(Bool(false)),
ty::TyBool if v == 1 => Ok(Bool(true)),
ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i8))),
ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i16))),
ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i32))),
ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))),
ty::TyInt(ast::IntTy::Is) => {
Ok(Integral(Isize(try!(ConstIsize::new(v as i64, tcx.sess.target.int_type)))))
},
ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
ty::TyUint(ast::UintTy::Us) => {
Ok(Integral(Usize(try!(ConstUsize::new(v, tcx.sess.target.uint_type)))))
},
ty::TyFloat(ast::FloatTy::F64) if val.is_negative() => {
// FIXME: this could probably be prettier
// there's no easy way to turn an `Infer` into a f64
let val = try!((-val).map_err(Math));
let val = val.to_u64().unwrap() as f64;
let val = -val;
Ok(Float(val))
},
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(val.to_u64().unwrap() as f64)),
ty::TyFloat(ast::FloatTy::F32) if val.is_negative() => {
let val = try!((-val).map_err(Math));
let val = val.to_u64().unwrap() as f32;
let val = -val;
Ok(Float(val as f64))
},
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(val.to_u64().unwrap() as f32 as f64)),
_ => Err(CannotCast),
}
}
fn lit_to_const(sess: &Session, span: Span, lit: &ast::Lit, ty_hint: Option<Ty>) -> ConstVal {
match lit.node {
ast::LitKind::Str(ref s, _) => Str((*s).clone()),
ast::LitKind::ByteStr(ref data) => {
ByteStr(data.clone())
}
ast::LitKind::Byte(n) => Uint(n as u64),
ast::LitKind::Char(n) => Uint(n as u64),
ast::LitKind::Int(n, ast::LitIntType::Signed(_)) => Int(n as i64),
ast::LitKind::Int(n, ast::LitIntType::Unsuffixed) => {
match ty_hint.map(|ty| &ty.sty) {
Some(&ty::TyUint(_)) => Uint(n),
_ => Int(n as i64)
fn cast_const_float<'tcx>(tcx: &ty::ctxt<'tcx>, f: f64, ty: ty::Ty) -> CastResult {
match ty.sty {
ty::TyInt(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
ty::TyInt(_) => cast_const_int(tcx, InferSigned(f as i64), ty),
ty::TyUint(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(f)),
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(f as f32 as f64)),
_ => Err(CannotCast),
}
}
fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
match val {
Integral(i) => cast_const_int(tcx, i, ty),
Bool(b) => cast_const_int(tcx, Infer(b as u64), ty),
Float(f) => cast_const_float(tcx, f, ty),
Char(c) => cast_const_int(tcx, Infer(c as u64), ty),
_ => Err(CannotCast),
}
}
fn lit_to_const<'tcx>(lit: &ast::LitKind,
tcx: &ty::ctxt<'tcx>,
ty_hint: Option<Ty<'tcx>>,
span: Span,
) -> Result<ConstVal, ConstMathErr> {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
const I8MAX: u64 = ::std::i8::MAX as u64;
const I16MAX: u64 = ::std::i16::MAX as u64;
const I32MAX: u64 = ::std::i32::MAX as u64;
const I64MAX: u64 = ::std::i64::MAX as u64;
const U8MAX: u64 = ::std::u8::MAX as u64;
const U16MAX: u64 = ::std::u16::MAX as u64;
const U32MAX: u64 = ::std::u32::MAX as u64;
const U64MAX: u64 = ::std::u64::MAX as u64;
match *lit {
LitKind::Str(ref s, _) => Ok(Str((*s).clone())),
LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
LitKind::Byte(n) => Ok(Integral(U8(n))),
LitKind::Int(n @ 0...I8MAX, Signed(IntTy::I8)) => Ok(Integral(I8(n as i8))),
LitKind::Int(n @ 0...I16MAX, Signed(IntTy::I16)) => Ok(Integral(I16(n as i16))),
LitKind::Int(n @ 0...I32MAX, Signed(IntTy::I32)) => Ok(Integral(I32(n as i32))),
LitKind::Int(n @ 0...I64MAX, Signed(IntTy::I64)) => Ok(Integral(I64(n as i64))),
LitKind::Int(n, Signed(IntTy::Is)) => {
Ok(Integral(Isize(try!(ConstIsize::new(n as i64, tcx.sess.target.int_type)))))
},
LitKind::Int(_, Signed(ty)) => Err(ConstMathErr::LitOutOfRange(ty)),
LitKind::Int(n, Unsuffixed) => {
match ty_hint.map(|t| &t.sty) {
Some(&ty::TyInt(ity)) => {
lit_to_const(&LitKind::Int(n, Signed(ity)), tcx, ty_hint, span)
},
Some(&ty::TyUint(uty)) => {
lit_to_const(&LitKind::Int(n, Unsigned(uty)), tcx, ty_hint, span)
},
None => Ok(Integral(Infer(n))),
Some(&ty::TyEnum(ref adt, _)) => {
let hints = tcx.lookup_repr_hints(adt.did);
let int_ty = tcx.enum_repr_type(hints.iter().next());
lit_to_const(lit, tcx, Some(int_ty.to_ty(tcx)), span)
},
Some(ty_hint) => panic!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
}
}
ast::LitKind::Int(n, ast::LitIntType::Unsigned(_)) => Uint(n),
ast::LitKind::Float(ref n, _) |
ast::LitKind::FloatUnsuffixed(ref n) => {
},
LitKind::Int(n @ 0...U8MAX, Unsigned(UintTy::U8)) => Ok(Integral(U8(n as u8))),
LitKind::Int(n @ 0...U16MAX, Unsigned(UintTy::U16)) => Ok(Integral(U16(n as u16))),
LitKind::Int(n @ 0...U32MAX, Unsigned(UintTy::U32)) => Ok(Integral(U32(n as u32))),
LitKind::Int(n @ 0...U64MAX, Unsigned(UintTy::U64)) => Ok(Integral(U64(n as u64))),
LitKind::Int(n, Unsigned(UintTy::Us)) => {
Ok(Integral(Usize(try!(ConstUsize::new(n as u64, tcx.sess.target.uint_type)))))
},
LitKind::Int(_, Unsigned(ty)) => Err(ConstMathErr::ULitOutOfRange(ty)),
LitKind::Float(ref n, _) |
LitKind::FloatUnsuffixed(ref n) => {
if let Ok(x) = n.parse::<f64>() {
Float(x)
Ok(Float(x))
} else {
// FIXME(#31407) this is only necessary because float parsing is buggy
sess.span_bug(span, "could not evaluate float literal (see issue #31407)");
tcx.sess.span_bug(span, "could not evaluate float literal (see issue #31407)");
}
}
ast::LitKind::Bool(b) => Bool(b)
LitKind::Bool(b) => Ok(Bool(b)),
LitKind::Char(c) => Ok(Char(c)),
}
}
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
Some(match (a, b) {
(&Int(a), &Int(b)) => a.cmp(&b),
(&Uint(a), &Uint(b)) => a.cmp(&b),
match (a, b) {
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
(&Float(a), &Float(b)) => {
// This is pretty bad but it is the existing behavior.
if a == b {
Some(if a == b {
Ordering::Equal
} else if a < b {
Ordering::Less
} else {
Ordering::Greater
}
})
}
(&Str(ref a), &Str(ref b)) => a.cmp(b),
(&Bool(a), &Bool(b)) => a.cmp(&b),
(&ByteStr(ref a), &ByteStr(ref b)) => a.cmp(b),
_ => return None
})
(&Str(ref a), &Str(ref b)) => Some(a.cmp(b)),
(&Bool(a), &Bool(b)) => Some(a.cmp(&b)),
(&ByteStr(ref a), &ByteStr(ref b)) => Some(a.cmp(b)),
(&Char(a), &Char(ref b)) => Some(a.cmp(b)),
_ => None,
}
}
pub fn compare_lit_exprs<'tcx>(tcx: &TyCtxt<'tcx>,

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

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,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,551 @@
// 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 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 i8),
(Infer(a @ 0...as_u64::I16MAX), I16(_)) => I16(a as i16),
(Infer(a @ 0...as_u64::I32MAX), I32(_)) => I32(a 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 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"),
}
}
}
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

@ -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

@ -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

@ -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

@ -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;
@ -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,7 @@ 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::Function(_) => C_nil(ccx)
}
}
@ -99,7 +118,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

@ -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

@ -80,6 +80,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;
@ -1021,7 +1023,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)]
)
}
@ -1030,24 +1032,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) => {
@ -1066,16 +1083,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,
@ -1085,12 +1097,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>,
@ -1104,17 +1115,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

@ -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::MirPass;
@ -23,6 +24,7 @@ use rustc::mir::repr::{Mir, Literal};
use rustc::mir::visit::MutVisitor;
use rustc::middle::infer::InferCtxt;
use rustc::middle::const_eval::ConstVal;
use rustc_const_eval::ConstInt;
use rustc_plugin::Registry;
struct Pass;
@ -37,8 +39,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

@ -17,7 +17,7 @@
// self-hosted and a cross-compiled setup; therefore resorting to
// error-pattern for now.
// error-pattern: expected constant integer for repeat count, but attempted to add with overflow
// error-pattern: expected constant integer for repeat count, but tried to add two integrals of
#![allow(unused_imports)]
@ -36,4 +36,3 @@ fn main() {
fn foo<T:fmt::Debug>(x: T) {
println!("{:?}", x);
}

View File

@ -21,8 +21,7 @@ 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 tried to add two integrals of different types [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,44 @@
// 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.
#[repr(i8)]
enum Ei8 {
Ai8 = 23,
Bi8 = -23,
Ci8 = 223, //~ ERROR literal out of range for i8 [E0080]
}
#[repr(i16)]
enum Ei16 {
Ai16 = 23,
Bi16 = -22333,
Ci16 = 55555, //~ ERROR literal out of range for i16 [E0080]
}
#[repr(i32)]
enum Ei32 {
Ai32 = 23,
Bi32 = -2_000_000_000,
Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32 [E0080]
}
#[repr(i64)]
enum Ei64 {
Ai64 = 23,
Bi64 = -9223372036854775808,
Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64 [E0080]
}
// 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,9 @@
enum Foo {
A = 1i64,
//~^ ERROR mismatched types
//~| expected `isize`
//~| found `i64`
//~^ ERROR mismatched types: expected `isize` got `i64`
B = 2u8
//~^ ERROR mismatched types
//~| expected `isize`
//~| found `u8`
//~^ ERROR mismatched types: expected `isize` got `u8`
}
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,23 @@
// 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 literal out of range for i8
}

View File

@ -0,0 +1,21 @@
// 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 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

@ -44,12 +44,12 @@ fn main() {
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `isize`
//~| ERROR expected positive integer for repeat count, found negative integer [E0306]
//~| ERROR expected positive integer for repeat count, found isize [E0306]
let f = [0_usize; -1_isize];
//~^ ERROR mismatched types
//~| expected `usize`
//~| found `isize`
//~| ERROR expected positive integer for repeat count, found negative integer [E0306]
//~| ERROR expected positive integer for repeat count, found isize [E0306]
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,37 @@
// 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.
#[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);
assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000);
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

@ -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);
}

View File

@ -20,7 +20,7 @@ struct S<T, S> {
pub fn main() {
unsafe {
let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as u32 };
let transd : [u8; 9] = mem::transmute(s);
// Don't worry about endianness, the numbers are palindromic.
assert_eq!(transd,
@ -29,7 +29,7 @@ pub fn main() {
0xaa, 0xaa, 0xaa, 0xaa]);
let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as i16};
let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as u16};
let transd : [u8; 4] = mem::transmute(s);
// Again, no endianness problems.
assert_eq!(transd,

View File

@ -45,7 +45,7 @@ fn test_expr() {
let v4 = 4 as isize;
let v2 = 2 as isize;
assert_eq!(v10 >> v2 as usize, v2 as i8);
assert_eq!(v10 << v4 as usize, 160 as i8);
assert_eq!(v10 << v2 as usize, 40 as i8);
let v10 = 10 as usize;
let v4 = 4 as isize;
@ -71,9 +71,9 @@ fn test_const() {
assert_eq!(r2_3, 160 as isize);
static r1_4: i8 = 10i8 >> 2_usize;
static r2_4: i8 = 10i8 << 4_usize;
static r2_4: i8 = 10i8 << 2_usize;
assert_eq!(r1_4, 2 as i8);
assert_eq!(r2_4, 160 as i8);
assert_eq!(r2_4, 40 as i8);
static r1_5: usize = 10_usize >> 2_usize;
static r2_5: usize = 10_usize << 4_usize;