Auto merge of #30587 - oli-obk:eager_const_eval2, r=nikomatsakis
typestrong const integers ~~It would be great if someone could run crater on this PR, as this has a high danger of breaking valid code~~ Crater ran. Good to go. ---- So this PR does a few things: 1. ~~const eval array values when const evaluating an array expression~~ 2. ~~const eval repeat value when const evaluating a repeat expression~~ 3. ~~const eval all struct and tuple fields when evaluating a struct/tuple expression~~ 4. remove the `ConstVal::Int` and `ConstVal::Uint` variants and replace them with a single enum (`ConstInt`) which has variants for all integral types * `usize`/`isize` are also enums with variants for 32 and 64 bit. At creation and various usage steps there are assertions in place checking if the target bitwidth matches with the chosen enum variant 5. enum discriminants (`ty::Disr`) are now `ConstInt` 6. trans has its own `Disr` type now (newtype around `u64`) This obviously can't be done without breaking changes (the ones that are noticable in stable) We could probably write lints that find those situations and error on it for a cycle or two. But then again, those situations are rare and really bugs imo anyway: ```rust let v10 = 10 as i8; let v4 = 4 as isize; assert_eq!(v10 << v4 as usize, 160 as i8); ``` stops compiling because 160 is not a valid i8 ```rust struct S<T, S> { a: T, b: u8, c: S } let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 }; ``` stops compiling because `0xaa_aa_aa_aa` is not a valid i32 ---- cc @eddyb @pnkfelix related: https://github.com/rust-lang/rfcs/issues/1071
This commit is contained in:
commit
01118928fc
16
mk/crates.mk
16
mk/crates.mk
@ -53,7 +53,7 @@ TARGET_CRATES := libc std term \
|
||||
getopts collections test rand \
|
||||
core alloc \
|
||||
rustc_unicode rustc_bitflags \
|
||||
alloc_system alloc_jemalloc
|
||||
alloc_system alloc_jemalloc rustc_const_eval
|
||||
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||
rustc_data_structures rustc_front rustc_platform_intrinsics \
|
||||
@ -91,8 +91,11 @@ DEPS_test := std getopts term native:rust_test_helpers
|
||||
DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
|
||||
DEPS_syntax_ext := syntax fmt_macros
|
||||
|
||||
DEPS_rustc_const_eval := std syntax
|
||||
|
||||
DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
|
||||
log graphviz rustc_llvm rustc_back rustc_data_structures
|
||||
log graphviz rustc_llvm rustc_back rustc_data_structures\
|
||||
rustc_const_eval
|
||||
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
|
||||
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
|
||||
DEPS_rustc_data_structures := std log serialize
|
||||
@ -103,16 +106,17 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo
|
||||
DEPS_rustc_front := std syntax log serialize
|
||||
DEPS_rustc_lint := rustc log syntax
|
||||
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
|
||||
DEPS_rustc_metadata := rustc rustc_front syntax rbml
|
||||
DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_eval
|
||||
DEPS_rustc_passes := syntax rustc core rustc_front
|
||||
DEPS_rustc_mir := rustc rustc_front syntax
|
||||
DEPS_rustc_mir := rustc rustc_front syntax rustc_const_eval
|
||||
DEPS_rustc_resolve := arena rustc rustc_front log syntax
|
||||
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
|
||||
DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
|
||||
DEPS_rustc_privacy := rustc rustc_front log syntax
|
||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
|
||||
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
|
||||
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
|
||||
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \
|
||||
rustc_const_eval
|
||||
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_eval
|
||||
|
||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||
test rustc_lint rustc_front
|
||||
|
@ -18,6 +18,7 @@ log = { path = "../liblog" }
|
||||
rbml = { path = "../librbml" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_front = { path = "../librustc_front" }
|
||||
rustc_llvm = { path = "../librustc_llvm" }
|
||||
|
@ -55,6 +55,7 @@ extern crate rustc_front;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate serialize;
|
||||
extern crate collections;
|
||||
extern crate rustc_const_eval;
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate syntax;
|
||||
#[macro_use] #[no_link] extern crate rustc_bitflags;
|
||||
|
@ -476,7 +476,7 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
|
||||
Some(Def::AssociatedConst(did)) |
|
||||
Some(Def::Const(did)) => match lookup_const_by_id(self.tcx, did,
|
||||
Some(pat.id), None) {
|
||||
Some(const_expr) => {
|
||||
Some((const_expr, _const_ty)) => {
|
||||
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
|
||||
|
||||
if let Some(ref mut renaming_map) = self.renaming_map {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -342,8 +342,12 @@ pub struct TyCtxt<'tcx> {
|
||||
/// FIXME(arielb1): why is this separate from populated_external_types?
|
||||
pub populated_external_primitive_impls: RefCell<DefIdSet>,
|
||||
|
||||
/// These caches are used by const_eval when decoding external constants.
|
||||
pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
|
||||
/// Cache used by const_eval when decoding external constants.
|
||||
/// Contains `None` when the constant has been fetched but doesn't exist.
|
||||
/// Constains `Some(expr_id, type)` otherwise.
|
||||
/// `type` is `None` in case it's not a primitive type
|
||||
pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
|
||||
/// Cache used by const_eval when decoding extern const fns
|
||||
pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
|
||||
|
||||
pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
|
||||
|
@ -50,6 +50,8 @@ use syntax::attr::{self, AttrMetaMethods};
|
||||
use syntax::codemap::{DUMMY_SP, Span};
|
||||
use syntax::parse::token::InternedString;
|
||||
|
||||
use rustc_const_eval::ConstInt;
|
||||
|
||||
use rustc_front::hir;
|
||||
use rustc_front::hir::{ItemImpl, ItemTrait, PatKind};
|
||||
use rustc_front::intravisit::Visitor;
|
||||
@ -100,8 +102,7 @@ mod ivar;
|
||||
mod structural_impls;
|
||||
mod sty;
|
||||
|
||||
pub type Disr = u64;
|
||||
pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
|
||||
pub type Disr = ConstInt;
|
||||
|
||||
// Data types
|
||||
|
||||
@ -1580,7 +1581,7 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
|
||||
/// Asserts this is a struct and returns the struct's unique
|
||||
/// variant.
|
||||
pub fn struct_variant(&self) -> &VariantDefData<'tcx, 'container> {
|
||||
assert!(self.adt_kind() == AdtKind::Struct);
|
||||
assert_eq!(self.adt_kind(), AdtKind::Struct);
|
||||
&self.variants[0]
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,8 @@ use middle::traits;
|
||||
use middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
|
||||
use middle::ty::{Disr, ParameterEnvironment};
|
||||
use middle::ty::TypeVariants::*;
|
||||
use util::num::ToPrimitive;
|
||||
|
||||
use rustc_const_eval::{ConstInt, ConstIsize, ConstUsize};
|
||||
|
||||
use std::cmp;
|
||||
use std::hash::{Hash, SipHasher, Hasher};
|
||||
@ -34,11 +35,9 @@ use rustc_front::hir;
|
||||
|
||||
pub trait IntTypeExt {
|
||||
fn to_ty<'tcx>(&self, cx: &TyCtxt<'tcx>) -> Ty<'tcx>;
|
||||
fn i64_to_disr(&self, val: i64) -> Option<Disr>;
|
||||
fn u64_to_disr(&self, val: u64) -> Option<Disr>;
|
||||
fn disr_incr(&self, val: Disr) -> Option<Disr>;
|
||||
fn disr_string(&self, val: Disr) -> String;
|
||||
fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr;
|
||||
fn assert_ty_matches(&self, val: Disr);
|
||||
fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr;
|
||||
}
|
||||
|
||||
impl IntTypeExt for attr::IntType {
|
||||
@ -57,98 +56,48 @@ impl IntTypeExt for attr::IntType {
|
||||
}
|
||||
}
|
||||
|
||||
fn i64_to_disr(&self, val: i64) -> Option<Disr> {
|
||||
fn initial_discriminant(&self, tcx: &TyCtxt) -> Disr {
|
||||
match *self {
|
||||
SignedInt(ast::IntTy::I8) => val.to_i8() .map(|v| v as Disr),
|
||||
SignedInt(ast::IntTy::I16) => val.to_i16() .map(|v| v as Disr),
|
||||
SignedInt(ast::IntTy::I32) => val.to_i32() .map(|v| v as Disr),
|
||||
SignedInt(ast::IntTy::I64) => val.to_i64() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U8) => val.to_u8() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
|
||||
|
||||
UnsignedInt(ast::UintTy::Us) |
|
||||
SignedInt(ast::IntTy::Is) => unreachable!(),
|
||||
SignedInt(ast::IntTy::I8) => ConstInt::I8(0),
|
||||
SignedInt(ast::IntTy::I16) => ConstInt::I16(0),
|
||||
SignedInt(ast::IntTy::I32) => ConstInt::I32(0),
|
||||
SignedInt(ast::IntTy::I64) => ConstInt::I64(0),
|
||||
SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type {
|
||||
ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)),
|
||||
ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64(0)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
UnsignedInt(ast::UintTy::U8) => ConstInt::U8(0),
|
||||
UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0),
|
||||
UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0),
|
||||
UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0),
|
||||
UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type {
|
||||
ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)),
|
||||
ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64(0)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn u64_to_disr(&self, val: u64) -> Option<Disr> {
|
||||
match *self {
|
||||
SignedInt(ast::IntTy::I8) => val.to_i8() .map(|v| v as Disr),
|
||||
SignedInt(ast::IntTy::I16) => val.to_i16() .map(|v| v as Disr),
|
||||
SignedInt(ast::IntTy::I32) => val.to_i32() .map(|v| v as Disr),
|
||||
SignedInt(ast::IntTy::I64) => val.to_i64() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U8) => val.to_u8() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U16) => val.to_u16() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U32) => val.to_u32() .map(|v| v as Disr),
|
||||
UnsignedInt(ast::UintTy::U64) => val.to_u64() .map(|v| v as Disr),
|
||||
|
||||
UnsignedInt(ast::UintTy::Us) |
|
||||
SignedInt(ast::IntTy::Is) => unreachable!(),
|
||||
fn assert_ty_matches(&self, val: Disr) {
|
||||
match (*self, val) {
|
||||
(SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
|
||||
(SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
|
||||
(SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
|
||||
(SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
|
||||
(SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
|
||||
(UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
|
||||
_ => panic!("disr type mismatch: {:?} vs {:?}", self, val),
|
||||
}
|
||||
}
|
||||
|
||||
fn disr_incr(&self, val: Disr) -> Option<Disr> {
|
||||
macro_rules! add1 {
|
||||
($e:expr) => { $e.and_then(|v|v.checked_add(1)).map(|v| v as Disr) }
|
||||
}
|
||||
match *self {
|
||||
// SignedInt repr means we *want* to reinterpret the bits
|
||||
// treating the highest bit of Disr as a sign-bit, so
|
||||
// cast to i64 before range-checking.
|
||||
SignedInt(ast::IntTy::I8) => add1!((val as i64).to_i8()),
|
||||
SignedInt(ast::IntTy::I16) => add1!((val as i64).to_i16()),
|
||||
SignedInt(ast::IntTy::I32) => add1!((val as i64).to_i32()),
|
||||
SignedInt(ast::IntTy::I64) => add1!(Some(val as i64)),
|
||||
|
||||
UnsignedInt(ast::UintTy::U8) => add1!(val.to_u8()),
|
||||
UnsignedInt(ast::UintTy::U16) => add1!(val.to_u16()),
|
||||
UnsignedInt(ast::UintTy::U32) => add1!(val.to_u32()),
|
||||
UnsignedInt(ast::UintTy::U64) => add1!(Some(val)),
|
||||
|
||||
UnsignedInt(ast::UintTy::Us) |
|
||||
SignedInt(ast::IntTy::Is) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
// This returns a String because (1.) it is only used for
|
||||
// rendering an error message and (2.) a string can represent the
|
||||
// full range from `i64::MIN` through `u64::MAX`.
|
||||
fn disr_string(&self, val: Disr) -> String {
|
||||
match *self {
|
||||
SignedInt(ast::IntTy::I8) => format!("{}", val as i8 ),
|
||||
SignedInt(ast::IntTy::I16) => format!("{}", val as i16),
|
||||
SignedInt(ast::IntTy::I32) => format!("{}", val as i32),
|
||||
SignedInt(ast::IntTy::I64) => format!("{}", val as i64),
|
||||
UnsignedInt(ast::UintTy::U8) => format!("{}", val as u8 ),
|
||||
UnsignedInt(ast::UintTy::U16) => format!("{}", val as u16),
|
||||
UnsignedInt(ast::UintTy::U32) => format!("{}", val as u32),
|
||||
UnsignedInt(ast::UintTy::U64) => format!("{}", val as u64),
|
||||
|
||||
UnsignedInt(ast::UintTy::Us) |
|
||||
SignedInt(ast::IntTy::Is) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn disr_wrap_incr(&self, val: Option<Disr>) -> Disr {
|
||||
macro_rules! add1 {
|
||||
($e:expr) => { ($e).wrapping_add(1) as Disr }
|
||||
}
|
||||
let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
|
||||
match *self {
|
||||
SignedInt(ast::IntTy::I8) => add1!(val as i8 ),
|
||||
SignedInt(ast::IntTy::I16) => add1!(val as i16),
|
||||
SignedInt(ast::IntTy::I32) => add1!(val as i32),
|
||||
SignedInt(ast::IntTy::I64) => add1!(val as i64),
|
||||
UnsignedInt(ast::UintTy::U8) => add1!(val as u8 ),
|
||||
UnsignedInt(ast::UintTy::U16) => add1!(val as u16),
|
||||
UnsignedInt(ast::UintTy::U32) => add1!(val as u32),
|
||||
UnsignedInt(ast::UintTy::U64) => add1!(val as u64),
|
||||
|
||||
UnsignedInt(ast::UintTy::Us) |
|
||||
SignedInt(ast::IntTy::Is) => unreachable!(),
|
||||
}
|
||||
self.assert_ty_matches(val);
|
||||
(val + ConstInt::Infer(1)).ok()
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,13 +215,11 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `(normalized_type, ty)`, where `normalized_type` is the
|
||||
/// IntType representation of one of {i64,i32,i16,i8,u64,u32,u16,u8},
|
||||
/// and `ty` is the original type (i.e. may include `isize` or
|
||||
/// `usize`).
|
||||
pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>)
|
||||
-> (attr::IntType, Ty<'tcx>) {
|
||||
let repr_type = match opt_hint {
|
||||
/// Returns the IntType representation.
|
||||
/// This used to ensure `int_ty` doesn't contain `usize` and `isize`
|
||||
/// by converting them to their actual types. That doesn't happen anymore.
|
||||
pub fn enum_repr_type(&self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
|
||||
match opt_hint {
|
||||
// Feed in the given type
|
||||
Some(&attr::ReprInt(_, int_t)) => int_t,
|
||||
// ... but provide sensible default if none provided
|
||||
@ -280,18 +227,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
// NB. Historically `fn enum_variants` generate i64 here, while
|
||||
// rustc_typeck::check would generate isize.
|
||||
_ => SignedInt(ast::IntTy::Is),
|
||||
};
|
||||
|
||||
let repr_type_ty = repr_type.to_ty(self);
|
||||
let repr_type = match repr_type {
|
||||
SignedInt(ast::IntTy::Is) =>
|
||||
SignedInt(self.sess.target.int_type),
|
||||
UnsignedInt(ast::UintTy::Us) =>
|
||||
UnsignedInt(self.sess.target.uint_type),
|
||||
other => other
|
||||
};
|
||||
|
||||
(repr_type, repr_type_ty)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the deeply last field of nested structures, or the same type,
|
||||
@ -335,15 +271,16 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
|
||||
let hint = UncheckedExprHint(self.types.usize);
|
||||
match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
|
||||
Ok(val) => {
|
||||
let found = match val {
|
||||
ConstVal::Uint(count) => return count as usize,
|
||||
ConstVal::Int(count) if count >= 0 => return count as usize,
|
||||
const_val => const_val.description(),
|
||||
};
|
||||
Ok(ConstVal::Integral(ConstInt::Usize(count))) => {
|
||||
let val = count.as_u64(self.sess.target.uint_type);
|
||||
assert_eq!(val as usize as u64, val);
|
||||
val as usize
|
||||
},
|
||||
Ok(const_val) => {
|
||||
span_err!(self.sess, count_expr.span, E0306,
|
||||
"expected positive integer for repeat count, found {}",
|
||||
found);
|
||||
"expected positive integer for repeat count, found {}",
|
||||
const_val.description());
|
||||
0
|
||||
}
|
||||
Err(err) => {
|
||||
let err_msg = match count_expr.node {
|
||||
@ -360,9 +297,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
};
|
||||
span_err!(self.sess, count_expr.span, E0307,
|
||||
"expected constant integer for repeat count, {}", err_msg);
|
||||
0
|
||||
}
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Given a set of predicates that apply to an object type, returns
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use graphviz::IntoCow;
|
||||
use middle::const_eval::ConstVal;
|
||||
use rustc_const_eval::{ConstUsize, ConstInt};
|
||||
use middle::def_id::DefId;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
||||
@ -851,13 +852,12 @@ pub struct Constant<'tcx> {
|
||||
pub struct TypedConstVal<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub span: Span,
|
||||
pub value: ConstVal
|
||||
pub value: ConstUsize,
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for TypedConstVal<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||
try!(write!(fmt, "const "));
|
||||
fmt_const_val(fmt, &self.value)
|
||||
write!(fmt, "const {}", ConstInt::Usize(self.value))
|
||||
}
|
||||
}
|
||||
|
||||
@ -897,8 +897,7 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
|
||||
use middle::const_eval::ConstVal::*;
|
||||
match *const_val {
|
||||
Float(f) => write!(fmt, "{:?}", f),
|
||||
Int(n) => write!(fmt, "{:?}", n),
|
||||
Uint(n) => write!(fmt, "{:?}", n),
|
||||
Integral(n) => write!(fmt, "{}", n),
|
||||
Str(ref s) => write!(fmt, "{:?}", s),
|
||||
ByteStr(ref bytes) => {
|
||||
let escaped: String = bytes
|
||||
@ -911,6 +910,8 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
|
||||
Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
|
||||
Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
|
||||
write!(fmt, "{}", node_to_string(node_id)),
|
||||
Char(c) => write!(fmt, "{:?}", c),
|
||||
Dummy => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
*/
|
||||
|
||||
use mir::repr::*;
|
||||
use middle::const_eval::ConstVal;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||
use rustc_front::hir;
|
||||
@ -144,12 +143,10 @@ impl<'tcx> Mir<'tcx> {
|
||||
match *rvalue {
|
||||
Rvalue::Use(ref operand) => Some(self.operand_ty(tcx, operand)),
|
||||
Rvalue::Repeat(ref operand, ref count) => {
|
||||
if let ConstVal::Uint(u) = count.value {
|
||||
let op_ty = self.operand_ty(tcx, operand);
|
||||
Some(tcx.mk_array(op_ty, u as usize))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let op_ty = self.operand_ty(tcx, operand);
|
||||
let count = count.value.as_u64(tcx.sess.target.uint_type);
|
||||
assert_eq!(count as usize as u64, count);
|
||||
Some(tcx.mk_array(op_ty, count as usize))
|
||||
}
|
||||
Rvalue::Ref(reg, bk, ref lv) => {
|
||||
let lv_ty = self.lvalue_ty(tcx, lv).to_ty(tcx);
|
||||
|
14
src/librustc_const_eval/Cargo.toml
Normal file
14
src/librustc_const_eval/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_const_eval"
|
||||
version = "0.0.0"
|
||||
|
||||
[lib]
|
||||
name = "rustc_const_eval"
|
||||
path = "lib.rs"
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
log = { path = "../liblog" }
|
||||
serialize = { path = "../libserialize" }
|
||||
syntax = { path = "../libsyntax" }
|
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",
|
||||
}
|
||||
}
|
||||
}
|
569
src/librustc_const_eval/int.rs
Normal file
569
src/librustc_const_eval/int.rs
Normal file
@ -0,0 +1,569 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use syntax::attr::IntType;
|
||||
use syntax::ast::{IntTy, UintTy};
|
||||
|
||||
use super::is::*;
|
||||
use super::us::*;
|
||||
use super::err::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Hash, Eq, PartialEq)]
|
||||
pub enum ConstInt {
|
||||
I8(i8),
|
||||
I16(i16),
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
Isize(ConstIsize),
|
||||
U8(u8),
|
||||
U16(u16),
|
||||
U32(u32),
|
||||
U64(u64),
|
||||
Usize(ConstUsize),
|
||||
Infer(u64),
|
||||
InferSigned(i64),
|
||||
}
|
||||
pub use self::ConstInt::*;
|
||||
|
||||
|
||||
macro_rules! bounds {
|
||||
($($t:ident $min:ident $max:ident)*) => {
|
||||
mod as_u64 {
|
||||
$(
|
||||
#[allow(dead_code)]
|
||||
pub const $min: u64 = ::std::$t::MIN as u64;
|
||||
#[allow(dead_code)]
|
||||
pub const $max: u64 = ::std::$t::MAX as u64;
|
||||
)*
|
||||
}
|
||||
mod as_i64 {
|
||||
$(
|
||||
#[allow(dead_code)]
|
||||
pub const $min: i64 = ::std::$t::MIN as i64;
|
||||
#[allow(dead_code)]
|
||||
pub const $max: i64 = ::std::$t::MAX as i64;
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bounds!{
|
||||
i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX isize IMIN IMAX
|
||||
u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX usize UMIN UMAX
|
||||
}
|
||||
|
||||
impl ConstInt {
|
||||
/// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
|
||||
/// the other value. If both values have no type, don't do anything
|
||||
pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
|
||||
let inferred = match (self, other) {
|
||||
(InferSigned(_), InferSigned(_))
|
||||
| (Infer(_), Infer(_)) => self, // no inference possible
|
||||
// kindof wrong, you could have had values > I64MAX during computation of a
|
||||
(Infer(a @ 0...as_u64::I64MAX), InferSigned(_)) => InferSigned(a as i64),
|
||||
(Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
|
||||
(_, InferSigned(_))
|
||||
| (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
|
||||
|
||||
(Infer(a @ 0...as_u64::I8MAX), I8(_)) => I8(a as i64 as i8),
|
||||
(Infer(a @ 0...as_u64::I16MAX), I16(_)) => I16(a as i64 as i16),
|
||||
(Infer(a @ 0...as_u64::I32MAX), I32(_)) => I32(a as i64 as i32),
|
||||
(Infer(a @ 0...as_u64::I64MAX), I64(_)) => I64(a as i64),
|
||||
(Infer(a @ 0...as_u64::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
|
||||
(Infer(a @ 0...as_u64::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
|
||||
(Infer(a @ 0...as_u64::U8MAX), U8(_)) => U8(a as u8),
|
||||
(Infer(a @ 0...as_u64::U16MAX), U16(_)) => U16(a as u16),
|
||||
(Infer(a @ 0...as_u64::U32MAX), U32(_)) => U32(a as u32),
|
||||
(Infer(a), U64(_)) => U64(a),
|
||||
(Infer(a @ 0...as_u64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
|
||||
(Infer(a), Usize(Us64(_))) => Usize(Us64(a)),
|
||||
|
||||
(Infer(_), _) => return Err(ConstMathErr::NotInRange),
|
||||
|
||||
(InferSigned(a @ as_i64::I8MIN...as_i64::I8MAX), I8(_)) => I8(a as i8),
|
||||
(InferSigned(a @ as_i64::I16MIN...as_i64::I16MAX), I16(_)) => I16(a as i16),
|
||||
(InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), I32(_)) => I32(a as i32),
|
||||
(InferSigned(a), I64(_)) => I64(a),
|
||||
(InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), Isize(Is32(_))) => {
|
||||
Isize(Is32(a as i32))
|
||||
},
|
||||
(InferSigned(a), Isize(Is64(_))) => Isize(Is64(a)),
|
||||
(InferSigned(a @ 0...as_i64::U8MAX), U8(_)) => U8(a as u8),
|
||||
(InferSigned(a @ 0...as_i64::U16MAX), U16(_)) => U16(a as u16),
|
||||
(InferSigned(a @ 0...as_i64::U32MAX), U32(_)) => U32(a as u32),
|
||||
(InferSigned(a @ 0...as_i64::I64MAX), U64(_)) => U64(a as u64),
|
||||
(InferSigned(a @ 0...as_i64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
|
||||
(InferSigned(a @ 0...as_i64::I64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
|
||||
(InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
|
||||
_ => self, // already known types
|
||||
};
|
||||
Ok((inferred, other))
|
||||
}
|
||||
|
||||
/// Turn this value into an `Infer` or an `InferSigned`
|
||||
pub fn erase_type(self) -> Self {
|
||||
match self {
|
||||
Infer(i) => Infer(i),
|
||||
InferSigned(i) if i < 0 => InferSigned(i),
|
||||
I8(i) if i < 0 => InferSigned(i as i64),
|
||||
I16(i) if i < 0 => InferSigned(i as i64),
|
||||
I32(i) if i < 0 => InferSigned(i as i64),
|
||||
I64(i) if i < 0 => InferSigned(i as i64),
|
||||
Isize(Is32(i)) if i < 0 => InferSigned(i as i64),
|
||||
Isize(Is64(i)) if i < 0 => InferSigned(i as i64),
|
||||
InferSigned(i) => Infer(i as u64),
|
||||
I8(i) => Infer(i as u64),
|
||||
I16(i) => Infer(i as u64),
|
||||
I32(i) => Infer(i as u64),
|
||||
I64(i) => Infer(i as u64),
|
||||
Isize(Is32(i)) => Infer(i as u64),
|
||||
Isize(Is64(i)) => Infer(i as u64),
|
||||
U8(i) => Infer(i as u64),
|
||||
U16(i) => Infer(i as u64),
|
||||
U32(i) => Infer(i as u64),
|
||||
U64(i) => Infer(i as u64),
|
||||
Usize(Us32(i)) => Infer(i as u64),
|
||||
Usize(Us64(i)) => Infer(i),
|
||||
}
|
||||
}
|
||||
|
||||
/// Description of the type, not the value
|
||||
pub fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
Infer(_) => "not yet inferred integral",
|
||||
InferSigned(_) => "not yet inferred signed integral",
|
||||
I8(_) => "i8",
|
||||
I16(_) => "i16",
|
||||
I32(_) => "i32",
|
||||
I64(_) => "i64",
|
||||
Isize(_) => "isize",
|
||||
U8(_) => "u8",
|
||||
U16(_) => "u16",
|
||||
U32(_) => "u32",
|
||||
U64(_) => "u64",
|
||||
Usize(_) => "usize",
|
||||
}
|
||||
}
|
||||
|
||||
/// Erases the type and returns a u64.
|
||||
/// This is not the same as `-5i8 as u64` but as `-5i8 as i64 as u64`
|
||||
pub fn to_u64_unchecked(self) -> u64 {
|
||||
match self.erase_type() {
|
||||
ConstInt::Infer(i) => i,
|
||||
ConstInt::InferSigned(i) => i as u64,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the value to a `u32` if it's in the range 0...std::u32::MAX
|
||||
pub fn to_u32(&self) -> Option<u32> {
|
||||
match *self {
|
||||
I8(v) if v >= 0 => Some(v as u32),
|
||||
I16(v) if v >= 0 => Some(v as u32),
|
||||
I32(v) if v >= 0 => Some(v as u32),
|
||||
InferSigned(v)
|
||||
| Isize(Is64(v))
|
||||
| I64(v) if v >= 0 && v <= ::std::u32::MAX as i64 => Some(v as u32),
|
||||
Isize(Is32(v)) if v >= 0 => Some(v as u32),
|
||||
U8(v) => Some(v as u32),
|
||||
U16(v) => Some(v as u32),
|
||||
U32(v) => Some(v),
|
||||
Infer(v)
|
||||
| Usize(Us64(v))
|
||||
| U64(v) if v <= ::std::u32::MAX as u64 => Some(v as u32),
|
||||
Usize(Us32(v)) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the value to a `u64` if it's >= 0
|
||||
pub fn to_u64(&self) -> Option<u64> {
|
||||
match *self {
|
||||
Infer(v) => Some(v),
|
||||
InferSigned(v) if v >= 0 => Some(v as u64),
|
||||
I8(v) if v >= 0 => Some(v as u64),
|
||||
I16(v) if v >= 0 => Some(v as u64),
|
||||
I32(v) if v >= 0 => Some(v as u64),
|
||||
I64(v) if v >= 0 => Some(v as u64),
|
||||
Isize(Is32(v)) if v >= 0 => Some(v as u64),
|
||||
Isize(Is64(v)) if v >= 0 => Some(v as u64),
|
||||
U8(v) => Some(v as u64),
|
||||
U16(v) => Some(v as u64),
|
||||
U32(v) => Some(v as u64),
|
||||
U64(v) => Some(v),
|
||||
Usize(Us32(v)) => Some(v as u64),
|
||||
Usize(Us64(v)) => Some(v),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_negative(&self) -> bool {
|
||||
match *self {
|
||||
I8(v) => v < 0,
|
||||
I16(v) => v < 0,
|
||||
I32(v) => v < 0,
|
||||
I64(v) => v < 0,
|
||||
Isize(Is32(v)) => v < 0,
|
||||
Isize(Is64(v)) => v < 0,
|
||||
InferSigned(v) => v < 0,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares the values if they are of the same type
|
||||
pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
|
||||
match try!(self.infer(rhs)) {
|
||||
(I8(a), I8(b)) => Ok(a.cmp(&b)),
|
||||
(I16(a), I16(b)) => Ok(a.cmp(&b)),
|
||||
(I32(a), I32(b)) => Ok(a.cmp(&b)),
|
||||
(I64(a), I64(b)) => Ok(a.cmp(&b)),
|
||||
(Isize(Is32(a)), Isize(Is32(b))) => Ok(a.cmp(&b)),
|
||||
(Isize(Is64(a)), Isize(Is64(b))) => Ok(a.cmp(&b)),
|
||||
(U8(a), U8(b)) => Ok(a.cmp(&b)),
|
||||
(U16(a), U16(b)) => Ok(a.cmp(&b)),
|
||||
(U32(a), U32(b)) => Ok(a.cmp(&b)),
|
||||
(U64(a), U64(b)) => Ok(a.cmp(&b)),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
|
||||
(Infer(a), Infer(b)) => Ok(a.cmp(&b)),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
|
||||
_ => Err(CmpBetweenUnequalTypes),
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds 1 to the value and wraps around if the maximum for the type is reached
|
||||
pub fn wrap_incr(self) -> Self {
|
||||
macro_rules! add1 {
|
||||
($e:expr) => { ($e).wrapping_add(1) }
|
||||
}
|
||||
match self {
|
||||
ConstInt::I8(i) => ConstInt::I8(add1!(i)),
|
||||
ConstInt::I16(i) => ConstInt::I16(add1!(i)),
|
||||
ConstInt::I32(i) => ConstInt::I32(add1!(i)),
|
||||
ConstInt::I64(i) => ConstInt::I64(add1!(i)),
|
||||
ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))),
|
||||
ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))),
|
||||
ConstInt::U8(i) => ConstInt::U8(add1!(i)),
|
||||
ConstInt::U16(i) => ConstInt::U16(add1!(i)),
|
||||
ConstInt::U32(i) => ConstInt::U32(add1!(i)),
|
||||
ConstInt::U64(i) => ConstInt::U64(add1!(i)),
|
||||
ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
|
||||
ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
|
||||
ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn int_type(self) -> Option<IntType> {
|
||||
match self {
|
||||
ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
|
||||
ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
|
||||
ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
|
||||
ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
|
||||
ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
|
||||
ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
|
||||
ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
|
||||
ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
|
||||
ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
|
||||
ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::cmp::PartialOrd for ConstInt {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
self.try_cmp(*other).ok()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::cmp::Ord for ConstInt {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.try_cmp(*other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for ConstInt {
|
||||
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
|
||||
match *self {
|
||||
Infer(i) => write!(fmt, "{}", i),
|
||||
InferSigned(i) => write!(fmt, "{}", i),
|
||||
I8(i) => write!(fmt, "{}i8", i),
|
||||
I16(i) => write!(fmt, "{}i16", i),
|
||||
I32(i) => write!(fmt, "{}i32", i),
|
||||
I64(i) => write!(fmt, "{}i64", i),
|
||||
Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i),
|
||||
Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i),
|
||||
U8(i) => write!(fmt, "{}u8", i),
|
||||
U16(i) => write!(fmt, "{}u16", i),
|
||||
U32(i) => write!(fmt, "{}u32", i),
|
||||
U64(i) => write!(fmt, "{}u64", i),
|
||||
Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i),
|
||||
Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! overflowing {
|
||||
($e:expr, $err:expr) => {{
|
||||
if $e.1 {
|
||||
return Err(Overflow($err));
|
||||
} else {
|
||||
$e.0
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! impl_binop {
|
||||
($op:ident, $func:ident, $checked_func:ident) => {
|
||||
impl ::std::ops::$op for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
match try!(self.infer(rhs)) {
|
||||
(I8(a), I8(b)) => a.$checked_func(b).map(I8),
|
||||
(I16(a), I16(b)) => a.$checked_func(b).map(I16),
|
||||
(I32(a), I32(b)) => a.$checked_func(b).map(I32),
|
||||
(I64(a), I64(b)) => a.$checked_func(b).map(I64),
|
||||
(Isize(Is32(a)), Isize(Is32(b))) => a.$checked_func(b).map(Is32).map(Isize),
|
||||
(Isize(Is64(a)), Isize(Is64(b))) => a.$checked_func(b).map(Is64).map(Isize),
|
||||
(U8(a), U8(b)) => a.$checked_func(b).map(U8),
|
||||
(U16(a), U16(b)) => a.$checked_func(b).map(U16),
|
||||
(U32(a), U32(b)) => a.$checked_func(b).map(U32),
|
||||
(U64(a), U64(b)) => a.$checked_func(b).map(U64),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
|
||||
(Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
|
||||
(InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
|
||||
_ => return Err(UnequalTypes(Op::$op)),
|
||||
}.ok_or(Overflow(Op::$op))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! derive_binop {
|
||||
($op:ident, $func:ident) => {
|
||||
impl ::std::ops::$op for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
match try!(self.infer(rhs)) {
|
||||
(I8(a), I8(b)) => Ok(I8(a.$func(b))),
|
||||
(I16(a), I16(b)) => Ok(I16(a.$func(b))),
|
||||
(I32(a), I32(b)) => Ok(I32(a.$func(b))),
|
||||
(I64(a), I64(b)) => Ok(I64(a.$func(b))),
|
||||
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a.$func(b)))),
|
||||
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a.$func(b)))),
|
||||
(U8(a), U8(b)) => Ok(U8(a.$func(b))),
|
||||
(U16(a), U16(b)) => Ok(U16(a.$func(b))),
|
||||
(U32(a), U32(b)) => Ok(U32(a.$func(b))),
|
||||
(U64(a), U64(b)) => Ok(U64(a.$func(b))),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
|
||||
(Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
|
||||
_ => Err(UnequalTypes(Op::$op)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_binop!(Add, add, checked_add);
|
||||
impl_binop!(Sub, sub, checked_sub);
|
||||
impl_binop!(Mul, mul, checked_mul);
|
||||
derive_binop!(BitAnd, bitand);
|
||||
derive_binop!(BitOr, bitor);
|
||||
derive_binop!(BitXor, bitxor);
|
||||
|
||||
fn check_division(
|
||||
lhs: ConstInt,
|
||||
rhs: ConstInt,
|
||||
op: Op,
|
||||
zerr: ConstMathErr,
|
||||
) -> Result<(), ConstMathErr> {
|
||||
match (lhs, rhs) {
|
||||
(I8(_), I8(0)) => Err(zerr),
|
||||
(I16(_), I16(0)) => Err(zerr),
|
||||
(I32(_), I32(0)) => Err(zerr),
|
||||
(I64(_), I64(0)) => Err(zerr),
|
||||
(Isize(_), Isize(Is32(0))) => Err(zerr),
|
||||
(Isize(_), Isize(Is64(0))) => Err(zerr),
|
||||
(InferSigned(_), InferSigned(0)) => Err(zerr),
|
||||
|
||||
(U8(_), U8(0)) => Err(zerr),
|
||||
(U16(_), U16(0)) => Err(zerr),
|
||||
(U32(_), U32(0)) => Err(zerr),
|
||||
(U64(_), U64(0)) => Err(zerr),
|
||||
(Usize(_), Usize(Us32(0))) => Err(zerr),
|
||||
(Usize(_), Usize(Us64(0))) => Err(zerr),
|
||||
(Infer(_), Infer(0)) => Err(zerr),
|
||||
|
||||
(I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
|
||||
(I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
|
||||
(I32(::std::i32::MIN), I32(-1)) => Err(Overflow(op)),
|
||||
(I64(::std::i64::MIN), I64(-1)) => Err(Overflow(op)),
|
||||
(Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
|
||||
(Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
|
||||
(InferSigned(::std::i64::MIN), InferSigned(-1)) => Err(Overflow(op)),
|
||||
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Div for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
let (lhs, rhs) = try!(self.infer(rhs));
|
||||
try!(check_division(lhs, rhs, Op::Div, DivisionByZero));
|
||||
match (lhs, rhs) {
|
||||
(I8(a), I8(b)) => Ok(I8(a/b)),
|
||||
(I16(a), I16(b)) => Ok(I16(a/b)),
|
||||
(I32(a), I32(b)) => Ok(I32(a/b)),
|
||||
(I64(a), I64(b)) => Ok(I64(a/b)),
|
||||
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
|
||||
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
|
||||
|
||||
(U8(a), U8(b)) => Ok(U8(a/b)),
|
||||
(U16(a), U16(b)) => Ok(U16(a/b)),
|
||||
(U32(a), U32(b)) => Ok(U32(a/b)),
|
||||
(U64(a), U64(b)) => Ok(U64(a/b)),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
|
||||
(Infer(a), Infer(b)) => Ok(Infer(a/b)),
|
||||
|
||||
_ => Err(UnequalTypes(Op::Div)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Rem for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
let (lhs, rhs) = try!(self.infer(rhs));
|
||||
// should INT_MIN%-1 be zero or an error?
|
||||
try!(check_division(lhs, rhs, Op::Rem, RemainderByZero));
|
||||
match (lhs, rhs) {
|
||||
(I8(a), I8(b)) => Ok(I8(a%b)),
|
||||
(I16(a), I16(b)) => Ok(I16(a%b)),
|
||||
(I32(a), I32(b)) => Ok(I32(a%b)),
|
||||
(I64(a), I64(b)) => Ok(I64(a%b)),
|
||||
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
|
||||
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
|
||||
(InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
|
||||
|
||||
(U8(a), U8(b)) => Ok(U8(a%b)),
|
||||
(U16(a), U16(b)) => Ok(U16(a%b)),
|
||||
(U32(a), U32(b)) => Ok(U32(a%b)),
|
||||
(U64(a), U64(b)) => Ok(U64(a%b)),
|
||||
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
|
||||
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
|
||||
(Infer(a), Infer(b)) => Ok(Infer(a%b)),
|
||||
|
||||
_ => Err(UnequalTypes(Op::Rem)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Shl<ConstInt> for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn shl(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
let b = try!(rhs.to_u32().ok_or(ShiftNegative));
|
||||
match self {
|
||||
I8(a) => Ok(I8(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
I16(a) => Ok(I16(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
I32(a) => Ok(I32(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
I64(a) => Ok(I64(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
|
||||
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
|
||||
U8(a) => Ok(U8(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
U16(a) => Ok(U16(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
U32(a) => Ok(U32(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
U64(a) => Ok(U64(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
|
||||
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
|
||||
Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Shr<ConstInt> for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn shr(self, rhs: Self) -> Result<Self, ConstMathErr> {
|
||||
let b = try!(rhs.to_u32().ok_or(ShiftNegative));
|
||||
match self {
|
||||
I8(a) => Ok(I8(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
I16(a) => Ok(I16(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
I32(a) => Ok(I32(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
I64(a) => Ok(I64(overflowing!(a.overflowing_shr(b), Op::Shl))),
|
||||
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
|
||||
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
|
||||
U8(a) => Ok(U8(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
U16(a) => Ok(U16(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
U32(a) => Ok(U32(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
U64(a) => Ok(U64(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
|
||||
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
|
||||
Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Neg for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn neg(self) -> Result<Self, ConstMathErr> {
|
||||
match self {
|
||||
I8(a) => Ok(I8(overflowing!(a.overflowing_neg(), Op::Neg))),
|
||||
I16(a) => Ok(I16(overflowing!(a.overflowing_neg(), Op::Neg))),
|
||||
I32(a) => Ok(I32(overflowing!(a.overflowing_neg(), Op::Neg))),
|
||||
I64(a) => Ok(I64(overflowing!(a.overflowing_neg(), Op::Neg))),
|
||||
Isize(Is32(a)) => Ok(Isize(Is32(overflowing!(a.overflowing_neg(), Op::Neg)))),
|
||||
Isize(Is64(a)) => Ok(Isize(Is64(overflowing!(a.overflowing_neg(), Op::Neg)))),
|
||||
U8(0) => Ok(U8(0)),
|
||||
U16(0) => Ok(U16(0)),
|
||||
U32(0) => Ok(U32(0)),
|
||||
U64(0) => Ok(U64(0)),
|
||||
Usize(Us32(0)) => Ok(Usize(Us32(0))),
|
||||
Usize(Us64(0)) => Ok(Usize(Us64(0))),
|
||||
U8(_) => Err(UnsignedNegation),
|
||||
U16(_) => Err(UnsignedNegation),
|
||||
U32(_) => Err(UnsignedNegation),
|
||||
U64(_) => Err(UnsignedNegation),
|
||||
Usize(_) => Err(UnsignedNegation),
|
||||
Infer(a @ 0...as_u64::I64MAX) => Ok(InferSigned(-(a as i64))),
|
||||
Infer(_) => Err(Overflow(Op::Neg)),
|
||||
InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::ops::Not for ConstInt {
|
||||
type Output = Result<Self, ConstMathErr>;
|
||||
fn not(self) -> Result<Self, ConstMathErr> {
|
||||
match self {
|
||||
I8(a) => Ok(I8(!a)),
|
||||
I16(a) => Ok(I16(!a)),
|
||||
I32(a) => Ok(I32(!a)),
|
||||
I64(a) => Ok(I64(!a)),
|
||||
Isize(Is32(a)) => Ok(Isize(Is32(!a))),
|
||||
Isize(Is64(a)) => Ok(Isize(Is64(!a))),
|
||||
U8(a) => Ok(U8(!a)),
|
||||
U16(a) => Ok(U16(!a)),
|
||||
U32(a) => Ok(U32(!a)),
|
||||
U64(a) => Ok(U64(!a)),
|
||||
Usize(Us32(a)) => Ok(Usize(Us32(!a))),
|
||||
Usize(Us64(a)) => Ok(Usize(Us64(!a))),
|
||||
Infer(a) => Ok(Infer(!a)),
|
||||
InferSigned(a) => Ok(InferSigned(!a)),
|
||||
}
|
||||
}
|
||||
}
|
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 {
|
||||
match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
|
||||
Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
|
||||
Ok(ConstVal::Uint(shift)) => { shift >= bits },
|
||||
Ok(ConstVal::Integral(i)) => {
|
||||
i.is_negative() || i.to_u64()
|
||||
.map(|i| i >= bits)
|
||||
.unwrap_or(true)
|
||||
},
|
||||
_ => { false }
|
||||
}
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ rbml = { path = "../librbml" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_front = { path = "../librustc_front" }
|
||||
rustc_llvm = { path = "../librustc_llvm" }
|
||||
serialize = { path = "../libserialize" }
|
||||
|
@ -35,6 +35,8 @@ use middle::subst;
|
||||
use middle::ty::{ImplContainer, TraitContainer};
|
||||
use middle::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind};
|
||||
|
||||
use rustc_const_eval::ConstInt;
|
||||
|
||||
use rustc::mir;
|
||||
use rustc::mir::visit::MutVisitor;
|
||||
|
||||
@ -198,7 +200,7 @@ fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
|
||||
reader::tagged_docs(d, tag_items_data_item_reexport)
|
||||
}
|
||||
|
||||
fn variant_disr_val(d: rbml::Doc) -> Option<ty::Disr> {
|
||||
fn variant_disr_val(d: rbml::Doc) -> Option<u64> {
|
||||
reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| {
|
||||
reader::with_doc_data(val_doc, |data| {
|
||||
str::from_utf8(data).ok().and_then(|s| s.parse().ok())
|
||||
@ -396,7 +398,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
|
||||
did: did,
|
||||
name: item_name(intr, item),
|
||||
fields: get_variant_fields(intr, cdata, item, tcx),
|
||||
disr_val: disr,
|
||||
disr_val: ConstInt::Infer(disr),
|
||||
kind: expect_variant_kind(item_family(item), tcx),
|
||||
}
|
||||
}).collect()
|
||||
@ -432,7 +434,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner,
|
||||
did: did,
|
||||
name: item_name(intr, doc),
|
||||
fields: get_variant_fields(intr, cdata, doc, tcx),
|
||||
disr_val: 0,
|
||||
disr_val: ConstInt::Infer(0),
|
||||
kind: expect_variant_kind(item_family(doc), tcx),
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ use middle::dependency_format::Linkage;
|
||||
use middle::stability;
|
||||
use middle::subst;
|
||||
use middle::ty::{self, Ty, TyCtxt};
|
||||
use middle::ty::util::IntTypeExt;
|
||||
|
||||
use rustc::back::svh::Svh;
|
||||
use rustc::front::map::{LinkedPath, PathElem, PathElems};
|
||||
@ -238,7 +239,8 @@ fn encode_symbol(ecx: &EncodeContext,
|
||||
fn encode_disr_val(_: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
disr_val: ty::Disr) {
|
||||
rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_string());
|
||||
// convert to u64 so just the number is printed, without any type info
|
||||
rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string());
|
||||
}
|
||||
|
||||
fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
|
||||
@ -262,13 +264,14 @@ fn encode_struct_fields(rbml_w: &mut Encoder,
|
||||
|
||||
fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
||||
rbml_w: &mut Encoder,
|
||||
id: NodeId,
|
||||
did: DefId,
|
||||
vis: hir::Visibility,
|
||||
index: &mut CrateIndex<'tcx>) {
|
||||
debug!("encode_enum_variant_info(id={})", id);
|
||||
|
||||
let mut disr_val = 0;
|
||||
let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id));
|
||||
debug!("encode_enum_variant_info(did={:?})", did);
|
||||
let repr_hints = ecx.tcx.lookup_repr_hints(did);
|
||||
let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
|
||||
let mut disr_val = repr_type.initial_discriminant(&ecx.tcx);
|
||||
let def = ecx.tcx.lookup_adt_def(did);
|
||||
for variant in &def.variants {
|
||||
let vid = variant.did;
|
||||
let variant_node_id = ecx.local_id(vid);
|
||||
@ -290,7 +293,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
||||
ty::VariantKind::Unit => 'w',
|
||||
});
|
||||
encode_name(rbml_w, variant.name);
|
||||
encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
|
||||
encode_parent_item(rbml_w, did);
|
||||
encode_visibility(rbml_w, vis);
|
||||
|
||||
let attrs = ecx.tcx.get_attrs(vid);
|
||||
@ -313,7 +316,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
||||
|
||||
ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path));
|
||||
rbml_w.end_tag();
|
||||
disr_val = disr_val.wrapping_add(1);
|
||||
disr_val = disr_val.wrap_incr();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1035,7 +1038,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
||||
|
||||
encode_enum_variant_info(ecx,
|
||||
rbml_w,
|
||||
item.id,
|
||||
def_id,
|
||||
vis,
|
||||
index);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ extern crate rustc;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_front;
|
||||
extern crate rustc_llvm;
|
||||
extern crate rustc_const_eval;
|
||||
|
||||
pub use rustc::middle;
|
||||
|
||||
|
@ -13,6 +13,7 @@ graphviz = { path = "../libgraphviz" }
|
||||
log = { path = "../liblog" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_front = { path = "../librustc_front" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
|
@ -269,7 +269,7 @@ enum TestKind<'tcx> {
|
||||
|
||||
// test length of the slice is equal to len
|
||||
Len {
|
||||
len: usize,
|
||||
len: u64,
|
||||
op: BinOp,
|
||||
},
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
};
|
||||
Test {
|
||||
span: match_pair.pattern.span,
|
||||
kind: TestKind::Len { len: len, op: op },
|
||||
kind: TestKind::Len { len: len as u64, op: op },
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
Operand::Constant(constant)
|
||||
}
|
||||
|
||||
pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> {
|
||||
pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: u64) -> Lvalue<'tcx> {
|
||||
let usize_ty = self.hir.usize_ty();
|
||||
let temp = self.temp(usize_ty);
|
||||
self.cfg.push_assign_constant(
|
||||
|
@ -94,6 +94,8 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc::mir::repr::*;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use syntax::parse::token::intern_and_get_ident;
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc_const_eval::ConstInt;
|
||||
|
||||
pub struct Scope<'tcx> {
|
||||
extent: CodeExtent,
|
||||
@ -517,7 +519,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
}, Constant {
|
||||
span: span,
|
||||
ty: self.hir.tcx().types.u32,
|
||||
literal: self.hir.usize_literal(span_lines.line)
|
||||
literal: Literal::Value {
|
||||
value: ConstVal::Integral(ConstInt::U32(span_lines.line as u32)),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,13 @@
|
||||
|
||||
use hair::*;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use rustc_const_eval::ConstInt;
|
||||
use hair::cx::Cx;
|
||||
use hair::cx::block;
|
||||
use hair::cx::to_ref::ToRef;
|
||||
use rustc::front::map;
|
||||
use rustc::middle::def::Def;
|
||||
use rustc::middle::const_eval;
|
||||
use rustc::middle::const_eval::{self, ConstVal};
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::pat_util;
|
||||
use rustc::middle::ty::{self, VariantDef, Ty};
|
||||
@ -227,28 +228,37 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprUnary(op, ref arg) => {
|
||||
hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
|
||||
if cx.tcx.is_method_call(self.id) {
|
||||
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
|
||||
PassArgs::ByValue, arg.to_ref(), vec![])
|
||||
} else {
|
||||
// FIXME overflow
|
||||
let op = match op {
|
||||
hir::UnOp::UnNot => UnOp::Not,
|
||||
hir::UnOp::UnNeg => UnOp::Neg,
|
||||
hir::UnOp::UnDeref => {
|
||||
cx.tcx.sess.span_bug(
|
||||
self.span,
|
||||
"UnDeref should have been handled elsewhere");
|
||||
}
|
||||
};
|
||||
ExprKind::Unary {
|
||||
op: op,
|
||||
op: UnOp::Not,
|
||||
arg: arg.to_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
|
||||
if cx.tcx.is_method_call(self.id) {
|
||||
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
|
||||
PassArgs::ByValue, arg.to_ref(), vec![])
|
||||
} else {
|
||||
// FIXME runtime-overflow
|
||||
if let hir::ExprLit(_) = arg.node {
|
||||
ExprKind::Literal {
|
||||
literal: cx.const_eval_literal(self),
|
||||
}
|
||||
} else {
|
||||
ExprKind::Unary {
|
||||
op: UnOp::Neg,
|
||||
arg: arg.to_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprStruct(_, ref fields, ref base) => {
|
||||
match expr_ty.sty {
|
||||
ty::TyStruct(adt, substs) => {
|
||||
@ -338,7 +348,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
count: TypedConstVal {
|
||||
ty: cx.tcx.expr_ty(c),
|
||||
span: c.span,
|
||||
value: const_eval::eval_const_expr(cx.tcx, c)
|
||||
value: match const_eval::eval_const_expr(cx.tcx, c) {
|
||||
ConstVal::Integral(ConstInt::Usize(u)) => u,
|
||||
other => panic!("constant evaluation of repeat count yielded {:?}", other),
|
||||
},
|
||||
}
|
||||
},
|
||||
hir::ExprRet(ref v) =>
|
||||
|
@ -24,6 +24,7 @@ use rustc::middle::ty::{self, Ty, TyCtxt};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token;
|
||||
use rustc_front::hir;
|
||||
use rustc_const_eval::{ConstInt, ConstUsize};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Cx<'a, 'tcx: 'a> {
|
||||
@ -50,8 +51,11 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
|
||||
self.tcx.types.usize
|
||||
}
|
||||
|
||||
pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Uint(value as u64) }
|
||||
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
|
||||
match ConstUsize::new(value, self.tcx.sess.target.uint_type) {
|
||||
Ok(val) => Literal::Value { value: ConstVal::Integral(ConstInt::Usize(val))},
|
||||
Err(_) => panic!("usize literal out of range for target"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool_ty(&mut self) -> Ty<'tcx> {
|
||||
|
@ -87,7 +87,7 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
|
||||
Def::Const(def_id) | Def::AssociatedConst(def_id) =>
|
||||
match const_eval::lookup_const_by_id(self.cx.tcx, def_id,
|
||||
Some(pat.id), None) {
|
||||
Some(const_expr) => {
|
||||
Some((const_expr, _const_ty)) => {
|
||||
let pat = const_eval::const_expr_to_pat(self.cx.tcx, const_expr,
|
||||
pat.span);
|
||||
return self.to_pattern(&pat);
|
||||
|
@ -31,6 +31,7 @@ extern crate rustc_data_structures;
|
||||
extern crate rustc_front;
|
||||
extern crate rustc_back;
|
||||
extern crate syntax;
|
||||
extern crate rustc_const_eval;
|
||||
|
||||
pub mod build;
|
||||
pub mod graphviz;
|
||||
|
@ -604,7 +604,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
||||
}
|
||||
Some(Def::Const(did)) |
|
||||
Some(Def::AssociatedConst(did)) => {
|
||||
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
|
||||
if let Some((expr, _ty)) = const_eval::lookup_const_by_id(v.tcx, did,
|
||||
Some(e.id),
|
||||
None) {
|
||||
let inner = v.global_expr(Mode::Const, expr);
|
||||
|
@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" }
|
||||
log = { path = "../liblog" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_front = { path = "../librustc_front" }
|
||||
rustc_llvm = { path = "../librustc_llvm" }
|
||||
|
@ -50,6 +50,7 @@ pub extern crate rustc_llvm as llvm;
|
||||
extern crate rustc_mir;
|
||||
extern crate rustc_platform_intrinsics as intrinsics;
|
||||
extern crate serialize;
|
||||
extern crate rustc_const_eval;
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
#[macro_use] extern crate syntax;
|
||||
|
@ -1035,7 +1035,7 @@ fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
|
||||
match ity {
|
||||
attr::UnsignedInt(_) => {
|
||||
assert!(min <= discr);
|
||||
assert!(discr <= max)
|
||||
assert!(discr <= max);
|
||||
},
|
||||
attr::SignedInt(_) => {
|
||||
assert!(min.0 as i64 <= discr.0 as i64);
|
||||
|
@ -15,15 +15,7 @@ use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
|
||||
use llvm::{InternalLinkage, ValueRef, Bool, True};
|
||||
use middle::const_qualif::ConstQualif;
|
||||
use middle::cstore::LOCAL_CRATE;
|
||||
use middle::const_eval::{self, ConstVal, ConstEvalErr};
|
||||
use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
|
||||
use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
|
||||
use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
|
||||
use middle::const_eval::{const_int_checked_mul, const_uint_checked_mul};
|
||||
use middle::const_eval::{const_int_checked_div, const_uint_checked_div};
|
||||
use middle::const_eval::{const_int_checked_rem, const_uint_checked_rem};
|
||||
use middle::const_eval::{const_int_checked_shl, const_uint_checked_shl};
|
||||
use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
|
||||
use middle::const_eval::{self, ConstEvalErr};
|
||||
use middle::def::Def;
|
||||
use middle::def_id::DefId;
|
||||
use trans::{adt, closure, debuginfo, expr, inline, machine};
|
||||
@ -42,9 +34,10 @@ use trans::Disr;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::adjustment::{AdjustDerefRef, AdjustReifyFnPointer};
|
||||
use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer};
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::ty::{self, Ty, TyCtxt};
|
||||
use middle::ty::cast::{CastTy,IntTy};
|
||||
use util::nodemap::NodeMap;
|
||||
use rustc_const_eval::{ConstInt, ConstMathErr, ConstUsize, ConstIsize};
|
||||
|
||||
use rustc_front::hir;
|
||||
|
||||
@ -234,7 +227,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id), Some(param_substs)) {
|
||||
Some(ref expr) => expr,
|
||||
Some((ref expr, _ty)) => expr,
|
||||
None => {
|
||||
ccx.sess().span_bug(ref_expr.span, "constant item not found")
|
||||
}
|
||||
@ -469,35 +462,70 @@ fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
|
||||
// Catch this up front by looking for ExprLit directly,
|
||||
// and just accepting it.
|
||||
if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
|
||||
|
||||
let result = match t.sty {
|
||||
ty::TyInt(int_type) => {
|
||||
let input = match const_to_opt_int(te) {
|
||||
Some(v) => v,
|
||||
None => return Ok(()),
|
||||
};
|
||||
const_int_checked_neg(
|
||||
input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
|
||||
}
|
||||
ty::TyUint(uint_type) => {
|
||||
let input = match const_to_opt_uint(te) {
|
||||
Some(v) => v,
|
||||
None => return Ok(()),
|
||||
};
|
||||
const_uint_checked_neg(
|
||||
input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
|
||||
}
|
||||
_ => return Ok(()),
|
||||
let cval = match to_const_int(te, t, cx.tcx()) {
|
||||
Some(v) => v,
|
||||
None => return Ok(()),
|
||||
};
|
||||
const_err(cx, e, result, trueconst)
|
||||
match -cval {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(err) => const_err(cx, e, Err(err), trueconst),
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn to_const_int(value: ValueRef, t: Ty, tcx: &TyCtxt) -> Option<ConstInt> {
|
||||
match t.sty {
|
||||
ty::TyInt(int_type) => const_to_opt_int(value).and_then(|input| match int_type {
|
||||
ast::IntTy::I8 => {
|
||||
assert_eq!(input as i8 as i64, input);
|
||||
Some(ConstInt::I8(input as i8))
|
||||
},
|
||||
ast::IntTy::I16 => {
|
||||
assert_eq!(input as i16 as i64, input);
|
||||
Some(ConstInt::I16(input as i16))
|
||||
},
|
||||
ast::IntTy::I32 => {
|
||||
assert_eq!(input as i32 as i64, input);
|
||||
Some(ConstInt::I32(input as i32))
|
||||
},
|
||||
ast::IntTy::I64 => {
|
||||
Some(ConstInt::I64(input))
|
||||
},
|
||||
ast::IntTy::Is => {
|
||||
ConstIsize::new(input, tcx.sess.target.int_type)
|
||||
.ok().map(ConstInt::Isize)
|
||||
},
|
||||
}),
|
||||
ty::TyUint(uint_type) => const_to_opt_uint(value).and_then(|input| match uint_type {
|
||||
ast::UintTy::U8 => {
|
||||
assert_eq!(input as u8 as u64, input);
|
||||
Some(ConstInt::U8(input as u8))
|
||||
},
|
||||
ast::UintTy::U16 => {
|
||||
assert_eq!(input as u16 as u64, input);
|
||||
Some(ConstInt::U16(input as u16))
|
||||
},
|
||||
ast::UintTy::U32 => {
|
||||
assert_eq!(input as u32 as u64, input);
|
||||
Some(ConstInt::U32(input as u32))
|
||||
},
|
||||
ast::UintTy::U64 => {
|
||||
Some(ConstInt::U64(input))
|
||||
},
|
||||
ast::UintTy::Us => {
|
||||
ConstUsize::new(input, tcx.sess.target.uint_type)
|
||||
.ok().map(ConstInt::Usize)
|
||||
},
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn const_err(cx: &CrateContext,
|
||||
e: &hir::Expr,
|
||||
result: Result<ConstVal, ConstEvalErr>,
|
||||
result: Result<ConstInt, ConstMathErr>,
|
||||
trueconst: TrueConst)
|
||||
-> Result<(), ConstEvalFailure> {
|
||||
match (result, trueconst) {
|
||||
@ -506,10 +534,12 @@ fn const_err(cx: &CrateContext,
|
||||
Ok(())
|
||||
},
|
||||
(Err(err), TrueConst::Yes) => {
|
||||
let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
|
||||
cx.tcx().sess.span_err(e.span, &err.description());
|
||||
Err(Compiletime(err))
|
||||
},
|
||||
(Err(err), TrueConst::No) => {
|
||||
let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
|
||||
cx.tcx().sess.span_warn(e.span, &err.description());
|
||||
Err(Runtime(err))
|
||||
},
|
||||
@ -520,46 +550,18 @@ fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
|
||||
te1: ValueRef, te2: ValueRef,
|
||||
trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
|
||||
let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() };
|
||||
|
||||
let result = match t.sty {
|
||||
ty::TyInt(int_type) => {
|
||||
let (lhs, rhs) = match (const_to_opt_int(te1),
|
||||
const_to_opt_int(te2)) {
|
||||
(Some(v1), Some(v2)) => (v1, v2),
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
|
||||
match b.node {
|
||||
hir::BiAdd => const_int_checked_add(lhs, rhs, e, opt_ety),
|
||||
hir::BiSub => const_int_checked_sub(lhs, rhs, e, opt_ety),
|
||||
hir::BiMul => const_int_checked_mul(lhs, rhs, e, opt_ety),
|
||||
hir::BiDiv => const_int_checked_div(lhs, rhs, e, opt_ety),
|
||||
hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
|
||||
hir::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
|
||||
hir::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
|
||||
_ => return Ok(()),
|
||||
}
|
||||
}
|
||||
ty::TyUint(uint_type) => {
|
||||
let (lhs, rhs) = match (const_to_opt_uint(te1),
|
||||
const_to_opt_uint(te2)) {
|
||||
(Some(v1), Some(v2)) => (v1, v2),
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
|
||||
match b.node {
|
||||
hir::BiAdd => const_uint_checked_add(lhs, rhs, e, opt_ety),
|
||||
hir::BiSub => const_uint_checked_sub(lhs, rhs, e, opt_ety),
|
||||
hir::BiMul => const_uint_checked_mul(lhs, rhs, e, opt_ety),
|
||||
hir::BiDiv => const_uint_checked_div(lhs, rhs, e, opt_ety),
|
||||
hir::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
|
||||
hir::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
|
||||
hir::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
|
||||
_ => return Ok(()),
|
||||
}
|
||||
}
|
||||
let (lhs, rhs) = match (to_const_int(te1, t, cx.tcx()), to_const_int(te2, t, cx.tcx())) {
|
||||
(Some(v1), Some(v2)) => (v1, v2),
|
||||
_ => return Ok(()),
|
||||
};
|
||||
let result = match b.node {
|
||||
hir::BiAdd => lhs + rhs,
|
||||
hir::BiSub => lhs - rhs,
|
||||
hir::BiMul => lhs * rhs,
|
||||
hir::BiDiv => lhs / rhs,
|
||||
hir::BiRem => lhs % rhs,
|
||||
hir::BiShl => lhs << rhs,
|
||||
hir::BiShr => lhs >> rhs,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
const_err(cx, e, result, trueconst)
|
||||
|
@ -1597,7 +1597,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
llvm::LLVMDIBuilderCreateEnumerator(
|
||||
DIB(cx),
|
||||
name.as_ptr(),
|
||||
v.disr_val as u64)
|
||||
v.disr_val.to_u64_unchecked())
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -26,7 +26,7 @@ impl ::std::ops::BitAnd for Disr {
|
||||
|
||||
impl From<::middle::ty::Disr> for Disr {
|
||||
fn from(i: ::middle::ty::Disr) -> Disr {
|
||||
Disr(i)
|
||||
Disr(i.to_u64_unchecked())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ use back::abi;
|
||||
use llvm::ValueRef;
|
||||
use middle::ty::{Ty, TypeFoldable};
|
||||
use rustc::middle::const_eval::{self, ConstVal};
|
||||
use rustc_const_eval::ConstInt::*;
|
||||
use rustc::mir::repr as mir;
|
||||
use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
|
||||
C_str_slice, C_nil, C_undef};
|
||||
@ -19,6 +20,7 @@ use trans::consts;
|
||||
use trans::expr;
|
||||
use trans::inline;
|
||||
use trans::type_of;
|
||||
use trans::type_::Type;
|
||||
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::MirContext;
|
||||
@ -63,8 +65,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
match *cv {
|
||||
ConstVal::Float(v) => C_floating_f64(v, llty),
|
||||
ConstVal::Bool(v) => C_bool(ccx, v),
|
||||
ConstVal::Int(v) => C_integral(llty, v as u64, true),
|
||||
ConstVal::Uint(v) => C_integral(llty, v, false),
|
||||
ConstVal::Integral(I8(v)) => C_integral(Type::i8(ccx), v as u64, true),
|
||||
ConstVal::Integral(I16(v)) => C_integral(Type::i16(ccx), v as u64, true),
|
||||
ConstVal::Integral(I32(v)) => C_integral(Type::i32(ccx), v as u64, true),
|
||||
ConstVal::Integral(I64(v)) => C_integral(Type::i64(ccx), v as u64, true),
|
||||
ConstVal::Integral(Isize(v)) => {
|
||||
let i = v.as_i64(ccx.tcx().sess.target.int_type);
|
||||
C_integral(Type::int(ccx), i as u64, true)
|
||||
},
|
||||
ConstVal::Integral(U8(v)) => C_integral(Type::i8(ccx), v as u64, false),
|
||||
ConstVal::Integral(U16(v)) => C_integral(Type::i16(ccx), v as u64, false),
|
||||
ConstVal::Integral(U32(v)) => C_integral(Type::i32(ccx), v as u64, false),
|
||||
ConstVal::Integral(U64(v)) => C_integral(Type::i64(ccx), v, false),
|
||||
ConstVal::Integral(Usize(v)) => {
|
||||
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
|
||||
C_integral(Type::int(ccx), u, false)
|
||||
},
|
||||
ConstVal::Integral(Infer(v)) => C_integral(llty, v as u64, false),
|
||||
ConstVal::Integral(InferSigned(v)) => C_integral(llty, v as u64, true),
|
||||
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
|
||||
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
|
||||
ConstVal::Struct(id) | ConstVal::Tuple(id) |
|
||||
@ -74,6 +92,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
expr::trans(bcx, expr).datum.val
|
||||
})
|
||||
},
|
||||
ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
|
||||
ConstVal::Dummy => unreachable!(),
|
||||
ConstVal::Function(_) => C_nil(ccx)
|
||||
}
|
||||
}
|
||||
@ -99,7 +119,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
|
||||
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
|
||||
let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs))
|
||||
.expect("def was const, but lookup_const_by_id failed");
|
||||
.expect("def was const, but lookup_const_by_id failed").0;
|
||||
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
|
||||
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
|
||||
let d = bcx.with_block(|bcx| {
|
||||
|
@ -11,6 +11,8 @@
|
||||
use llvm::ValueRef;
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use middle::ty::cast::{CastTy, IntTy};
|
||||
use middle::const_eval::ConstVal;
|
||||
use rustc_const_eval::ConstInt;
|
||||
use rustc::mir::repr as mir;
|
||||
|
||||
use trans::asm;
|
||||
@ -95,7 +97,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
|
||||
mir::Rvalue::Repeat(ref elem, ref count) => {
|
||||
let tr_elem = self.trans_operand(&bcx, elem);
|
||||
let size = self.trans_constval(&bcx, &count.value, count.ty).immediate();
|
||||
let count = ConstVal::Integral(ConstInt::Usize(count.value));
|
||||
let size = self.trans_constval(&bcx, &count, bcx.tcx().types.usize).immediate();
|
||||
let bcx = bcx.map_block(|block| {
|
||||
let base = expr::get_dataptr(block, dest.llval);
|
||||
tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
|
||||
|
@ -15,5 +15,6 @@ arena = { path = "../libarena" }
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_back = { path = "../librustc_back" }
|
||||
rustc_const_eval = { path = "../librustc_const_eval" }
|
||||
rustc_front = { path = "../librustc_front" }
|
||||
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
|
||||
|
@ -65,6 +65,8 @@ use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||
use util::nodemap::FnvHashSet;
|
||||
|
||||
use rustc_const_eval::ConstInt;
|
||||
|
||||
use syntax::{abi, ast};
|
||||
use syntax::codemap::{Span, Pos};
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
@ -1680,22 +1682,16 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
|
||||
hir::TyFixedLengthVec(ref ty, ref e) => {
|
||||
let hint = UncheckedExprHint(tcx.types.usize);
|
||||
match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
|
||||
Ok(r) => {
|
||||
match r {
|
||||
ConstVal::Int(i) =>
|
||||
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
|
||||
i as usize),
|
||||
ConstVal::Uint(i) =>
|
||||
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty),
|
||||
i as usize),
|
||||
_ => {
|
||||
span_err!(tcx.sess, ast_ty.span, E0249,
|
||||
"expected constant integer expression \
|
||||
for array length");
|
||||
this.tcx().types.err
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
|
||||
let i = i.as_u64(tcx.sess.target.uint_type);
|
||||
assert_eq!(i as usize as u64, i);
|
||||
tcx.mk_array(ast_ty_to_ty(this, rscope, &ty), i as usize)
|
||||
},
|
||||
Ok(val) => {
|
||||
span_err!(tcx.sess, ast_ty.span, E0249,
|
||||
"expected usize value for array length, got {}", val.description());
|
||||
this.tcx().types.err
|
||||
},
|
||||
Err(ref r) => {
|
||||
let mut err = struct_span_err!(tcx.sess, r.span, E0250,
|
||||
"array length constant evaluation error: {}",
|
||||
|
@ -94,7 +94,7 @@ use middle::pat_util::{self, pat_id_map};
|
||||
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
|
||||
use middle::traits::{self, report_fulfillment_errors};
|
||||
use middle::ty::{GenericPredicates, TypeScheme};
|
||||
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{ParamTy, ParameterEnvironment};
|
||||
use middle::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
|
||||
use middle::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
|
||||
use middle::ty::{MethodCall, MethodCallee};
|
||||
@ -102,7 +102,7 @@ use middle::ty::adjustment;
|
||||
use middle::ty::error::TypeError;
|
||||
use middle::ty::fold::{TypeFolder, TypeFoldable};
|
||||
use middle::ty::relate::TypeRelation;
|
||||
use middle::ty::util::Representability;
|
||||
use middle::ty::util::{Representability, IntTypeExt};
|
||||
use require_c_abi_if_variadic;
|
||||
use rscope::{ElisionFailureInfo, RegionScope};
|
||||
use session::{Session, CompileResult};
|
||||
@ -4076,34 +4076,6 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
sp: Span,
|
||||
vs: &'tcx [hir::Variant],
|
||||
id: ast::NodeId) {
|
||||
// disr_in_range should be removed once we have forced type hints for consts
|
||||
fn disr_in_range(ccx: &CrateCtxt,
|
||||
ty: attr::IntType,
|
||||
disr: ty::Disr) -> bool {
|
||||
fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
|
||||
match ty {
|
||||
ast::UintTy::U8 => disr as u8 as Disr == disr,
|
||||
ast::UintTy::U16 => disr as u16 as Disr == disr,
|
||||
ast::UintTy::U32 => disr as u32 as Disr == disr,
|
||||
ast::UintTy::U64 => disr as u64 as Disr == disr,
|
||||
ast::UintTy::Us => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
|
||||
}
|
||||
}
|
||||
fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
|
||||
match ty {
|
||||
ast::IntTy::I8 => disr as i8 as Disr == disr,
|
||||
ast::IntTy::I16 => disr as i16 as Disr == disr,
|
||||
ast::IntTy::I32 => disr as i32 as Disr == disr,
|
||||
ast::IntTy::I64 => disr as i64 as Disr == disr,
|
||||
ast::IntTy::Is => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
|
||||
}
|
||||
}
|
||||
match ty {
|
||||
attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
|
||||
attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
|
||||
}
|
||||
}
|
||||
|
||||
fn do_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
vs: &'tcx [hir::Variant],
|
||||
id: ast::NodeId,
|
||||
@ -4117,7 +4089,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
let inh = static_inherited_fields(ccx, &tables);
|
||||
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), id);
|
||||
|
||||
let (_, repr_type_ty) = ccx.tcx.enum_repr_type(Some(&hint));
|
||||
let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(&ccx.tcx);
|
||||
for v in vs {
|
||||
if let Some(ref e) = v.node.disr_expr {
|
||||
check_const_with_ty(&fcx, e.span, e, repr_type_ty);
|
||||
@ -4142,23 +4114,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
// Check for unrepresentable discriminant values
|
||||
match hint {
|
||||
attr::ReprAny | attr::ReprExtern => {
|
||||
disr_vals.push(current_disr_val);
|
||||
}
|
||||
attr::ReprInt(sp, ity) => {
|
||||
if !disr_in_range(ccx, ity, current_disr_val) {
|
||||
let mut err = struct_span_err!(ccx.tcx.sess, v.span, E0082,
|
||||
"discriminant value outside specified type");
|
||||
span_note!(&mut err, sp,
|
||||
"discriminant type specified here");
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
// Error reported elsewhere.
|
||||
attr::ReprSimd | attr::ReprPacked => {}
|
||||
}
|
||||
disr_vals.push(current_disr_val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,8 @@ use util::common::{ErrorReported, MemoizationMap};
|
||||
use util::nodemap::{FnvHashMap, FnvHashSet};
|
||||
use write_ty_to_tcx;
|
||||
|
||||
use rustc_const_eval::ConstInt;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
@ -1012,7 +1014,7 @@ fn convert_struct_def<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
tcx.intern_adt_def(
|
||||
did,
|
||||
ty::AdtKind::Struct,
|
||||
vec![convert_struct_variant(tcx, ctor_id, it.name, 0, def)]
|
||||
vec![convert_struct_variant(tcx, ctor_id, it.name, ConstInt::Infer(0), def)]
|
||||
)
|
||||
}
|
||||
|
||||
@ -1021,24 +1023,39 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
def: &hir::EnumDef)
|
||||
-> ty::AdtDefMaster<'tcx>
|
||||
{
|
||||
fn print_err(tcx: &TyCtxt, span: Span, ty: ty::Ty, cv: ConstVal) {
|
||||
span_err!(tcx.sess, span, E0079, "mismatched types: expected `{}` got `{}`",
|
||||
ty, cv.description());
|
||||
}
|
||||
fn evaluate_disr_expr<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
repr_ty: Ty<'tcx>,
|
||||
repr_ty: attr::IntType,
|
||||
e: &hir::Expr) -> Option<ty::Disr> {
|
||||
debug!("disr expr, checking {}", pprust::expr_to_string(e));
|
||||
|
||||
let hint = UncheckedExprHint(repr_ty);
|
||||
let ty_hint = repr_ty.to_ty(tcx);
|
||||
let hint = UncheckedExprHint(ty_hint);
|
||||
match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
|
||||
Ok(ConstVal::Int(val)) => Some(val as ty::Disr),
|
||||
Ok(ConstVal::Uint(val)) => Some(val as ty::Disr),
|
||||
Ok(_) => {
|
||||
let sign_desc = if repr_ty.is_signed() {
|
||||
"signed"
|
||||
} else {
|
||||
"unsigned"
|
||||
};
|
||||
span_err!(tcx.sess, e.span, E0079,
|
||||
"expected {} integer constant",
|
||||
sign_desc);
|
||||
Ok(ConstVal::Integral(i)) => {
|
||||
// FIXME: eval_const_expr_partial should return an error if the hint is wrong
|
||||
match (repr_ty, i) {
|
||||
(attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => Some(i),
|
||||
(attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => Some(i),
|
||||
(attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => Some(i),
|
||||
(attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => Some(i),
|
||||
(attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => Some(i),
|
||||
(attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => Some(i),
|
||||
(attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => Some(i),
|
||||
(attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => Some(i),
|
||||
(attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => Some(i),
|
||||
(attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i),
|
||||
(_, i) => {
|
||||
print_err(tcx, e.span, ty_hint, ConstVal::Integral(i));
|
||||
None
|
||||
},
|
||||
}
|
||||
},
|
||||
Ok(cv) => {
|
||||
print_err(tcx, e.span, ty_hint, cv);
|
||||
None
|
||||
},
|
||||
Err(err) => {
|
||||
@ -1057,16 +1074,11 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
fn report_discrim_overflow(tcx: &TyCtxt,
|
||||
variant_span: Span,
|
||||
variant_name: &str,
|
||||
repr_type: attr::IntType,
|
||||
prev_val: ty::Disr) {
|
||||
let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
|
||||
let computed_value = repr_type.disr_string(computed_value);
|
||||
let prev_val = repr_type.disr_string(prev_val);
|
||||
let repr_type = repr_type.to_ty(tcx);
|
||||
span_err!(tcx.sess, variant_span, E0370,
|
||||
"enum discriminant overflowed on value after {}: {}; \
|
||||
"enum discriminant overflowed on value after {}; \
|
||||
set explicitly via {} = {} if that is desired outcome",
|
||||
prev_val, repr_type, variant_name, computed_value);
|
||||
prev_val, variant_name, prev_val.wrap_incr());
|
||||
}
|
||||
|
||||
fn next_disr(tcx: &TyCtxt,
|
||||
@ -1076,12 +1088,11 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
if let Some(prev_disr_val) = prev_disr_val {
|
||||
let result = repr_type.disr_incr(prev_disr_val);
|
||||
if let None = result {
|
||||
report_discrim_overflow(tcx, v.span, &v.node.name.as_str(),
|
||||
repr_type, prev_disr_val);
|
||||
report_discrim_overflow(tcx, v.span, &v.node.name.as_str(), prev_disr_val);
|
||||
}
|
||||
result
|
||||
} else {
|
||||
Some(ty::INITIAL_DISCRIMINANT_VALUE)
|
||||
Some(repr_type.initial_discriminant(tcx))
|
||||
}
|
||||
}
|
||||
fn convert_enum_variant<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
@ -1095,17 +1106,19 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
}
|
||||
let did = tcx.map.local_def_id(it.id);
|
||||
let repr_hints = tcx.lookup_repr_hints(did);
|
||||
let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0));
|
||||
let repr_type = tcx.enum_repr_type(repr_hints.get(0));
|
||||
let mut prev_disr = None;
|
||||
let variants = def.variants.iter().map(|v| {
|
||||
let disr = match v.node.disr_expr {
|
||||
Some(ref e) => evaluate_disr_expr(tcx, repr_type_ty, e),
|
||||
Some(ref e) => evaluate_disr_expr(tcx, repr_type, e),
|
||||
None => next_disr(tcx, v, repr_type, prev_disr)
|
||||
}.unwrap_or(repr_type.disr_wrap_incr(prev_disr));
|
||||
}.unwrap_or_else(|| {
|
||||
prev_disr.map(ty::Disr::wrap_incr)
|
||||
.unwrap_or(repr_type.initial_discriminant(tcx))
|
||||
});
|
||||
|
||||
let v = convert_enum_variant(tcx, v, disr);
|
||||
prev_disr = Some(disr);
|
||||
v
|
||||
convert_enum_variant(tcx, v, disr)
|
||||
}).collect();
|
||||
tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
|
||||
}
|
||||
|
@ -91,6 +91,7 @@ extern crate rustc;
|
||||
extern crate rustc_platform_intrinsics as intrinsics;
|
||||
extern crate rustc_front;
|
||||
extern crate rustc_back;
|
||||
extern crate rustc_const_eval;
|
||||
|
||||
pub use rustc::dep_graph;
|
||||
pub use rustc::front;
|
||||
|
@ -337,7 +337,7 @@ pub fn build_impl(cx: &DocContext,
|
||||
let type_scheme = tcx.lookup_item_type(did);
|
||||
let default = if assoc_const.has_value {
|
||||
Some(const_eval::lookup_const_by_id(tcx, did, None, None)
|
||||
.unwrap().span.to_src(cx))
|
||||
.unwrap().0.span.to_src(cx))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -479,7 +479,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
|
||||
use rustc::middle::const_eval;
|
||||
use rustc_front::print::pprust;
|
||||
|
||||
let expr = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
|
||||
let (expr, ty) = const_eval::lookup_const_by_id(tcx, did, None, None).unwrap_or_else(|| {
|
||||
panic!("expected lookup_const_by_id to succeed for {:?}", did);
|
||||
});
|
||||
debug!("converting constant expr {:?} to snippet", expr);
|
||||
@ -487,7 +487,7 @@ fn build_const(cx: &DocContext, tcx: &TyCtxt,
|
||||
debug!("got snippet {}", sn);
|
||||
|
||||
clean::Constant {
|
||||
type_: tcx.lookup_item_type(did).ty.clean(cx),
|
||||
type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.lookup_item_type(did).ty.clean(cx)),
|
||||
expr: sn
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#[macro_use] extern crate rustc;
|
||||
extern crate rustc_front;
|
||||
extern crate rustc_plugin;
|
||||
extern crate rustc_const_eval;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc::mir::transform::{self, MirPass};
|
||||
@ -23,6 +24,7 @@ use rustc::mir::repr::{Mir, Literal};
|
||||
use rustc::mir::visit::MutVisitor;
|
||||
use rustc::middle::ty;
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc_const_eval::ConstInt;
|
||||
use rustc_plugin::Registry;
|
||||
|
||||
use syntax::ast::NodeId;
|
||||
@ -40,8 +42,10 @@ struct Visitor;
|
||||
|
||||
impl<'tcx> MutVisitor<'tcx> for Visitor {
|
||||
fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
|
||||
if let Literal::Value { value: ConstVal::Int(ref mut i @ 11) } = *literal {
|
||||
*i = 42;
|
||||
if let Literal::Value { ref mut value } = *literal {
|
||||
if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
|
||||
*i = 42;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ fn main() {
|
||||
//~^ WARN attempted to add with overflow
|
||||
//~^^ WARN attempted to add with overflow
|
||||
let c = 200u8 * 4;
|
||||
//~^ WARN attempted to mul with overflow
|
||||
//~^ WARN attempted to multiply with overflow
|
||||
let d = 42u8 - (42u8 + 1);
|
||||
//~^ WARN attempted to sub with overflow
|
||||
//~^ WARN attempted to subtract with overflow
|
||||
let _e = BLA;
|
||||
black_box(a);
|
||||
black_box(b);
|
||||
|
@ -21,10 +21,11 @@ const NEG_128: i8 = -128;
|
||||
const NEG_NEG_128: i8 = -NEG_128;
|
||||
//~^ ERROR constant evaluation error: attempted to negate with overflow
|
||||
//~| ERROR attempted to negate with overflow
|
||||
//~| ERROR attempted to negate with overflow
|
||||
|
||||
fn main() {
|
||||
match -128i8 {
|
||||
NEG_NEG_128 => println!("A"),
|
||||
NEG_NEG_128 => println!("A"), //~ NOTE in pattern here
|
||||
_ => println!("B"),
|
||||
}
|
||||
}
|
||||
|
@ -36,4 +36,3 @@ fn main() {
|
||||
fn foo<T:fmt::Debug>(x: T) {
|
||||
println!("{:?}", x);
|
||||
}
|
||||
|
||||
|
@ -21,8 +21,9 @@ use std::{u8, u16, u32, u64, usize};
|
||||
|
||||
const A_I8_T
|
||||
: [u32; (i8::MAX as i8 + 1u8) as usize]
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR the trait `core::ops::Add<u8>` is not implemented for the type `i8`
|
||||
//~^ ERROR mismatched types:
|
||||
//~| expected `i8`,
|
||||
//~| found `u8` [E0250]
|
||||
= [0; (i8::MAX as usize) + 1];
|
||||
|
||||
fn main() {
|
||||
|
@ -23,84 +23,84 @@ const VALS_I8: (i8, i8, i8, i8) =
|
||||
(-i8::MIN,
|
||||
//~^ ERROR attempted to negate with overflow
|
||||
i8::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
i8::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
i8::MIN * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
const VALS_I16: (i16, i16, i16, i16) =
|
||||
(-i16::MIN,
|
||||
//~^ ERROR attempted to negate with overflow
|
||||
i16::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
i16::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
i16::MIN * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
const VALS_I32: (i32, i32, i32, i32) =
|
||||
(-i32::MIN,
|
||||
//~^ ERROR attempted to negate with overflow
|
||||
i32::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
i32::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
i32::MIN * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
const VALS_I64: (i64, i64, i64, i64) =
|
||||
(-i64::MIN,
|
||||
//~^ ERROR attempted to negate with overflow
|
||||
i64::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
i64::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
i64::MAX * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
const VALS_U8: (u8, u8, u8, u8) =
|
||||
(-(u8::MIN as i8) as u8,
|
||||
u8::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
u8::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
u8::MAX * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
const VALS_U16: (u16, u16, u16, u16) =
|
||||
(-(u16::MIN as i16) as u16,
|
||||
u16::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
u16::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
u16::MAX * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
const VALS_U32: (u32, u32, u32, u32) =
|
||||
(-(u32::MIN as i32) as u32,
|
||||
u32::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
u32::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
u32::MAX * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
const VALS_U64: (u64, u64, u64, u64) =
|
||||
(-(u64::MIN as i64) as u64,
|
||||
u64::MIN - 1,
|
||||
//~^ ERROR attempted to sub with overflow
|
||||
//~^ ERROR attempted to subtract with overflow
|
||||
u64::MAX + 1,
|
||||
//~^ ERROR attempted to add with overflow
|
||||
u64::MAX * 2,
|
||||
//~^ ERROR attempted to mul with overflow
|
||||
//~^ ERROR attempted to multiply with overflow
|
||||
);
|
||||
|
||||
fn main() {
|
||||
|
@ -8,32 +8,30 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const X: usize = 42 && 39; //~ ERROR: can't do this op on unsigned integrals
|
||||
const X: usize = 42 && 39; //~ ERROR: can't do this op on integrals
|
||||
const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
|
||||
|
||||
const X1: usize = 42 || 39; //~ ERROR: can't do this op on unsigned integrals
|
||||
const X1: usize = 42 || 39; //~ ERROR: can't do this op on integrals
|
||||
const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
|
||||
|
||||
// FIXME: the error should be `on signed integrals`
|
||||
const X2: usize = -42 || -39; //~ ERROR: can't do this op on unsigned integrals
|
||||
const X2: usize = -42 || -39; //~ ERROR: unary negation of unsigned integer
|
||||
const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
|
||||
|
||||
// FIXME: the error should be `on signed integrals`
|
||||
const X3: usize = -42 && -39; //~ ERROR: can't do this op on unsigned integrals
|
||||
const X3: usize = -42 && -39; //~ ERROR: unary negation of unsigned integer
|
||||
const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
|
||||
|
||||
const Y: usize = 42.0 == 42.0;
|
||||
const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
|
||||
const ARRR: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
|
||||
const Y1: usize = 42.0 >= 42.0;
|
||||
const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
|
||||
const ARRR1: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
|
||||
const Y2: usize = 42.0 <= 42.0;
|
||||
const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected constant integer expression for array length
|
||||
const ARRR2: [i32; Y] = [99; 1]; //~ ERROR: expected usize value for array length
|
||||
const Y3: usize = 42.0 > 42.0;
|
||||
const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
|
||||
const ARRR3: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
|
||||
const Y4: usize = 42.0 < 42.0;
|
||||
const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
|
||||
const ARRR4: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
|
||||
const Y5: usize = 42.0 != 42.0;
|
||||
const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected constant integer expression for array length
|
||||
const ARRR5: [i32; Y] = [99; 0]; //~ ERROR: expected usize value for array length
|
||||
|
||||
fn main() {
|
||||
let _ = ARR;
|
||||
|
@ -15,7 +15,7 @@
|
||||
const ONE: usize = 1;
|
||||
const TWO: usize = 2;
|
||||
const LEN: usize = ONE - TWO;
|
||||
//~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
|
||||
//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
|
||||
|
||||
fn main() {
|
||||
let a: [i8; LEN] = unimplemented!();
|
||||
|
@ -16,5 +16,5 @@ const TWO: usize = 2;
|
||||
|
||||
fn main() {
|
||||
let a: [i8; ONE - TWO] = unimplemented!();
|
||||
//~^ ERROR array length constant evaluation error: attempted to sub with overflow [E0250]
|
||||
//~^ ERROR array length constant evaluation error: attempted to subtract with overflow [E0250]
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
// Test spans of errors
|
||||
|
||||
const TUP: (usize,) = 5 << 64;
|
||||
//~^ ERROR: attempted left shift with overflow [E0250]
|
||||
//~^ ERROR: attempted to shift left with overflow [E0250]
|
||||
const ARR: [i32; TUP.0] = [];
|
||||
|
||||
fn main() {
|
||||
|
@ -24,7 +24,7 @@ fn f_i8() {
|
||||
enum A {
|
||||
Ok = i8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ fn f_u8() {
|
||||
enum A {
|
||||
Ok = u8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ fn f_i8() {
|
||||
enum A {
|
||||
Ok = i8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 127: i8; set explicitly via OhNo = -128 if that is desired outcome
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 127i8; set explicitly via OhNo = -128i8 if that is desired outcome
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
@ -33,7 +33,7 @@ fn f_u8() {
|
||||
enum A {
|
||||
Ok = u8::MAX - 1,
|
||||
Ok2,
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 255: u8; set explicitly via OhNo = 0 if that is desired outcome
|
||||
OhNo, //~ ERROR enum discriminant overflowed on value after 255u8; set explicitly via OhNo = 0u8 if that is desired outcome
|
||||
}
|
||||
|
||||
let x = A::Ok;
|
||||
|
@ -9,46 +9,32 @@
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
#[repr(u8)] //~ NOTE discriminant type specified here
|
||||
#[repr(u8)]
|
||||
enum Eu8 {
|
||||
Au8 = 23,
|
||||
Bu8 = 223,
|
||||
Cu8 = -23, //~ ERROR discriminant value outside specified type
|
||||
Cu8 = -23, //~ ERROR unary negation of unsigned integer
|
||||
}
|
||||
|
||||
#[repr(i8)] //~ NOTE discriminant type specified here
|
||||
enum Ei8 {
|
||||
Ai8 = 23,
|
||||
Bi8 = -23,
|
||||
Ci8 = 223, //~ ERROR discriminant value outside specified type
|
||||
}
|
||||
|
||||
#[repr(u16)] //~ NOTE discriminant type specified here
|
||||
#[repr(u16)]
|
||||
enum Eu16 {
|
||||
Au16 = 23,
|
||||
Bu16 = 55555,
|
||||
Cu16 = -22333, //~ ERROR discriminant value outside specified type
|
||||
Cu16 = -22333, //~ ERROR unary negation of unsigned integer
|
||||
}
|
||||
|
||||
#[repr(i16)] //~ NOTE discriminant type specified here
|
||||
enum Ei16 {
|
||||
Ai16 = 23,
|
||||
Bi16 = -22333,
|
||||
Ci16 = 55555, //~ ERROR discriminant value outside specified type
|
||||
}
|
||||
|
||||
#[repr(u32)] //~ NOTE discriminant type specified here
|
||||
#[repr(u32)]
|
||||
enum Eu32 {
|
||||
Au32 = 23,
|
||||
Bu32 = 3_000_000_000,
|
||||
Cu32 = -2_000_000_000, //~ ERROR discriminant value outside specified type
|
||||
Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
|
||||
}
|
||||
|
||||
#[repr(i32)] //~ NOTE discriminant type specified here
|
||||
enum Ei32 {
|
||||
Ai32 = 23,
|
||||
Bi32 = -2_000_000_000,
|
||||
Ci32 = 3_000_000_000, //~ ERROR discriminant value outside specified type
|
||||
#[repr(u64)]
|
||||
enum Eu64 {
|
||||
Au32 = 23,
|
||||
Bu32 = 3_000_000_000,
|
||||
Cu32 = -2_000_000_000, //~ ERROR unary negation of unsigned integer
|
||||
}
|
||||
|
||||
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
|
||||
|
47
src/test/compile-fail/enum-discrim-too-small2.rs
Normal file
47
src/test/compile-fail/enum-discrim-too-small2.rs
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![deny(overflowing_literals)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[repr(i8)]
|
||||
enum Ei8 {
|
||||
Ai8 = 23,
|
||||
Bi8 = -23,
|
||||
Ci8 = 223, //~ ERROR literal out of range for i8
|
||||
}
|
||||
|
||||
#[repr(i16)]
|
||||
enum Ei16 {
|
||||
Ai16 = 23,
|
||||
Bi16 = -22333,
|
||||
Ci16 = 55555, //~ ERROR literal out of range for i16
|
||||
}
|
||||
|
||||
#[repr(i32)]
|
||||
enum Ei32 {
|
||||
Ai32 = 23,
|
||||
Bi32 = -2_000_000_000,
|
||||
Ci32 = 3_000_000_000, //~ ERROR literal out of range for i32
|
||||
}
|
||||
|
||||
#[repr(i64)]
|
||||
enum Ei64 {
|
||||
Ai64 = 23,
|
||||
Bi64 = -9223372036854775808,
|
||||
Ci64 = 9223372036854775809, //~ ERROR literal out of range for i64
|
||||
}
|
||||
|
||||
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
|
||||
// little counterintuitive, but since the discriminant can store all the bits, and extracting it
|
||||
// with a cast requires specifying the signedness, there is no loss of information in those cases.
|
||||
// This also applies to isize and usize on 64-bit targets.
|
||||
|
||||
pub fn main() { }
|
@ -10,7 +10,8 @@
|
||||
|
||||
enum test {
|
||||
div_zero = 1/0, //~ERROR constant evaluation error: attempted to divide by zero
|
||||
rem_zero = 1%0 //~ERROR constant evaluation error: attempted remainder with a divisor of zero
|
||||
rem_zero = 1%0,
|
||||
//~^ ERROR constant evaluation error: attempted to calculate the remainder with a divisor of zero
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -21,22 +21,7 @@ const _MAX: usize = -1;
|
||||
//~| HELP use a cast or the `!` operator
|
||||
|
||||
fn main() {
|
||||
let a = -1;
|
||||
//~^ ERROR unary negation of unsigned integer
|
||||
//~| HELP use a cast or the `!` operator
|
||||
let _b : u8 = a; // for infering variable a to u8.
|
||||
|
||||
-a;
|
||||
//~^ ERROR unary negation of unsigned integer
|
||||
//~| HELP use a cast or the `!` operator
|
||||
|
||||
let _d = -1u8;
|
||||
//~^ ERROR unary negation of unsigned integer
|
||||
//~| HELP use a cast or the `!` operator
|
||||
|
||||
for _ in -10..10u8 {}
|
||||
//~^ ERROR unary negation of unsigned integer
|
||||
//~| HELP use a cast or the `!` operator
|
||||
|
||||
let x = 5u8;
|
||||
let _y = -x; //~ ERROR unary negation of unsigned integer
|
||||
-S; // should not trigger the gate; issue 26840
|
||||
}
|
||||
|
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 {
|
||||
A = 1,
|
||||
B = 1, //~ ERROR discriminant value `1` already exists
|
||||
B = 1, //~ ERROR discriminant value `1isize` already exists
|
||||
//~^^ NOTE conflicting
|
||||
C = 0,
|
||||
D, //~ ERROR discriminant value `1` already exists
|
||||
D, //~ ERROR discriminant value `1isize` already exists
|
||||
//~^^^^^ NOTE conflicting
|
||||
E = N, //~ ERROR discriminant value `1` already exists
|
||||
E = N, //~ ERROR discriminant value `1isize` already exists
|
||||
//~^^^^^^^ NOTE conflicting
|
||||
}
|
||||
|
||||
|
@ -35,23 +35,23 @@ fn main() {
|
||||
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
|
||||
//~^ ERROR attempted to divide by zero
|
||||
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with overflow
|
||||
//~^ ERROR attempted to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with overflow
|
||||
//~^ ERROR attempted to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with overflow
|
||||
//~^ ERROR attempted to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with overflow
|
||||
//~^ ERROR attempted to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with overflow
|
||||
//~^ ERROR attempted to calculate the remainder with overflow
|
||||
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with a divisor of zero
|
||||
//~^ ERROR attempted to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with a divisor of zero
|
||||
//~^ ERROR attempted to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with a divisor of zero
|
||||
//~^ ERROR attempted to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with a divisor of zero
|
||||
//~^ ERROR attempted to calculate the remainder with a divisor of zero
|
||||
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
|
||||
//~^ ERROR attempted remainder with a divisor of zero
|
||||
//~^ ERROR attempted to calculate the remainder with a divisor of zero
|
||||
}
|
||||
|
@ -10,13 +10,13 @@
|
||||
|
||||
enum Foo {
|
||||
A = 1i64,
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `isize`
|
||||
//~| found `i64`
|
||||
//~^ ERROR mismatched types:
|
||||
//~| expected `isize`,
|
||||
//~| found `i64` [E0080]
|
||||
B = 2u8
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `isize`
|
||||
//~| found `u8`
|
||||
//~^ ERROR mismatched types:
|
||||
//~| expected `isize`,
|
||||
//~| found `u8` [E0080]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -24,11 +24,6 @@ fn bar() -> i8 {
|
||||
return 123;
|
||||
}
|
||||
|
||||
fn baz() -> bool {
|
||||
128 > bar() //~ ERROR comparison is useless due to type limits
|
||||
//~^ WARNING literal out of range for i8
|
||||
}
|
||||
|
||||
fn bleh() {
|
||||
let u = 42u8;
|
||||
let _ = u > 255; //~ ERROR comparison is useless due to type limits
|
||||
@ -40,11 +35,3 @@ fn bleh() {
|
||||
let _ = u >= 0; //~ ERROR comparison is useless due to type limits
|
||||
let _ = 0 <= u; //~ ERROR comparison is useless due to type limits
|
||||
}
|
||||
|
||||
fn qux() {
|
||||
let mut i = 1i8;
|
||||
while 200 != i { //~ ERROR comparison is useless due to type limits
|
||||
//~^ WARNING literal out of range for i8
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
24
src/test/compile-fail/lint-type-limits2.rs
Normal file
24
src/test/compile-fail/lint-type-limits2.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// compile-flags: -D unused-comparisons
|
||||
fn main() { }
|
||||
|
||||
|
||||
fn bar() -> i8 {
|
||||
return 123;
|
||||
}
|
||||
|
||||
fn baz() -> bool {
|
||||
128 > bar() //~ ERROR comparison is useless due to type limits
|
||||
//~| WARN literal out of range for i8
|
||||
}
|
22
src/test/compile-fail/lint-type-limits3.rs
Normal file
22
src/test/compile-fail/lint-type-limits3.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
// compile-flags: -D unused-comparisons
|
||||
fn main() { }
|
||||
|
||||
fn qux() {
|
||||
let mut i = 1i8;
|
||||
while 200 != i { //~ ERROR comparison is useless due to type limits
|
||||
//~| WARN literal out of range for i8
|
||||
i += 1;
|
||||
}
|
||||
}
|
@ -25,7 +25,6 @@ fn main() {
|
||||
|
||||
let x2: i8 = -128; // should be OK
|
||||
let x1: i8 = 128; //~ error: literal out of range for i8
|
||||
let x2: i8 = --128; //~ error: literal out of range for i8
|
||||
|
||||
let x3: i8 = -129; //~ error: literal out of range for i8
|
||||
let x3: i8 = -(129); //~ error: literal out of range for i8
|
||||
@ -54,9 +53,4 @@ fn main() {
|
||||
let x = 18446744073709551615_i64; //~ error: literal out of range for i64
|
||||
let x: i64 = -9223372036854775809; //~ error: literal out of range for i64
|
||||
let x = -9223372036854775809_i64; //~ error: literal out of range for i64
|
||||
|
||||
let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
|
||||
let x = 3.40282348e+38_f32; //~ error: literal out of range for f32
|
||||
let x = -1.7976931348623159e+308_f64; //~ error: literal out of range for f64
|
||||
let x = 1.7976931348623159e+308_f64; //~ error: literal out of range for f64
|
||||
}
|
||||
|
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
|
||||
}
|
@ -43,13 +43,17 @@ fn main() {
|
||||
let f = [0; -4_isize];
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `usize`
|
||||
//~| found `isize`
|
||||
//~| ERROR expected positive integer for repeat count, found negative integer [E0306]
|
||||
//~| found `isize` [E0308]
|
||||
//~| ERROR mismatched types:
|
||||
//~| expected `usize`,
|
||||
//~| found `isize` [E0307]
|
||||
let f = [0_usize; -1_isize];
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `usize`
|
||||
//~| found `isize`
|
||||
//~| ERROR expected positive integer for repeat count, found negative integer [E0306]
|
||||
//~| found `isize` [E0308]
|
||||
//~| ERROR mismatched types
|
||||
//~| expected `usize`
|
||||
//~| found `isize` [E0307]
|
||||
struct G {
|
||||
g: (),
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
// A very basic test of const fn functionality.
|
||||
|
||||
#![feature(const_fn)]
|
||||
#![feature(const_fn, const_indexing)]
|
||||
|
||||
const fn add(x: u32, y: u32) -> u32 {
|
||||
x + y
|
||||
@ -24,6 +24,14 @@ const unsafe fn div(x: u32, y: u32) -> u32 {
|
||||
x / y
|
||||
}
|
||||
|
||||
const fn generic<T>(t: T) -> T {
|
||||
t
|
||||
}
|
||||
|
||||
const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
|
||||
t[0]
|
||||
}
|
||||
|
||||
const SUM: u32 = add(44, 22);
|
||||
const DIFF: u32 = sub(44, 22);
|
||||
const DIV: u32 = unsafe{div(44, 22)};
|
||||
@ -36,4 +44,6 @@ fn main() {
|
||||
assert_eq!(DIV, 2);
|
||||
|
||||
let _: [&'static str; sub(100, 99) as usize] = ["hi"];
|
||||
let _: [&'static str; generic(1)] = ["hi"];
|
||||
let _: [&'static str; generic_arr([1])] = ["hi"];
|
||||
}
|
||||
|
42
src/test/run-pass/const-negation.rs
Normal file
42
src/test/run-pass/const-negation.rs
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
||||
#[deny(const_err)]
|
||||
|
||||
fn main() {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const I: isize = -2147483648isize;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const I: isize = -9223372036854775808isize;
|
||||
assert_eq!(::std::i32::MIN as u64, 0xffffffff80000000);
|
||||
assert_eq!(-2147483648isize as u64, 0xffffffff80000000);
|
||||
assert_eq!(::std::i64::MIN as u64, 0x8000000000000000);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
assert_eq!(-9223372036854775808isize as u64, 0x8000000000000000);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
assert_eq!(-9223372036854775808isize as u64, 0);
|
||||
const J: usize = ::std::i32::MAX as usize;
|
||||
const K: usize = -1i32 as u32 as usize;
|
||||
const L: usize = ::std::i32::MIN as usize;
|
||||
const M: usize = ::std::i64::MIN as usize;
|
||||
match 5 {
|
||||
J => {},
|
||||
K => {},
|
||||
L => {},
|
||||
M => {},
|
||||
_ => {}
|
||||
}
|
||||
match 5 {
|
||||
I => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(stmt_expr_attributes)]
|
||||
|
||||
use std::mem::size_of;
|
||||
|
||||
@ -46,11 +47,6 @@ enum Ei64 {
|
||||
Bi64 = 0x8000_0000
|
||||
}
|
||||
|
||||
enum Eu64 {
|
||||
Au64 = 0,
|
||||
Bu64 = 0x8000_0000_0000_0000
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
assert_eq!(size_of::<Ei8>(), 1);
|
||||
assert_eq!(size_of::<Eu8>(), 1);
|
||||
@ -58,6 +54,8 @@ pub fn main() {
|
||||
assert_eq!(size_of::<Eu16>(), 2);
|
||||
assert_eq!(size_of::<Ei32>(), 4);
|
||||
assert_eq!(size_of::<Eu32>(), 4);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
assert_eq!(size_of::<Ei64>(), 8);
|
||||
assert_eq!(size_of::<Eu64>(), 8);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
assert_eq!(size_of::<Ei64>(), 4);
|
||||
}
|
||||
|
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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user