typestrong constant integers
This commit is contained in:
16
mk/crates.mk
16
mk/crates.mk
@@ -53,7 +53,7 @@ TARGET_CRATES := libc std term \
|
|||||||
getopts collections test rand \
|
getopts collections test rand \
|
||||||
core alloc \
|
core alloc \
|
||||||
rustc_unicode rustc_bitflags \
|
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_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
|
||||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||||
rustc_data_structures rustc_front rustc_platform_intrinsics \
|
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 := std term serialize log arena libc rustc_bitflags rustc_unicode
|
||||||
DEPS_syntax_ext := syntax fmt_macros
|
DEPS_syntax_ext := syntax fmt_macros
|
||||||
|
|
||||||
|
DEPS_rustc_const_eval := std syntax
|
||||||
|
|
||||||
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
|
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_back := std syntax rustc_llvm rustc_front flate log libc
|
||||||
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
|
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
|
||||||
DEPS_rustc_data_structures := std log serialize
|
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_front := std syntax log serialize
|
||||||
DEPS_rustc_lint := rustc log syntax
|
DEPS_rustc_lint := rustc log syntax
|
||||||
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
|
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_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_resolve := arena rustc rustc_front log syntax
|
||||||
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
|
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
|
||||||
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
|
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
|
||||||
DEPS_rustc_privacy := rustc rustc_front log syntax
|
DEPS_rustc_privacy := rustc rustc_front log syntax
|
||||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
|
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
|
||||||
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
|
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \
|
||||||
DEPS_rustc_typeck := rustc syntax 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 \
|
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||||
test rustc_lint rustc_front
|
test rustc_lint rustc_front
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ extern crate rustc_front;
|
|||||||
extern crate rustc_data_structures;
|
extern crate rustc_data_structures;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
extern crate collections;
|
extern crate collections;
|
||||||
|
extern crate rustc_const_eval;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate syntax;
|
#[macro_use] extern crate syntax;
|
||||||
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||||
|
|||||||
@@ -23,10 +23,9 @@ use middle::subst::Subst;
|
|||||||
use middle::def_id::DefId;
|
use middle::def_id::DefId;
|
||||||
use middle::pat_util::def_to_path;
|
use middle::pat_util::def_to_path;
|
||||||
use middle::ty::{self, Ty, TyCtxt};
|
use middle::ty::{self, Ty, TyCtxt};
|
||||||
|
use middle::ty::util::IntTypeExt;
|
||||||
use middle::astconv_util::ast_ty_to_prim_ty;
|
use middle::astconv_util::ast_ty_to_prim_ty;
|
||||||
use util::num::ToPrimitive;
|
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
use session::Session;
|
|
||||||
|
|
||||||
use graphviz::IntoCow;
|
use graphviz::IntoCow;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
@@ -43,10 +42,20 @@ use std::cmp::Ordering;
|
|||||||
use std::collections::hash_map::Entry::Vacant;
|
use std::collections::hash_map::Entry::Vacant;
|
||||||
use std::hash;
|
use std::hash;
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use std::{i8, i16, i32, i64, u8, u16, u32, u64};
|
|
||||||
use std::rc::Rc;
|
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,
|
enum_def: DefId,
|
||||||
variant_def: DefId)
|
variant_def: DefId)
|
||||||
-> Option<&'a Expr> {
|
-> 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)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub enum ConstVal {
|
pub enum ConstVal {
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Int(i64),
|
Integral(ConstInt),
|
||||||
Uint(u64),
|
|
||||||
Str(InternedString),
|
Str(InternedString),
|
||||||
ByteStr(Rc<Vec<u8>>),
|
ByteStr(Rc<Vec<u8>>),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
@@ -258,14 +266,14 @@ pub enum ConstVal {
|
|||||||
Function(DefId),
|
Function(DefId),
|
||||||
Array(ast::NodeId, u64),
|
Array(ast::NodeId, u64),
|
||||||
Repeat(ast::NodeId, u64),
|
Repeat(ast::NodeId, u64),
|
||||||
|
Char(char),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hash::Hash for ConstVal {
|
impl hash::Hash for ConstVal {
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
match *self {
|
match *self {
|
||||||
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
|
Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
|
||||||
Int(a) => a.hash(state),
|
Integral(a) => a.hash(state),
|
||||||
Uint(a) => a.hash(state),
|
|
||||||
Str(ref a) => a.hash(state),
|
Str(ref a) => a.hash(state),
|
||||||
ByteStr(ref a) => a.hash(state),
|
ByteStr(ref a) => a.hash(state),
|
||||||
Bool(a) => a.hash(state),
|
Bool(a) => a.hash(state),
|
||||||
@@ -274,6 +282,7 @@ impl hash::Hash for ConstVal {
|
|||||||
Function(a) => a.hash(state),
|
Function(a) => a.hash(state),
|
||||||
Array(a, n) => { a.hash(state); n.hash(state) },
|
Array(a, n) => { a.hash(state); n.hash(state) },
|
||||||
Repeat(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 {
|
fn eq(&self, other: &ConstVal) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
|
(&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
|
||||||
(&Int(a), &Int(b)) => a == b,
|
(&Integral(a), &Integral(b)) => a == b,
|
||||||
(&Uint(a), &Uint(b)) => a == b,
|
|
||||||
(&Str(ref a), &Str(ref b)) => a == b,
|
(&Str(ref a), &Str(ref b)) => a == b,
|
||||||
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
|
(&ByteStr(ref a), &ByteStr(ref b)) => a == b,
|
||||||
(&Bool(a), &Bool(b)) => a == b,
|
(&Bool(a), &Bool(b)) => a == b,
|
||||||
@@ -296,6 +304,7 @@ impl PartialEq for ConstVal {
|
|||||||
(&Function(a), &Function(b)) => a == b,
|
(&Function(a), &Function(b)) => a == b,
|
||||||
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
|
(&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
|
||||||
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
|
(&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
|
||||||
|
(&Char(a), &Char(b)) => a == b,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,9 +316,7 @@ impl ConstVal {
|
|||||||
pub fn description(&self) -> &'static str {
|
pub fn description(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
Float(_) => "float",
|
Float(_) => "float",
|
||||||
Int(i) if i < 0 => "negative integer",
|
Integral(i) => i.description(),
|
||||||
Int(_) => "positive integer",
|
|
||||||
Uint(_) => "unsigned integer",
|
|
||||||
Str(_) => "string literal",
|
Str(_) => "string literal",
|
||||||
ByteStr(_) => "byte string literal",
|
ByteStr(_) => "byte string literal",
|
||||||
Bool(_) => "boolean",
|
Bool(_) => "boolean",
|
||||||
@@ -318,6 +325,7 @@ impl ConstVal {
|
|||||||
Function(_) => "function definition",
|
Function(_) => "function definition",
|
||||||
Array(..) => "array",
|
Array(..) => "array",
|
||||||
Repeat(..) => "repeat",
|
Repeat(..) => "repeat",
|
||||||
|
Char(..) => "char",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -402,7 +410,6 @@ pub enum ErrKind {
|
|||||||
CannotCast,
|
CannotCast,
|
||||||
CannotCastTo(&'static str),
|
CannotCastTo(&'static str),
|
||||||
InvalidOpForInts(hir::BinOp_),
|
InvalidOpForInts(hir::BinOp_),
|
||||||
InvalidOpForUInts(hir::BinOp_),
|
|
||||||
InvalidOpForBools(hir::BinOp_),
|
InvalidOpForBools(hir::BinOp_),
|
||||||
InvalidOpForFloats(hir::BinOp_),
|
InvalidOpForFloats(hir::BinOp_),
|
||||||
InvalidOpForIntUint(hir::BinOp_),
|
InvalidOpForIntUint(hir::BinOp_),
|
||||||
@@ -442,6 +449,13 @@ pub enum ErrKind {
|
|||||||
MiscCatchAll,
|
MiscCatchAll,
|
||||||
|
|
||||||
IndexOpFeatureGated,
|
IndexOpFeatureGated,
|
||||||
|
Math(ConstMathErr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ConstMathErr> for ErrKind {
|
||||||
|
fn from(err: ConstMathErr) -> ErrKind {
|
||||||
|
Math(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstEvalErr {
|
impl ConstEvalErr {
|
||||||
@@ -451,8 +465,7 @@ impl ConstEvalErr {
|
|||||||
match self.kind {
|
match self.kind {
|
||||||
CannotCast => "can't cast this type".into_cow(),
|
CannotCast => "can't cast this type".into_cow(),
|
||||||
CannotCastTo(s) => format!("can't cast this type to {}", s).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(),
|
InvalidOpForInts(_) => "can't do this op on integrals".into_cow(),
|
||||||
InvalidOpForUInts(_) => "can't do this op on unsigned integrals".into_cow(),
|
|
||||||
InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
|
InvalidOpForBools(_) => "can't do this op on bools".into_cow(),
|
||||||
InvalidOpForFloats(_) => "can't do this op on floats".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(),
|
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(),
|
MiscBinaryOp => "bad operands for binary".into_cow(),
|
||||||
MiscCatchAll => "unsupported constant expr".into_cow(),
|
MiscCatchAll => "unsupported constant expr".into_cow(),
|
||||||
IndexOpFeatureGated => "the index operation on const values is unstable".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 {
|
macro_rules! signal {
|
||||||
($e:expr, $exn:expr) => {
|
($e:expr, $exn:expr) => {
|
||||||
return Err(ConstEvalErr { span: $e.span, kind: $exn })
|
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
|
/// Evaluate a constant expression in a context where the expression isn't
|
||||||
/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
|
/// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
|
||||||
/// but a few places need to evaluate constants during type-checking, like
|
/// 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)
|
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 {
|
let result = match e.node {
|
||||||
hir::ExprUnary(hir::UnNeg, ref inner) => {
|
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)) {
|
match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
|
||||||
Float(f) => Float(-f),
|
Float(f) => Float(-f),
|
||||||
Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
|
Integral(i) => Integral(math!(e, -i)),
|
||||||
Uint(i) => {
|
|
||||||
try!(const_uint_checked_neg(i, e, expr_uint_type))
|
|
||||||
}
|
|
||||||
const_val => signal!(e, NegateOn(const_val)),
|
const_val => signal!(e, NegateOn(const_val)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ExprUnary(hir::UnNot, ref inner) => {
|
hir::ExprUnary(hir::UnNot, ref inner) => {
|
||||||
match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
|
match try!(eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)) {
|
||||||
Int(i) => Int(!i),
|
Integral(i) => Integral(math!(e, !i)),
|
||||||
Uint(i) => const_uint_not(i, expr_uint_type),
|
|
||||||
Bool(b) => Bool(!b),
|
Bool(b) => Bool(!b),
|
||||||
const_val => signal!(e, NotOn(const_val)),
|
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),
|
hir::BiShl | hir::BiShr => ty_hint.checked_or(tcx.types.usize),
|
||||||
_ => ty_hint
|
_ => 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)),
|
match (try!(eval_const_expr_partial(tcx, &a, ty_hint, fn_args)),
|
||||||
try!(eval_const_expr_partial(tcx, &b, b_ty, fn_args))) {
|
try!(eval_const_expr_partial(tcx, &b, b_ty, fn_args))) {
|
||||||
(Float(a), Float(b)) => {
|
(Float(a), Float(b)) => {
|
||||||
@@ -888,63 +665,28 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
_ => signal!(e, InvalidOpForFloats(op.node)),
|
_ => signal!(e, InvalidOpForFloats(op.node)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Int(a), Int(b)) => {
|
(Integral(a), Integral(b)) => {
|
||||||
|
use std::cmp::Ordering::*;
|
||||||
match op.node {
|
match op.node {
|
||||||
hir::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
|
hir::BiAdd => Integral(math!(e, a + b)),
|
||||||
hir::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
|
hir::BiSub => Integral(math!(e, a - b)),
|
||||||
hir::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
|
hir::BiMul => Integral(math!(e, a * b)),
|
||||||
hir::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
|
hir::BiDiv => Integral(math!(e, a / b)),
|
||||||
hir::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
|
hir::BiRem => Integral(math!(e, a % b)),
|
||||||
hir::BiBitAnd => Int(a & b),
|
hir::BiBitAnd => Integral(math!(e, a & b)),
|
||||||
hir::BiBitOr => Int(a | b),
|
hir::BiBitOr => Integral(math!(e, a | b)),
|
||||||
hir::BiBitXor => Int(a ^ b),
|
hir::BiBitXor => Integral(math!(e, a ^ b)),
|
||||||
hir::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
|
hir::BiShl => Integral(math!(e, a << b)),
|
||||||
hir::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
|
hir::BiShr => Integral(math!(e, a >> b)),
|
||||||
hir::BiEq => Bool(a == b),
|
hir::BiEq => Bool(math!(e, a.try_cmp(b)) == Equal),
|
||||||
hir::BiLt => Bool(a < b),
|
hir::BiLt => Bool(math!(e, a.try_cmp(b)) == Less),
|
||||||
hir::BiLe => Bool(a <= b),
|
hir::BiLe => Bool(math!(e, a.try_cmp(b)) != Greater),
|
||||||
hir::BiNe => Bool(a != b),
|
hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
|
||||||
hir::BiGe => Bool(a >= b),
|
hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
|
||||||
hir::BiGt => Bool(a > b),
|
hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
|
||||||
_ => signal!(e, InvalidOpForInts(op.node)),
|
_ => 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(a), Bool(b)) => {
|
||||||
Bool(match op.node {
|
Bool(match op.node {
|
||||||
hir::BiAnd => a && b,
|
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) => {
|
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(|| {
|
.unwrap_or_else(|| {
|
||||||
tcx.sess.span_fatal(target_ty.span,
|
tcx.sess.span_fatal(target_ty.span,
|
||||||
"target type not found for const cast")
|
"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 {
|
let base_hint = if let ExprTypeChecked = ty_hint {
|
||||||
ExprTypeChecked
|
ExprTypeChecked
|
||||||
} else {
|
} 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) {
|
match tcx.expr_ty_opt(&base) {
|
||||||
Some(t) => UncheckedExprHint(t),
|
Some(t) => UncheckedExprHint(t),
|
||||||
None => ty_hint
|
None => ty_hint
|
||||||
@@ -1103,10 +842,28 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
|
|
||||||
let mut call_args = NodeMap();
|
let mut call_args = NodeMap();
|
||||||
for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
|
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(
|
let arg_val = try!(eval_const_expr_partial(
|
||||||
tcx,
|
tcx,
|
||||||
arg_expr,
|
arg_expr,
|
||||||
sub_ty_hint,
|
arg_hint,
|
||||||
fn_args
|
fn_args
|
||||||
));
|
));
|
||||||
debug!("const call arg: {:?}", arg);
|
debug!("const call arg: {:?}", arg);
|
||||||
@@ -1116,7 +873,10 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
debug!("const call({:?})", call_args);
|
debug!("const call({:?})", call_args);
|
||||||
try!(eval_const_expr_partial(tcx, &result, ty_hint, Some(&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) => {
|
hir::ExprBlock(ref block) => {
|
||||||
match block.expr {
|
match block.expr {
|
||||||
Some(ref expr) => try!(eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)),
|
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 arr = try!(eval_const_expr_partial(tcx, arr, arr_hint, fn_args));
|
||||||
let idx_hint = ty_hint.checked_or(tcx.types.usize);
|
let idx_hint = ty_hint.checked_or(tcx.types.usize);
|
||||||
let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
|
let idx = match try!(eval_const_expr_partial(tcx, idx, idx_hint, fn_args)) {
|
||||||
Int(i) if i >= 0 => i as u64,
|
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
|
||||||
Int(_) => signal!(idx, IndexNegative),
|
Integral(_) => unreachable!(),
|
||||||
Uint(i) => i,
|
|
||||||
_ => signal!(idx, IndexNotInt),
|
_ => signal!(idx, IndexNotInt),
|
||||||
};
|
};
|
||||||
|
assert_eq!(idx as usize as u64, idx);
|
||||||
match arr {
|
match arr {
|
||||||
Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
|
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))
|
try!(eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args))
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -1155,13 +916,13 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
fn_args,
|
fn_args,
|
||||||
)),
|
)),
|
||||||
|
|
||||||
ByteStr(ref data) if idx as usize >= data.len()
|
ByteStr(ref data) if idx >= data.len() as u64 => signal!(e, IndexOutOfBounds),
|
||||||
=> signal!(e, IndexOutOfBounds),
|
ByteStr(data) => {
|
||||||
ByteStr(data) => Uint(data[idx as usize] as u64),
|
Integral(U8(data[idx as usize]))
|
||||||
|
},
|
||||||
|
|
||||||
Str(ref s) if idx as usize >= s.len()
|
Str(ref s) if idx as usize >= s.len() => signal!(e, IndexOutOfBounds),
|
||||||
=> signal!(e, IndexOutOfBounds),
|
Str(_) => unimplemented!(), // FIXME: return a const char
|
||||||
Str(_) => unimplemented!(), // there's no const_char type
|
|
||||||
_ => signal!(e, IndexedNonVec),
|
_ => signal!(e, IndexedNonVec),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1171,9 +932,8 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
Repeat(
|
Repeat(
|
||||||
e.id,
|
e.id,
|
||||||
match try!(eval_const_expr_partial(tcx, &n, len_hint, fn_args)) {
|
match try!(eval_const_expr_partial(tcx, &n, len_hint, fn_args)) {
|
||||||
Int(i) if i >= 0 => i as u64,
|
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
|
||||||
Int(_) => signal!(e, RepeatCountNotNatural),
|
Integral(_) => signal!(e, RepeatCountNotNatural),
|
||||||
Uint(i) => i,
|
|
||||||
_ => signal!(e, RepeatCountNotInt),
|
_ => 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 Tuple(tup_id) = c {
|
||||||
if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
|
if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
|
||||||
if index.node < fields.len() {
|
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 {
|
} else {
|
||||||
signal!(e, TupleIndexOutOfBounds);
|
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 the idents are compared run-pass/issue-19244 fails
|
||||||
if let Some(f) = fields.iter().find(|f| f.name.node
|
if let Some(f) = fields.iter().find(|f| f.name.node
|
||||||
== field_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 {
|
} else {
|
||||||
signal!(e, MissingStructField);
|
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 {
|
fn cast_const_int<'tcx>(tcx: &TyCtxt<'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
|
||||||
macro_rules! convert_val {
|
let v = val.to_u64_unchecked();
|
||||||
($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"),
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::TyInt(ast::IntTy::Is) => unreachable!(),
|
ty::TyBool if v == 0 => Ok(Bool(false)),
|
||||||
ty::TyUint(ast::UintTy::Us) => unreachable!(),
|
ty::TyBool if v == 1 => Ok(Bool(true)),
|
||||||
|
ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i8))),
|
||||||
ty::TyInt(ast::IntTy::I8) => convert_val!(i8, Int, i64),
|
ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i16))),
|
||||||
ty::TyInt(ast::IntTy::I16) => convert_val!(i16, Int, i64),
|
ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i32))),
|
||||||
ty::TyInt(ast::IntTy::I32) => convert_val!(i32, Int, i64),
|
ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))),
|
||||||
ty::TyInt(ast::IntTy::I64) => convert_val!(i64, Int, 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) => convert_val!(u8, Uint, u64),
|
},
|
||||||
ty::TyUint(ast::UintTy::U16) => convert_val!(u16, Uint, u64),
|
ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))),
|
||||||
ty::TyUint(ast::UintTy::U32) => convert_val!(u32, Uint, u64),
|
ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))),
|
||||||
ty::TyUint(ast::UintTy::U64) => convert_val!(u64, Uint, u64),
|
ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))),
|
||||||
|
ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))),
|
||||||
ty::TyFloat(ast::FloatTy::F32) => convert_val!(f32, Float, f64),
|
ty::TyUint(ast::UintTy::Us) => {
|
||||||
ty::TyFloat(ast::FloatTy::F64) => convert_val!(f64, Float, f64),
|
Ok(Integral(Usize(try!(ConstUsize::new(v, tcx.sess.target.uint_type)))))
|
||||||
_ => Err(ErrKind::CannotCast),
|
},
|
||||||
|
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 {
|
fn cast_const_float<'tcx>(tcx: &ty::ctxt<'tcx>, f: f64, ty: ty::Ty) -> CastResult {
|
||||||
match lit.node {
|
match ty.sty {
|
||||||
ast::LitKind::Str(ref s, _) => Str((*s).clone()),
|
ty::TyInt(_) if f >= 0.0 => cast_const_int(tcx, Infer(f as u64), ty),
|
||||||
ast::LitKind::ByteStr(ref data) => {
|
ty::TyInt(_) => cast_const_int(tcx, InferSigned(f as i64), ty),
|
||||||
ByteStr(data.clone())
|
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),
|
||||||
}
|
}
|
||||||
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),
|
fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
|
||||||
ast::LitKind::Int(n, ast::LitIntType::Unsuffixed) => {
|
match val {
|
||||||
match ty_hint.map(|ty| &ty.sty) {
|
Integral(i) => cast_const_int(tcx, i, ty),
|
||||||
Some(&ty::TyUint(_)) => Uint(n),
|
Bool(b) => cast_const_int(tcx, Infer(b as u64), ty),
|
||||||
_ => Int(n as i64)
|
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, _) |
|
LitKind::Int(n @ 0...U8MAX, Unsigned(UintTy::U8)) => Ok(Integral(U8(n as u8))),
|
||||||
ast::LitKind::FloatUnsuffixed(ref n) => {
|
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>() {
|
if let Ok(x) = n.parse::<f64>() {
|
||||||
Float(x)
|
Ok(Float(x))
|
||||||
} else {
|
} else {
|
||||||
// FIXME(#31407) this is only necessary because float parsing is buggy
|
// 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> {
|
pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
|
||||||
Some(match (a, b) {
|
match (a, b) {
|
||||||
(&Int(a), &Int(b)) => a.cmp(&b),
|
(&Integral(a), &Integral(b)) => a.try_cmp(b).ok(),
|
||||||
(&Uint(a), &Uint(b)) => a.cmp(&b),
|
|
||||||
(&Float(a), &Float(b)) => {
|
(&Float(a), &Float(b)) => {
|
||||||
// This is pretty bad but it is the existing behavior.
|
// This is pretty bad but it is the existing behavior.
|
||||||
if a == b {
|
Some(if a == b {
|
||||||
Ordering::Equal
|
Ordering::Equal
|
||||||
} else if a < b {
|
} else if a < b {
|
||||||
Ordering::Less
|
Ordering::Less
|
||||||
} else {
|
} else {
|
||||||
Ordering::Greater
|
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>,
|
pub fn compare_lit_exprs<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ use syntax::attr::{self, AttrMetaMethods};
|
|||||||
use syntax::codemap::{DUMMY_SP, Span};
|
use syntax::codemap::{DUMMY_SP, Span};
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::parse::token::InternedString;
|
||||||
|
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
|
|
||||||
use rustc_front::hir;
|
use rustc_front::hir;
|
||||||
use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};
|
use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};
|
||||||
use rustc_front::intravisit::Visitor;
|
use rustc_front::intravisit::Visitor;
|
||||||
@@ -100,8 +102,7 @@ mod ivar;
|
|||||||
mod structural_impls;
|
mod structural_impls;
|
||||||
mod sty;
|
mod sty;
|
||||||
|
|
||||||
pub type Disr = u64;
|
pub type Disr = ConstInt;
|
||||||
pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
|
|
||||||
|
|
||||||
// Data types
|
// Data types
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ use middle::traits;
|
|||||||
use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
|
use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
|
||||||
use middle::ty::{Disr, ParameterEnvironment};
|
use middle::ty::{Disr, ParameterEnvironment};
|
||||||
use middle::ty::TypeVariants::*;
|
use middle::ty::TypeVariants::*;
|
||||||
use util::num::ToPrimitive;
|
|
||||||
|
use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize};
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::hash::{Hash, SipHasher, Hasher};
|
use std::hash::{Hash, SipHasher, Hasher};
|
||||||
@@ -34,11 +35,9 @@ use rustc_front::hir;
|
|||||||
|
|
||||||
pub trait IntTypeExt {
|
pub trait IntTypeExt {
|
||||||
fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>;
|
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_incr(&self, val: Disr) -> Option<Disr>;
|
||||||
fn disr_string(&self, val: Disr) -> String;
|
fn assert_ty_matches(&self, val: Disr);
|
||||||
fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
|
fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntTypeExt for attr::IntType {
|
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 {
|
match *self {
|
||||||
SignedInt(ast::IntTy::I8) => val.to_i8() .map(|v| v as Disr),
|
SignedInt(ast::IntTy::I8) => ConstInt::I8(0),
|
||||||
SignedInt(ast::IntTy::I16) => val.to_i16() .map(|v| v as Disr),
|
SignedInt(ast::IntTy::I16) => ConstInt::I16(0),
|
||||||
SignedInt(ast::IntTy::I32) => val.to_i32() .map(|v| v as Disr),
|
SignedInt(ast::IntTy::I32) => ConstInt::I32(0),
|
||||||
SignedInt(ast::IntTy::I64) => val.to_i64() .map(|v| v as Disr),
|
SignedInt(ast::IntTy::I64) => ConstInt::I64(0),
|
||||||
UnsignedInt(ast::UintTy::U8) => val.to_u8() .map(|v| v as Disr),
|
SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
|
||||||
UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
|
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
|
||||||
UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
|
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
|
||||||
UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
UnsignedInt(ast::UintTy::Us) |
|
UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0),
|
||||||
SignedInt(ast::IntTy::Is) => unreachable!(),
|
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> {
|
fn assert_ty_matches(&self, val: Disr) {
|
||||||
match *self {
|
match (*self, val) {
|
||||||
SignedInt(ast::IntTy::I8) => val.to_i8() .map(|v| v as Disr),
|
(SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
|
||||||
SignedInt(ast::IntTy::I16) => val.to_i16() .map(|v| v as Disr),
|
(SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
|
||||||
SignedInt(ast::IntTy::I32) => val.to_i32() .map(|v| v as Disr),
|
(SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
|
||||||
SignedInt(ast::IntTy::I64) => val.to_i64() .map(|v| v as Disr),
|
(SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
|
||||||
UnsignedInt(ast::UintTy::U8) => val.to_u8() .map(|v| v as Disr),
|
(SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
|
||||||
UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
|
(UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
|
||||||
UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
|
(UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
|
||||||
UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
|
(UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
|
||||||
|
(UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
|
||||||
UnsignedInt(ast::UintTy::Us) |
|
(UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
|
||||||
SignedInt(ast::IntTy::Is) => unreachable!(),
|
_ => panic!("disr type mismatch: {:?} vs {:?}", self, val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disr_incr(&self, val: Disr) -> Option<Disr> {
|
fn disr_incr(&self, val: Disr) -> Option<Disr> {
|
||||||
macro_rules! add1 {
|
self.assert_ty_matches(val);
|
||||||
($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
|
(val + ConstInt::Infer(1)).ok()
|
||||||
}
|
|
||||||
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!(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,13 +215,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `(normalized_type, ty)`, where `normalized_type` is the
|
/// Returns the IntType representation.
|
||||||
/// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
|
/// This used to ensure `int_ty` doesn't contain `usize` and `isize`
|
||||||
/// and `ty` is the original type (i.e. may include `isize` or
|
/// by converting them to their actual types. That doesn't happen anymore.
|
||||||
/// `usize`).
|
pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
|
||||||
pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
|
match opt_hint {
|
||||||
-> (attr::IntType, Ty<'tcx>) {
|
|
||||||
let repr_type = match opt_hint {
|
|
||||||
// Feed in the given type
|
// Feed in the given type
|
||||||
Some(&attr::ReprInt(_, int_t)) => int_t,
|
Some(&attr::ReprInt(_, int_t)) => int_t,
|
||||||
// ... but provide sensible default if none provided
|
// ... but provide sensible default if none provided
|
||||||
@@ -280,18 +227,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
// NB. Historically `fn enum_variants` generate i64 here, while
|
// NB. Historically `fn enum_variants` generate i64 here, while
|
||||||
// rustc_typeck::check would generate isize.
|
// rustc_typeck::check would generate isize.
|
||||||
_ => SignedInt(ast::IntTy::Is),
|
_ => 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,
|
/// 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 {
|
pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
|
||||||
let hint = UncheckedExprHint(self.types.usize);
|
let hint = UncheckedExprHint(self.types.usize);
|
||||||
match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
|
match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
|
||||||
Ok(val) => {
|
Ok(ConstVal::Integral(ConstInt::Usize(count))) => {
|
||||||
let found = match val {
|
let val = count.as_u64(self.sess.target.uint_type);
|
||||||
ConstVal::Uint(count) => return count as usize,
|
assert_eq!(val as usize as u64, val);
|
||||||
ConstVal::Int(count) if count >= 0 => return count as usize,
|
val as usize
|
||||||
const_val => const_val.description(),
|
},
|
||||||
};
|
Ok(const_val) => {
|
||||||
span_err!(self.sess, count_expr.span, E0306,
|
span_err!(self.sess, count_expr.span, E0306,
|
||||||
"expected positive integer for repeat count, found {}",
|
"expected positive integer for repeat count, found {}",
|
||||||
found);
|
const_val.description());
|
||||||
|
0
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let err_msg = match count_expr.node {
|
let err_msg = match count_expr.node {
|
||||||
@@ -360,10 +297,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
};
|
};
|
||||||
span_err!(self.sess, count_expr.span, E0307,
|
span_err!(self.sess, count_expr.span, E0307,
|
||||||
"expected constant integer for repeat count, {}", err_msg);
|
"expected constant integer for repeat count, {}", err_msg);
|
||||||
}
|
|
||||||
}
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a set of predicates that apply to an object type, returns
|
/// Given a set of predicates that apply to an object type, returns
|
||||||
/// the region bounds that the (erased) `Self` type must
|
/// the region bounds that the (erased) `Self` type must
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
use graphviz::IntoCow;
|
use graphviz::IntoCow;
|
||||||
use middle::const_eval::ConstVal;
|
use middle::const_eval::ConstVal;
|
||||||
|
use rustc_const_eval::{ConstUsize, ConstInt};
|
||||||
use middle::def_id::DefId;
|
use middle::def_id::DefId;
|
||||||
use middle::subst::Substs;
|
use middle::subst::Substs;
|
||||||
use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
||||||
@@ -851,13 +852,12 @@ pub struct Constant<'tcx> {
|
|||||||
pub struct TypedConstVal<'tcx> {
|
pub struct TypedConstVal<'tcx> {
|
||||||
pub ty: Ty<'tcx>,
|
pub ty: Ty<'tcx>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub value: ConstVal
|
pub value: ConstUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for TypedConstVal<'tcx> {
|
impl<'tcx> Debug for TypedConstVal<'tcx> {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
try!(write!(fmt, "const "));
|
write!(fmt, "const {}", ConstInt::Usize(self.value))
|
||||||
fmt_const_val(fmt, &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::*;
|
use middle::const_eval::ConstVal::*;
|
||||||
match *const_val {
|
match *const_val {
|
||||||
Float(f) => write!(fmt, "{:?}", f),
|
Float(f) => write!(fmt, "{:?}", f),
|
||||||
Int(n) => write!(fmt, "{:?}", n),
|
Integral(n) => write!(fmt, "{}", n),
|
||||||
Uint(n) => write!(fmt, "{:?}", n),
|
|
||||||
Str(ref s) => write!(fmt, "{:?}", s),
|
Str(ref s) => write!(fmt, "{:?}", s),
|
||||||
ByteStr(ref bytes) => {
|
ByteStr(ref bytes) => {
|
||||||
let escaped: String = 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)),
|
Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
|
||||||
Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
|
Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
|
||||||
write!(fmt, "{}", node_to_string(node_id)),
|
write!(fmt, "{}", node_to_string(node_id)),
|
||||||
|
Char(c) => write!(fmt, "{:?}", c),
|
||||||
|
Dummy => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use mir::repr::*;
|
use mir::repr::*;
|
||||||
use middle::const_eval::ConstVal;
|
|
||||||
use middle::subst::{Subst, Substs};
|
use middle::subst::{Subst, Substs};
|
||||||
use middle::ty::{self, AdtDef, Ty, TyCtxt};
|
use middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||||
use rustc_front::hir;
|
use rustc_front::hir;
|
||||||
@@ -144,12 +143,10 @@ impl<'tcx> Mir<'tcx> {
|
|||||||
match *rvalue {
|
match *rvalue {
|
||||||
Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
|
Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
|
||||||
Rvalue::Repeat(ref operand, ref count) => {
|
Rvalue::Repeat(ref operand, ref count) => {
|
||||||
if let ConstVal::Uint(u) = count.value {
|
|
||||||
let op_ty = self.operand_ty(tcx, operand);
|
let op_ty = self.operand_ty(tcx, operand);
|
||||||
Some(tcx.mk_array(op_ty, u as usize))
|
let count = count.value.as_u64(tcx.sess.target.uint_type);
|
||||||
} else {
|
assert_eq!(count as usize as u64, count);
|
||||||
None
|
Some(tcx.mk_array(op_ty, count as usize))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Rvalue::Ref(reg, bk, ref lv) => {
|
Rvalue::Ref(reg, bk, ref lv) => {
|
||||||
let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
|
let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
|
||||||
|
|||||||
85
src/librustc_const_eval/err.rs
Normal file
85
src/librustc_const_eval/err.rs
Normal 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",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
551
src/librustc_const_eval/int.rs
Normal file
551
src/librustc_const_eval/int.rs
Normal 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)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
src/librustc_const_eval/is.rs
Normal file
39
src/librustc_const_eval/is.rs
Normal 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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/librustc_const_eval/lib.rs
Normal file
42
src/librustc_const_eval/lib.rs
Normal 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;
|
||||||
39
src/librustc_const_eval/us.rs
Normal file
39
src/librustc_const_eval/us.rs
Normal 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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -143,8 +143,11 @@ impl LateLintPass for TypeLimits {
|
|||||||
else { false }
|
else { false }
|
||||||
} else {
|
} else {
|
||||||
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
|
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
|
||||||
Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
|
Ok(ConstVal::Integral(i)) => {
|
||||||
Ok(ConstVal::Uint(shift)) => { shift >= bits },
|
i.is_negative() || i.to_u64()
|
||||||
|
.map(|i| i >= bits)
|
||||||
|
.unwrap_or(true)
|
||||||
|
},
|
||||||
_ => { false }
|
_ => { false }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ use middle::subst;
|
|||||||
use middle::ty::{ImplContainer, TraitContainer};
|
use middle::ty::{ImplContainer, TraitContainer};
|
||||||
use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
|
use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
|
||||||
|
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
|
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::mir::visit::MutVisitor;
|
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)
|
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::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
|
||||||
reader::with_doc_data(val_doc, |data| {
|
reader::with_doc_data(val_doc, |data| {
|
||||||
str::from_utf8(data).ok().and_then(|s| s.parse().ok())
|
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,
|
did: did,
|
||||||
name: item_name(intr, item),
|
name: item_name(intr, item),
|
||||||
fields: get_variant_fields(intr, cdata, item, tcx),
|
fields: get_variant_fields(intr, cdata, item, tcx),
|
||||||
disr_val: disr,
|
disr_val: ConstInt::Infer(disr),
|
||||||
kind: expect_variant_kind(item_family(item), tcx),
|
kind: expect_variant_kind(item_family(item), tcx),
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
@@ -432,7 +434,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
|
|||||||
did: did,
|
did: did,
|
||||||
name: item_name(intr, doc),
|
name: item_name(intr, doc),
|
||||||
fields: get_variant_fields(intr, cdata, doc, tcx),
|
fields: get_variant_fields(intr, cdata, doc, tcx),
|
||||||
disr_val: 0,
|
disr_val: ConstInt::Infer(0),
|
||||||
kind: expect_variant_kind(item_family(doc), tcx),
|
kind: expect_variant_kind(item_family(doc), tcx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use middle::dependency_format::Linkage;
|
|||||||
use middle::stability;
|
use middle::stability;
|
||||||
use middle::subst;
|
use middle::subst;
|
||||||
use middle::ty::{self, Ty, TyCtxt};
|
use middle::ty::{self, Ty, TyCtxt};
|
||||||
|
use middle::ty::util::IntTypeExt;
|
||||||
|
|
||||||
use rustc::back::svh::Svh;
|
use rustc::back::svh::Svh;
|
||||||
use rustc::front::map::{LinkedPath, PathElem, PathElems};
|
use rustc::front::map::{LinkedPath, PathElem, PathElems};
|
||||||
@@ -238,7 +239,8 @@ fn encode_symbol(ecx: &EncodeContext,
|
|||||||
fn encode_disr_val(_: &EncodeContext,
|
fn encode_disr_val(_: &EncodeContext,
|
||||||
rbml_w: &mut Encoder,
|
rbml_w: &mut Encoder,
|
||||||
disr_val: ty::Disr) {
|
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) {
|
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>,
|
fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
||||||
rbml_w: &mut Encoder,
|
rbml_w: &mut Encoder,
|
||||||
id: NodeId,
|
did: DefId,
|
||||||
vis: hir::Visibility,
|
vis: hir::Visibility,
|
||||||
index: &mut CrateIndex<'tcx>) {
|
index: &mut CrateIndex<'tcx>) {
|
||||||
debug!("encode_enum_variant_info(id={})", id);
|
debug!("encode_enum_variant_info(did={:?})", did);
|
||||||
|
let repr_hints = ecx.tcx.lookup_repr_hints(did);
|
||||||
let mut disr_val = 0;
|
let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
|
||||||
let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id));
|
let mut disr_val = repr_type.initial_discriminant(&ecx.tcx);
|
||||||
|
let def = ecx.tcx.lookup_adt_def(did);
|
||||||
for variant in &def.variants {
|
for variant in &def.variants {
|
||||||
let vid = variant.did;
|
let vid = variant.did;
|
||||||
let variant_node_id = ecx.local_id(vid);
|
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',
|
ty::VariantKind::Unit => 'w',
|
||||||
});
|
});
|
||||||
encode_name(rbml_w, variant.name);
|
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);
|
encode_visibility(rbml_w, vis);
|
||||||
|
|
||||||
let attrs = ecx.tcx.get_attrs(vid);
|
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));
|
ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path));
|
||||||
rbml_w.end_tag();
|
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,
|
encode_enum_variant_info(ecx,
|
||||||
rbml_w,
|
rbml_w,
|
||||||
item.id,
|
def_id,
|
||||||
vis,
|
vis,
|
||||||
index);
|
index);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ extern crate rustc;
|
|||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
extern crate rustc_front;
|
extern crate rustc_front;
|
||||||
extern crate rustc_llvm;
|
extern crate rustc_llvm;
|
||||||
|
extern crate rustc_const_eval;
|
||||||
|
|
||||||
pub use rustc::middle;
|
pub use rustc::middle;
|
||||||
|
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ enum TestKind<'tcx> {
|
|||||||
|
|
||||||
// test length of the slice is equal to len
|
// test length of the slice is equal to len
|
||||||
Len {
|
Len {
|
||||||
len: usize,
|
len: u64,
|
||||||
op: BinOp,
|
op: BinOp,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
};
|
};
|
||||||
Test {
|
Test {
|
||||||
span: match_pair.pattern.span,
|
span: match_pair.pattern.span,
|
||||||
kind: TestKind::Len { len: len, op: op },
|
kind: TestKind::Len { len: len as u64, op: op },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
Operand::Constant(constant)
|
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 usize_ty = self.hir.usize_ty();
|
||||||
let temp = self.temp(usize_ty);
|
let temp = self.temp(usize_ty);
|
||||||
self.cfg.push_assign_constant(
|
self.cfg.push_assign_constant(
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
|
|||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use syntax::codemap::{Span, DUMMY_SP};
|
use syntax::codemap::{Span, DUMMY_SP};
|
||||||
use syntax::parse::token::intern_and_get_ident;
|
use syntax::parse::token::intern_and_get_ident;
|
||||||
|
use rustc::middle::const_eval::ConstVal;
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
|
|
||||||
pub struct Scope<'tcx> {
|
pub struct Scope<'tcx> {
|
||||||
extent: CodeExtent,
|
extent: CodeExtent,
|
||||||
@@ -517,7 +519,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||||||
}, Constant {
|
}, Constant {
|
||||||
span: span,
|
span: span,
|
||||||
ty: self.hir.tcx().types.u32,
|
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)),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,13 @@
|
|||||||
|
|
||||||
use hair::*;
|
use hair::*;
|
||||||
use rustc_data_structures::fnv::FnvHashMap;
|
use rustc_data_structures::fnv::FnvHashMap;
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
use hair::cx::Cx;
|
use hair::cx::Cx;
|
||||||
use hair::cx::block;
|
use hair::cx::block;
|
||||||
use hair::cx::to_ref::ToRef;
|
use hair::cx::to_ref::ToRef;
|
||||||
use rustc::front::map;
|
use rustc::front::map;
|
||||||
use rustc::middle::def::Def;
|
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::region::CodeExtent;
|
||||||
use rustc::middle::pat_util;
|
use rustc::middle::pat_util;
|
||||||
use rustc::middle::ty::{self, VariantDef, Ty};
|
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) {
|
if cx.tcx.is_method_call(self.id) {
|
||||||
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
|
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
|
||||||
PassArgs::ByValue, arg.to_ref(), vec![])
|
PassArgs::ByValue, arg.to_ref(), vec![])
|
||||||
} else {
|
} 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 {
|
ExprKind::Unary {
|
||||||
op: op,
|
op: UnOp::Not,
|
||||||
arg: arg.to_ref(),
|
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) => {
|
hir::ExprStruct(_, ref fields, ref base) => {
|
||||||
match expr_ty.sty {
|
match expr_ty.sty {
|
||||||
ty::TyStruct(adt, substs) => {
|
ty::TyStruct(adt, substs) => {
|
||||||
@@ -338,7 +348,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
|||||||
count: TypedConstVal {
|
count: TypedConstVal {
|
||||||
ty: cx.tcx.expr_ty(c),
|
ty: cx.tcx.expr_ty(c),
|
||||||
span: c.span,
|
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) =>
|
hir::ExprRet(ref v) =>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
|
|||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
use rustc_front::hir;
|
use rustc_front::hir;
|
||||||
|
use rustc_const_eval::{ConstInt, ConstUsize};
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Cx<'a, 'tcx: 'a> {
|
pub struct Cx<'a, 'tcx: 'a> {
|
||||||
@@ -50,8 +51,11 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
|
|||||||
self.tcx.types.usize
|
self.tcx.types.usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
|
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
|
||||||
Literal::Value { value: ConstVal::Uint(value as u64) }
|
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> {
|
pub fn bool_ty(&mut self) -> Ty<'tcx> {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ extern crate rustc_data_structures;
|
|||||||
extern crate rustc_front;
|
extern crate rustc_front;
|
||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
extern crate rustc_const_eval;
|
||||||
|
|
||||||
pub mod build;
|
pub mod build;
|
||||||
pub mod graphviz;
|
pub mod graphviz;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ pub extern crate rustc_llvm as llvm;
|
|||||||
extern crate rustc_mir;
|
extern crate rustc_mir;
|
||||||
extern crate rustc_platform_intrinsics as intrinsics;
|
extern crate rustc_platform_intrinsics as intrinsics;
|
||||||
extern crate serialize;
|
extern crate serialize;
|
||||||
|
extern crate rustc_const_eval;
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate syntax;
|
#[macro_use] extern crate syntax;
|
||||||
|
|||||||
@@ -1035,7 +1035,7 @@ fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
|
|||||||
match ity {
|
match ity {
|
||||||
attr::UnsignedInt(_) => {
|
attr::UnsignedInt(_) => {
|
||||||
assert!(min <= discr);
|
assert!(min <= discr);
|
||||||
assert!(discr <= max)
|
assert!(discr <= max);
|
||||||
},
|
},
|
||||||
attr::SignedInt(_) => {
|
attr::SignedInt(_) => {
|
||||||
assert!(min.0 as i64 <= discr.0 as i64);
|
assert!(min.0 as i64 <= discr.0 as i64);
|
||||||
|
|||||||
@@ -15,15 +15,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
|
|||||||
use llvm::{InternalLinkage, ValueRef, Bool, True};
|
use llvm::{InternalLinkage, ValueRef, Bool, True};
|
||||||
use middle::const_qualif::ConstQualif;
|
use middle::const_qualif::ConstQualif;
|
||||||
use middle::cstore::LOCAL_CRATE;
|
use middle::cstore::LOCAL_CRATE;
|
||||||
use middle::const_eval::{self, ConstVal, ConstEvalErr};
|
use middle::const_eval::{self, 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::def::Def;
|
use middle::def::Def;
|
||||||
use middle::def_id::DefId;
|
use middle::def_id::DefId;
|
||||||
use trans::{adt, closure, debuginfo, expr, inline, machine};
|
use trans::{adt, closure, debuginfo, expr, inline, machine};
|
||||||
@@ -42,9 +34,10 @@ use trans::Disr;
|
|||||||
use middle::subst::Substs;
|
use middle::subst::Substs;
|
||||||
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
|
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
|
||||||
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
|
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty, TyCtxt};
|
||||||
use middle::ty::cast::{CastTy,IntTy};
|
use middle::ty::cast::{CastTy,IntTy};
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
|
use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize};
|
||||||
|
|
||||||
use rustc_front::hir;
|
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,
|
// Catch this up front by looking for ExprLit directly,
|
||||||
// and just accepting it.
|
// and just accepting it.
|
||||||
if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
|
if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
|
||||||
|
let cval = match to_const_int(te, t, cx.tcx()) {
|
||||||
let result = match t.sty {
|
|
||||||
ty::TyInt(int_type) => {
|
|
||||||
let input = match const_to_opt_int(te) {
|
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
const_int_checked_neg(
|
match -cval {
|
||||||
input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
|
Ok(_) => return Ok(()),
|
||||||
|
Err(err) => const_err(cx, e, Err(err), trueconst),
|
||||||
}
|
}
|
||||||
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(()),
|
|
||||||
};
|
|
||||||
const_err(cx, e, result, trueconst)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
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,
|
fn const_err(cx: &CrateContext,
|
||||||
e: &hir::Expr,
|
e: &hir::Expr,
|
||||||
result: Result<ConstVal, ConstEvalErr>,
|
result: Result<ConstInt, ConstMathErr>,
|
||||||
trueconst: TrueConst)
|
trueconst: TrueConst)
|
||||||
-> Result<(), ConstEvalFailure> {
|
-> Result<(), ConstEvalFailure> {
|
||||||
match (result, trueconst) {
|
match (result, trueconst) {
|
||||||
@@ -506,10 +534,12 @@ fn const_err(cx: &CrateContext,
|
|||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
(Err(err), TrueConst::Yes) => {
|
(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());
|
cx.tcx().sess.span_err(e.span, &err.description());
|
||||||
Err(Compiletime(err))
|
Err(Compiletime(err))
|
||||||
},
|
},
|
||||||
(Err(err), TrueConst::No) => {
|
(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());
|
cx.tcx().sess.span_warn(e.span, &err.description());
|
||||||
Err(Runtime(err))
|
Err(Runtime(err))
|
||||||
},
|
},
|
||||||
@@ -520,46 +550,18 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
|
|||||||
te1: ValueRef, te2: ValueRef,
|
te1: ValueRef, te2: ValueRef,
|
||||||
trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
|
trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
|
||||||
let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() };
|
let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() };
|
||||||
|
let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) {
|
||||||
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),
|
(Some(v1), Some(v2)) => (v1, v2),
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
|
let result = match b.node {
|
||||||
let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
|
hir::BiAdd => lhs + rhs,
|
||||||
match b.node {
|
hir::BiSub => lhs - rhs,
|
||||||
hir::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
|
hir::BiMul => lhs * rhs,
|
||||||
hir::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
|
hir::BiDiv => lhs / rhs,
|
||||||
hir::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
|
hir::BiRem => lhs % rhs,
|
||||||
hir::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
|
hir::BiShl => lhs << rhs,
|
||||||
hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
|
hir::BiShr => lhs >> rhs,
|
||||||
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(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => return Ok(()),
|
_ => return Ok(()),
|
||||||
};
|
};
|
||||||
const_err(cx, e, result, trueconst)
|
const_err(cx, e, result, trueconst)
|
||||||
|
|||||||
@@ -1597,7 +1597,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
llvm::LLVMDIBuilderCreateEnumerator(
|
llvm::LLVMDIBuilderCreateEnumerator(
|
||||||
DIB(cx),
|
DIB(cx),
|
||||||
name.as_ptr(),
|
name.as_ptr(),
|
||||||
v.disr_val as u64)
|
v.disr_val.to_u64_unchecked())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ impl ::std::ops::BitAnd for Disr {
|
|||||||
|
|
||||||
impl From<::middle::ty::Disr> for Disr {
|
impl From<::middle::ty::Disr> for Disr {
|
||||||
fn from(i: ::middle::ty::Disr) -> Disr {
|
fn from(i: ::middle::ty::Disr) -> Disr {
|
||||||
Disr(i)
|
Disr(i.to_u64_unchecked())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use back::abi;
|
|||||||
use llvm::ValueRef;
|
use llvm::ValueRef;
|
||||||
use middle::ty::{Ty, TypeFoldable};
|
use middle::ty::{Ty, TypeFoldable};
|
||||||
use rustc::middle::const_eval::{self, ConstVal};
|
use rustc::middle::const_eval::{self, ConstVal};
|
||||||
|
use rustc_const_eval::ConstInt::*;
|
||||||
use rustc::mir::repr as mir;
|
use rustc::mir::repr as mir;
|
||||||
use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
|
use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
|
||||||
C_str_slice, C_nil, C_undef};
|
C_str_slice, C_nil, C_undef};
|
||||||
@@ -19,6 +20,7 @@ use trans::consts;
|
|||||||
use trans::expr;
|
use trans::expr;
|
||||||
use trans::inline;
|
use trans::inline;
|
||||||
use trans::type_of;
|
use trans::type_of;
|
||||||
|
use trans::type_::Type;
|
||||||
|
|
||||||
use super::operand::{OperandRef, OperandValue};
|
use super::operand::{OperandRef, OperandValue};
|
||||||
use super::MirContext;
|
use super::MirContext;
|
||||||
@@ -63,8 +65,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
match *cv {
|
match *cv {
|
||||||
ConstVal::Float(v) => C_floating_f64(v, llty),
|
ConstVal::Float(v) => C_floating_f64(v, llty),
|
||||||
ConstVal::Bool(v) => C_bool(ccx, v),
|
ConstVal::Bool(v) => C_bool(ccx, v),
|
||||||
ConstVal::Int(v) => C_integral(llty, v as u64, true),
|
ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
|
||||||
ConstVal::Uint(v) => C_integral(llty, v, false),
|
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::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::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
|
||||||
ConstVal::Struct(id) | ConstVal::Tuple(id) |
|
ConstVal::Struct(id) | ConstVal::Tuple(id) |
|
||||||
@@ -74,6 +92,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
expr::trans(bcx, expr).datum.val
|
expr::trans(bcx, expr).datum.val
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
|
||||||
ConstVal::Function(_) => C_nil(ccx)
|
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 substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
|
||||||
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
|
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))
|
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,
|
// 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.
|
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
|
||||||
let d = bcx.with_block(|bcx| {
|
let d = bcx.with_block(|bcx| {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@
|
|||||||
use llvm::ValueRef;
|
use llvm::ValueRef;
|
||||||
use rustc::middle::ty::{self, Ty};
|
use rustc::middle::ty::{self, Ty};
|
||||||
use middle::ty::cast::{CastTy, IntTy};
|
use middle::ty::cast::{CastTy, IntTy};
|
||||||
|
use middle::const_eval::ConstVal;
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
use rustc::mir::repr as mir;
|
use rustc::mir::repr as mir;
|
||||||
|
|
||||||
use trans::asm;
|
use trans::asm;
|
||||||
@@ -95,7 +97,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||||||
|
|
||||||
mir::Rvalue::Repeat(ref elem, ref count) => {
|
mir::Rvalue::Repeat(ref elem, ref count) => {
|
||||||
let tr_elem = self.trans_operand(&bcx, elem);
|
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 bcx = bcx.map_block(|block| {
|
||||||
let base = expr::get_dataptr(block, dest.llval);
|
let base = expr::get_dataptr(block, dest.llval);
|
||||||
tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
|
tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
|||||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||||
use util::nodemap::FnvHashSet;
|
use util::nodemap::FnvHashSet;
|
||||||
|
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
|
|
||||||
use syntax::{abi, ast};
|
use syntax::{abi, ast};
|
||||||
use syntax::codemap::{Span, Pos};
|
use syntax::codemap::{Span, Pos};
|
||||||
use syntax::errors::DiagnosticBuilder;
|
use syntax::errors::DiagnosticBuilder;
|
||||||
@@ -1680,22 +1682,16 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
|
|||||||
hir::TyFixedLengthVec(ref ty, ref e) => {
|
hir::TyFixedLengthVec(ref ty, ref e) => {
|
||||||
let hint = UncheckedExprHint(tcx.types.usize);
|
let hint = UncheckedExprHint(tcx.types.usize);
|
||||||
match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
|
match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
|
||||||
Ok(r) => {
|
Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
|
||||||
match r {
|
let i = i.as_u64(tcx.sess.target.uint_type);
|
||||||
ConstVal::Int(i) =>
|
assert_eq!(i as usize as u64, i);
|
||||||
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
|
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty), i as usize)
|
||||||
i as usize),
|
},
|
||||||
ConstVal::Uint(i) =>
|
Ok(val) => {
|
||||||
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
|
|
||||||
i as usize),
|
|
||||||
_ => {
|
|
||||||
span_err!(tcx.sess, ast_ty.span, E0249,
|
span_err!(tcx.sess, ast_ty.span, E0249,
|
||||||
"expected constant integer expression \
|
"expected usize value for array length, got {}", val.description());
|
||||||
for array length");
|
|
||||||
this.tcx().types.err
|
this.tcx().types.err
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(ref r) => {
|
Err(ref r) => {
|
||||||
let mut err = struct_span_err!(tcx.sess, r.span, E0250,
|
let mut err = struct_span_err!(tcx.sess, r.span, E0250,
|
||||||
"array length constant evaluation error: {}",
|
"array length constant evaluation error: {}",
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ use middle::pat_util::{self, pat_id_map};
|
|||||||
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
|
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
|
||||||
use middle::traits::{self, report_fulfillment_errors};
|
use middle::traits::{self, report_fulfillment_errors};
|
||||||
use middle::ty::{GenericPredicates, TypeScheme};
|
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::{LvaluePreference, NoPreference, PreferMutLvalue};
|
||||||
use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
|
use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
|
||||||
use middle::ty::{MethodCall, MethodCallee};
|
use middle::ty::{MethodCall, MethodCallee};
|
||||||
@@ -102,7 +102,7 @@ use middle::ty::adjustment;
|
|||||||
use middle::ty::error::TypeError;
|
use middle::ty::error::TypeError;
|
||||||
use middle::ty::fold::{TypeFolder, TypeFoldable};
|
use middle::ty::fold::{TypeFolder, TypeFoldable};
|
||||||
use middle::ty::relate::TypeRelation;
|
use middle::ty::relate::TypeRelation;
|
||||||
use middle::ty::util::Representability;
|
use middle::ty::util::{Representability, IntTypeExt};
|
||||||
use require_c_abi_if_variadic;
|
use require_c_abi_if_variadic;
|
||||||
use rscope::{ElisionFailureInfo, RegionScope};
|
use rscope::{ElisionFailureInfo, RegionScope};
|
||||||
use session::{Session, CompileResult};
|
use session::{Session, CompileResult};
|
||||||
@@ -4076,34 +4076,6 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||||||
sp: Span,
|
sp: Span,
|
||||||
vs: &'tcx [hir::Variant],
|
vs: &'tcx [hir::Variant],
|
||||||
id: ast::NodeId) {
|
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>,
|
fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||||
vs: &'tcx [hir::Variant],
|
vs: &'tcx [hir::Variant],
|
||||||
id: ast::NodeId,
|
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 inh = static_inherited_fields(ccx, &tables);
|
||||||
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
|
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 {
|
for v in vs {
|
||||||
if let Some(ref e) = v.node.disr_expr {
|
if let Some(ref e) = v.node.disr_expr {
|
||||||
check_const_with_ty(&fcx, e.span, e, repr_type_ty);
|
check_const_with_ty(&fcx, e.span, e, repr_type_ty);
|
||||||
@@ -4142,24 +4114,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
// Check for unrepresentable discriminant values
|
|
||||||
match hint {
|
|
||||||
attr::ReprAny | attr::ReprExtern => {
|
|
||||||
disr_vals.push(current_disr_val);
|
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 => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let def_id = ccx.tcx.map.local_def_id(id);
|
let def_id = ccx.tcx.map.local_def_id(id);
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ use util::common::{ErrorReported, MemoizationMap};
|
|||||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||||
use write_ty_to_tcx;
|
use write_ty_to_tcx;
|
||||||
|
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -1021,7 +1023,7 @@ fn convert_struct_def<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
tcx.intern_adt_def(
|
tcx.intern_adt_def(
|
||||||
did,
|
did,
|
||||||
ty::AdtKind::Struct,
|
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)
|
def: &hir::EnumDef)
|
||||||
-> ty::AdtDefMaster<'tcx>
|
-> 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>,
|
fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||||
repr_ty: Ty<'tcx>,
|
repr_ty: attr::IntType,
|
||||||
e: &hir::Expr) -> Option<ty::Disr> {
|
e: &hir::Expr) -> Option<ty::Disr> {
|
||||||
debug!("disr expr, checking {}", pprust::expr_to_string(e));
|
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) {
|
match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
|
||||||
Ok(ConstVal::Int(val)) => Some(val as ty::Disr),
|
Ok(ConstVal::Integral(i)) => {
|
||||||
Ok(ConstVal::Uint(val)) => Some(val as ty::Disr),
|
// FIXME: eval_const_expr_partial should return an error if the hint is wrong
|
||||||
Ok(_) => {
|
match (repr_ty, i) {
|
||||||
let sign_desc = if repr_ty.is_signed() {
|
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => Some(i),
|
||||||
"signed"
|
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => Some(i),
|
||||||
} else {
|
(attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => Some(i),
|
||||||
"unsigned"
|
(attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => Some(i),
|
||||||
};
|
(attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => Some(i),
|
||||||
span_err!(tcx.sess, e.span, E0079,
|
(attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => Some(i),
|
||||||
"expected {} integer constant",
|
(attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => Some(i),
|
||||||
sign_desc);
|
(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
|
None
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -1066,16 +1083,11 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
fn report_discrim_overflow(tcx: &TyCtxt,
|
fn report_discrim_overflow(tcx: &TyCtxt,
|
||||||
variant_span: Span,
|
variant_span: Span,
|
||||||
variant_name: &str,
|
variant_name: &str,
|
||||||
repr_type: attr::IntType,
|
|
||||||
prev_val: ty::Disr) {
|
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,
|
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",
|
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,
|
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 {
|
if let Some(prev_disr_val) = prev_disr_val {
|
||||||
let result = repr_type.disr_incr(prev_disr_val);
|
let result = repr_type.disr_incr(prev_disr_val);
|
||||||
if let None = result {
|
if let None = result {
|
||||||
report_discrim_overflow(tcx, v.span, &v.node.name.as_str(),
|
report_discrim_overflow(tcx, v.span, &v.node.name.as_str(), prev_disr_val);
|
||||||
repr_type, prev_disr_val);
|
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
Some(ty::INITIAL_DISCRIMINANT_VALUE)
|
Some(repr_type.initial_discriminant(tcx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn convert_enum_variant<'tcx>(tcx: &TyCtxt<'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 did = tcx.map.local_def_id(it.id);
|
||||||
let repr_hints = tcx.lookup_repr_hints(did);
|
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 mut prev_disr = None;
|
||||||
let variants = def.variants.iter().map(|v| {
|
let variants = def.variants.iter().map(|v| {
|
||||||
let disr = match v.node.disr_expr {
|
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)
|
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);
|
prev_disr = Some(disr);
|
||||||
v
|
convert_enum_variant(tcx, v, disr)
|
||||||
}).collect();
|
}).collect();
|
||||||
tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
|
tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ extern crate rustc;
|
|||||||
extern crate rustc_platform_intrinsics as intrinsics;
|
extern crate rustc_platform_intrinsics as intrinsics;
|
||||||
extern crate rustc_front;
|
extern crate rustc_front;
|
||||||
extern crate rustc_back;
|
extern crate rustc_back;
|
||||||
|
extern crate rustc_const_eval;
|
||||||
|
|
||||||
pub use rustc::dep_graph;
|
pub use rustc::dep_graph;
|
||||||
pub use rustc::front;
|
pub use rustc::front;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#[macro_use] extern crate rustc;
|
#[macro_use] extern crate rustc;
|
||||||
extern crate rustc_front;
|
extern crate rustc_front;
|
||||||
extern crate rustc_plugin;
|
extern crate rustc_plugin;
|
||||||
|
extern crate rustc_const_eval;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::MirPass;
|
||||||
@@ -23,6 +24,7 @@ use rustc::mir::repr::{Mir, Literal};
|
|||||||
use rustc::mir::visit::MutVisitor;
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::middle::infer::InferCtxt;
|
use rustc::middle::infer::InferCtxt;
|
||||||
use rustc::middle::const_eval::ConstVal;
|
use rustc::middle::const_eval::ConstVal;
|
||||||
|
use rustc_const_eval::ConstInt;
|
||||||
use rustc_plugin::Registry;
|
use rustc_plugin::Registry;
|
||||||
|
|
||||||
struct Pass;
|
struct Pass;
|
||||||
@@ -37,10 +39,12 @@ struct Visitor;
|
|||||||
|
|
||||||
impl<'tcx> MutVisitor<'tcx> for Visitor {
|
impl<'tcx> MutVisitor<'tcx> for Visitor {
|
||||||
fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
|
fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
|
||||||
if let Literal::Value { value: ConstVal::Int(ref mut i @ 11) } = *literal {
|
if let Literal::Value { ref mut value } = *literal {
|
||||||
|
if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
|
||||||
*i = 42;
|
*i = 42;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[plugin_registrar]
|
#[plugin_registrar]
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ fn main() {
|
|||||||
//~^ WARN attempted to add with overflow
|
//~^ WARN attempted to add with overflow
|
||||||
//~^^ WARN attempted to add with overflow
|
//~^^ WARN attempted to add with overflow
|
||||||
let c = 200u8 * 4;
|
let c = 200u8 * 4;
|
||||||
//~^ WARN attempted to mul with overflow
|
//~^ WARN attempted to multiply with overflow
|
||||||
let d = 42u8 - (42u8 + 1);
|
let d = 42u8 - (42u8 + 1);
|
||||||
//~^ WARN attempted to sub with overflow
|
//~^ WARN attempted to subtract with overflow
|
||||||
let _e = BLA;
|
let _e = BLA;
|
||||||
black_box(a);
|
black_box(a);
|
||||||
black_box(b);
|
black_box(b);
|
||||||
|
|||||||
@@ -21,10 +21,11 @@ const NEG_128: i8 = -128;
|
|||||||
const NEG_NEG_128: i8 = -NEG_128;
|
const NEG_NEG_128: i8 = -NEG_128;
|
||||||
//~^ ERROR constant evaluation error: attempted to negate with overflow
|
//~^ ERROR constant evaluation error: attempted to negate with overflow
|
||||||
//~| ERROR attempted to negate with overflow
|
//~| ERROR attempted to negate with overflow
|
||||||
|
//~| ERROR attempted to negate with overflow
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
match -128i8 {
|
match -128i8 {
|
||||||
NEG_NEG_128 => println!("A"),
|
NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
|
||||||
_ => println!("B"),
|
_ => println!("B"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
// self-hosted and a cross-compiled setup; therefore resorting to
|
// self-hosted and a cross-compiled setup; therefore resorting to
|
||||||
// error-pattern for now.
|
// 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)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
@@ -36,4 +36,3 @@ fn main() {
|
|||||||
fn foo<T:fmt::Debug>(x: T) {
|
fn foo<T:fmt::Debug>(x: T) {
|
||||||
println!("{:?}", x);
|
println!("{:?}", x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ use std::{u8, u16, u32, u64, usize};
|
|||||||
|
|
||||||
const A_I8_T
|
const A_I8_T
|
||||||
: [u32; (i8::MAX as i8 + 1u8) as usize]
|
: [u32; (i8::MAX as i8 + 1u8) as usize]
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR tried to add two integrals of different types [E0250]
|
||||||
//~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
|
|
||||||
= [0; (i8::MAX as usize) + 1];
|
= [0; (i8::MAX as usize) + 1];
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -23,84 +23,84 @@ const VALS_I8: (i8, i8, i8, i8) =
|
|||||||
(-i8::MIN,
|
(-i8::MIN,
|
||||||
//~^ ERROR attempted to negate with overflow
|
//~^ ERROR attempted to negate with overflow
|
||||||
i8::MIN - 1,
|
i8::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
i8::MAX + 1,
|
i8::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
i8::MIN * 2,
|
i8::MIN * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
const VALS_I16: (i16, i16, i16, i16) =
|
const VALS_I16: (i16, i16, i16, i16) =
|
||||||
(-i16::MIN,
|
(-i16::MIN,
|
||||||
//~^ ERROR attempted to negate with overflow
|
//~^ ERROR attempted to negate with overflow
|
||||||
i16::MIN - 1,
|
i16::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
i16::MAX + 1,
|
i16::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
i16::MIN * 2,
|
i16::MIN * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
const VALS_I32: (i32, i32, i32, i32) =
|
const VALS_I32: (i32, i32, i32, i32) =
|
||||||
(-i32::MIN,
|
(-i32::MIN,
|
||||||
//~^ ERROR attempted to negate with overflow
|
//~^ ERROR attempted to negate with overflow
|
||||||
i32::MIN - 1,
|
i32::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
i32::MAX + 1,
|
i32::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
i32::MIN * 2,
|
i32::MIN * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
const VALS_I64: (i64, i64, i64, i64) =
|
const VALS_I64: (i64, i64, i64, i64) =
|
||||||
(-i64::MIN,
|
(-i64::MIN,
|
||||||
//~^ ERROR attempted to negate with overflow
|
//~^ ERROR attempted to negate with overflow
|
||||||
i64::MIN - 1,
|
i64::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
i64::MAX + 1,
|
i64::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
i64::MAX * 2,
|
i64::MAX * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
const VALS_U8: (u8, u8, u8, u8) =
|
const VALS_U8: (u8, u8, u8, u8) =
|
||||||
(-(u8::MIN as i8) as u8,
|
(-(u8::MIN as i8) as u8,
|
||||||
u8::MIN - 1,
|
u8::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
u8::MAX + 1,
|
u8::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
u8::MAX * 2,
|
u8::MAX * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
const VALS_U16: (u16, u16, u16, u16) =
|
const VALS_U16: (u16, u16, u16, u16) =
|
||||||
(-(u16::MIN as i16) as u16,
|
(-(u16::MIN as i16) as u16,
|
||||||
u16::MIN - 1,
|
u16::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
u16::MAX + 1,
|
u16::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
u16::MAX * 2,
|
u16::MAX * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
const VALS_U32: (u32, u32, u32, u32) =
|
const VALS_U32: (u32, u32, u32, u32) =
|
||||||
(-(u32::MIN as i32) as u32,
|
(-(u32::MIN as i32) as u32,
|
||||||
u32::MIN - 1,
|
u32::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
u32::MAX + 1,
|
u32::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
u32::MAX * 2,
|
u32::MAX * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
const VALS_U64: (u64, u64, u64, u64) =
|
const VALS_U64: (u64, u64, u64, u64) =
|
||||||
(-(u64::MIN as i64) as u64,
|
(-(u64::MIN as i64) as u64,
|
||||||
u64::MIN - 1,
|
u64::MIN - 1,
|
||||||
//~^ ERROR attempted to sub with overflow
|
//~^ ERROR attempted to subtract with overflow
|
||||||
u64::MAX + 1,
|
u64::MAX + 1,
|
||||||
//~^ ERROR attempted to add with overflow
|
//~^ ERROR attempted to add with overflow
|
||||||
u64::MAX * 2,
|
u64::MAX * 2,
|
||||||
//~^ ERROR attempted to mul with overflow
|
//~^ ERROR attempted to multiply with overflow
|
||||||
);
|
);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -8,32 +8,30 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
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 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
|
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: unary negation of unsigned integer
|
||||||
const X2: usize = -42 || -39; //~ ERROR: can't do this op on unsigned integrals
|
|
||||||
const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
|
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: unary negation of unsigned integer
|
||||||
const X3: usize = -42 && -39; //~ ERROR: can't do this op on unsigned integrals
|
|
||||||
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
|
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
|
||||||
|
|
||||||
const Y: usize = 42.0 == 42.0;
|
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 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 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 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 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 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() {
|
fn main() {
|
||||||
let _ = ARR;
|
let _ = ARR;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
const ONE: usize = 1;
|
const ONE: usize = 1;
|
||||||
const TWO: usize = 2;
|
const TWO: usize = 2;
|
||||||
const LEN: usize = ONE - TWO;
|
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() {
|
fn main() {
|
||||||
let a: [i8; LEN] = unimplemented!();
|
let a: [i8; LEN] = unimplemented!();
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ const TWO: usize = 2;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a: [i8; ONE - TWO] = unimplemented!();
|
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]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
// Test spans of errors
|
// Test spans of errors
|
||||||
|
|
||||||
const TUP: (usize,) = 5 << 64;
|
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] = [];
|
const ARR: [i32; TUP.0] = [];
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ fn f_i8() {
|
|||||||
enum A {
|
enum A {
|
||||||
Ok = i8::MAX - 1,
|
Ok = i8::MAX - 1,
|
||||||
Ok2,
|
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 {
|
enum A {
|
||||||
Ok = u8::MAX - 1,
|
Ok = u8::MAX - 1,
|
||||||
Ok2,
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ fn f_i8() {
|
|||||||
enum A {
|
enum A {
|
||||||
Ok = i8::MAX - 1,
|
Ok = i8::MAX - 1,
|
||||||
Ok2,
|
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;
|
let x = A::Ok;
|
||||||
@@ -33,7 +33,7 @@ fn f_u8() {
|
|||||||
enum A {
|
enum A {
|
||||||
Ok = u8::MAX - 1,
|
Ok = u8::MAX - 1,
|
||||||
Ok2,
|
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;
|
let x = A::Ok;
|
||||||
|
|||||||
@@ -9,46 +9,32 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
|
||||||
#[repr(u8)] //~ NOTE discriminant type specified here
|
#[repr(u8)]
|
||||||
enum Eu8 {
|
enum Eu8 {
|
||||||
Au8 = 23,
|
Au8 = 23,
|
||||||
Bu8 = 223,
|
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
|
#[repr(u16)]
|
||||||
enum Ei8 {
|
|
||||||
Ai8 = 23,
|
|
||||||
Bi8 = -23,
|
|
||||||
Ci8 = 223, //~ ERROR discriminant value outside specified type
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u16)] //~ NOTE discriminant type specified here
|
|
||||||
enum Eu16 {
|
enum Eu16 {
|
||||||
Au16 = 23,
|
Au16 = 23,
|
||||||
Bu16 = 55555,
|
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
|
#[repr(u32)]
|
||||||
enum Ei16 {
|
|
||||||
Ai16 = 23,
|
|
||||||
Bi16 = -22333,
|
|
||||||
Ci16 = 55555, //~ ERROR discriminant value outside specified type
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u32)] //~ NOTE discriminant type specified here
|
|
||||||
enum Eu32 {
|
enum Eu32 {
|
||||||
Au32 = 23,
|
Au32 = 23,
|
||||||
Bu32 = 3_000_000_000,
|
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
|
#[repr(u64)]
|
||||||
enum Ei32 {
|
enum Eu64 {
|
||||||
Ai32 = 23,
|
Au32 = 23,
|
||||||
Bi32 = -2_000_000_000,
|
Bu32 = 3_000_000_000,
|
||||||
Ci32 = 3_000_000_000, //~ ERROR discriminant value outside specified type
|
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
|
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
|
||||||
|
|||||||
44
src/test/compile-fail/enum-discrim-too-small2.rs
Normal file
44
src/test/compile-fail/enum-discrim-too-small2.rs
Normal 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() { }
|
||||||
@@ -10,7 +10,8 @@
|
|||||||
|
|
||||||
enum test {
|
enum test {
|
||||||
div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
|
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() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -21,22 +21,7 @@ const _MAX: usize = -1;
|
|||||||
//~| HELP use a cast or the `!` operator
|
//~| HELP use a cast or the `!` operator
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = -1;
|
let x = 5u8;
|
||||||
//~^ ERROR unary negation of unsigned integer
|
let _y = -x; //~ 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
|
|
||||||
|
|
||||||
-S; // should not trigger the gate; issue 26840
|
-S; // should not trigger the gate; issue 26840
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/test/compile-fail/feature-gate-negate-unsigned0.rs
Normal file
31
src/test/compile-fail/feature-gate-negate-unsigned0.rs
Normal 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
|
||||||
|
}
|
||||||
@@ -12,12 +12,12 @@ const N: isize = 1;
|
|||||||
|
|
||||||
enum Foo {
|
enum Foo {
|
||||||
A = 1,
|
A = 1,
|
||||||
B = 1, //~ ERROR discriminant value `1` already exists
|
B = 1, //~ ERROR discriminant value `1isize` already exists
|
||||||
//~^^ NOTE conflicting
|
//~^^ NOTE conflicting
|
||||||
C = 0,
|
C = 0,
|
||||||
D, //~ ERROR discriminant value `1` already exists
|
D, //~ ERROR discriminant value `1isize` already exists
|
||||||
//~^^^^^ NOTE conflicting
|
//~^^^^^ NOTE conflicting
|
||||||
E = N, //~ ERROR discriminant value `1` already exists
|
E = N, //~ ERROR discriminant value `1isize` already exists
|
||||||
//~^^^^^^^ NOTE conflicting
|
//~^^^^^^^ NOTE conflicting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,23 +35,23 @@ fn main() {
|
|||||||
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
|
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
|
||||||
//~^ ERROR attempted to divide by zero
|
//~^ ERROR attempted to divide by zero
|
||||||
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
|
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());
|
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());
|
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());
|
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());
|
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());
|
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());
|
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());
|
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());
|
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());
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,9 @@
|
|||||||
|
|
||||||
enum Foo {
|
enum Foo {
|
||||||
A = 1i64,
|
A = 1i64,
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types: expected `isize` got `i64`
|
||||||
//~| expected `isize`
|
|
||||||
//~| found `i64`
|
|
||||||
B = 2u8
|
B = 2u8
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types: expected `isize` got `u8`
|
||||||
//~| expected `isize`
|
|
||||||
//~| found `u8`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -24,11 +24,6 @@ fn bar() -> i8 {
|
|||||||
return 123;
|
return 123;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn baz() -> bool {
|
|
||||||
128 > bar() //~ ERROR comparison is useless due to type limits
|
|
||||||
//~^ WARNING literal out of range for i8
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bleh() {
|
fn bleh() {
|
||||||
let u = 42u8;
|
let u = 42u8;
|
||||||
let _ = u > 255; //~ ERROR comparison is useless due to type limits
|
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 _ = u >= 0; //~ ERROR comparison is useless due to type limits
|
||||||
let _ = 0 <= u; //~ 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
23
src/test/compile-fail/lint-type-limits2.rs
Normal file
23
src/test/compile-fail/lint-type-limits2.rs
Normal 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
|
||||||
|
}
|
||||||
21
src/test/compile-fail/lint-type-limits3.rs
Normal file
21
src/test/compile-fail/lint-type-limits3.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ fn main() {
|
|||||||
|
|
||||||
let x2: i8 = -128; // should be OK
|
let x2: i8 = -128; // should be OK
|
||||||
let x1: i8 = 128; //~ error: literal out of range for i8
|
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
|
||||||
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 = 18446744073709551615_i64; //~ error: literal out of range for i64
|
||||||
let x: i64 = -9223372036854775809; //~ 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 = -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
|
|
||||||
}
|
}
|
||||||
|
|||||||
22
src/test/compile-fail/lint-type-overflow2.rs
Normal file
22
src/test/compile-fail/lint-type-overflow2.rs
Normal 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
|
||||||
|
}
|
||||||
@@ -44,12 +44,12 @@ fn main() {
|
|||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
//~| expected `usize`
|
//~| expected `usize`
|
||||||
//~| found `isize`
|
//~| 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];
|
let f = [0_usize; -1_isize];
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
//~| expected `usize`
|
//~| expected `usize`
|
||||||
//~| found `isize`
|
//~| 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 {
|
struct G {
|
||||||
g: (),
|
g: (),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
// A very basic test of const fn functionality.
|
// A very basic test of const fn functionality.
|
||||||
|
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn, const_indexing)]
|
||||||
|
|
||||||
const fn add(x: u32, y: u32) -> u32 {
|
const fn add(x: u32, y: u32) -> u32 {
|
||||||
x + y
|
x + y
|
||||||
@@ -24,6 +24,14 @@ const unsafe fn div(x: u32, y: u32) -> u32 {
|
|||||||
x / y
|
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 SUM: u32 = add(44, 22);
|
||||||
const DIFF: u32 = sub(44, 22);
|
const DIFF: u32 = sub(44, 22);
|
||||||
const DIV: u32 = unsafe{div(44, 22)};
|
const DIV: u32 = unsafe{div(44, 22)};
|
||||||
@@ -36,4 +44,6 @@ fn main() {
|
|||||||
assert_eq!(DIV, 2);
|
assert_eq!(DIV, 2);
|
||||||
|
|
||||||
let _: [&'static str; sub(100, 99) as usize] = ["hi"];
|
let _: [&'static str; sub(100, 99) as usize] = ["hi"];
|
||||||
|
let _: [&'static str; generic(1)] = ["hi"];
|
||||||
|
let _: [&'static str; generic_arr([1])] = ["hi"];
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/test/run-pass/const-negation.rs
Normal file
37
src/test/run-pass/const-negation.rs
Normal 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 => {},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/test/run-pass/issue-23833.rs
Normal file
25
src/test/run-pass/issue-23833.rs
Normal 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);
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ struct S<T, S> {
|
|||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe {
|
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);
|
let transd : [u8; 9] = mem::transmute(s);
|
||||||
// Don't worry about endianness, the numbers are palindromic.
|
// Don't worry about endianness, the numbers are palindromic.
|
||||||
assert_eq!(transd,
|
assert_eq!(transd,
|
||||||
@@ -29,7 +29,7 @@ pub fn main() {
|
|||||||
0xaa, 0xaa, 0xaa, 0xaa]);
|
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);
|
let transd : [u8; 4] = mem::transmute(s);
|
||||||
// Again, no endianness problems.
|
// Again, no endianness problems.
|
||||||
assert_eq!(transd,
|
assert_eq!(transd,
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ fn test_expr() {
|
|||||||
let v4 = 4 as isize;
|
let v4 = 4 as isize;
|
||||||
let v2 = 2 as isize;
|
let v2 = 2 as isize;
|
||||||
assert_eq!(v10 >> v2 as usize, v2 as i8);
|
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 v10 = 10 as usize;
|
||||||
let v4 = 4 as isize;
|
let v4 = 4 as isize;
|
||||||
@@ -71,9 +71,9 @@ fn test_const() {
|
|||||||
assert_eq!(r2_3, 160 as isize);
|
assert_eq!(r2_3, 160 as isize);
|
||||||
|
|
||||||
static r1_4: i8 = 10i8 >> 2_usize;
|
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!(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 r1_5: usize = 10_usize >> 2_usize;
|
||||||
static r2_5: usize = 10_usize << 4_usize;
|
static r2_5: usize = 10_usize << 4_usize;
|
||||||
|
|||||||
Reference in New Issue
Block a user