diff --git a/mk/crates.mk b/mk/crates.mk index 86bb3a8ca0ccc..57df102317f30 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,7 +59,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math rustc_incremental rustc_macro + rustc_const_eval rustc_const_math rustc_incremental rustc_macro rustc_i128 HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -96,22 +96,24 @@ DEPS_getopts := std DEPS_graphviz := std DEPS_log := std DEPS_num := std -DEPS_serialize := std log +DEPS_serialize := std log rustc_i128 DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers +DEPS_rustc_i128 = std -DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos +DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors \ + syntax_pos rustc_i128 DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize -DEPS_rustc_const_math := std syntax log serialize +DEPS_rustc_const_math := std syntax log serialize rustc_i128 DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \ - rustc_back graphviz syntax_pos + rustc_back graphviz syntax_pos rustc_i128 DEPS_rustc := syntax fmt_macros flate arena serialize getopts \ log graphviz rustc_llvm rustc_back rustc_data_structures\ - rustc_const_math syntax_pos rustc_errors + rustc_const_math syntax_pos rustc_errors rustc_i128 DEPS_rustc_back := std syntax flate log libc DEPS_rustc_borrowck := rustc log graphviz syntax syntax_pos rustc_errors rustc_mir DEPS_rustc_data_structures := std log serialize libc @@ -122,19 +124,20 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo rustc_passes rustc_save_analysis rustc_const_eval \ rustc_incremental syntax_pos rustc_errors rustc_macro DEPS_rustc_errors := log libc serialize syntax_pos -DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval +DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval rustc_i128 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags DEPS_rustc_macro := std syntax DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \ - rustc_macro syntax_ext + rustc_macro syntax_ext rustc_i128 DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors -DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags +DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags \ + rustc_i128 DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors DEPS_rustc_platform_intrinsics := std DEPS_rustc_plugin := rustc rustc_metadata syntax syntax_pos rustc_errors DEPS_rustc_privacy := rustc log syntax syntax_pos DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ - log syntax serialize rustc_llvm rustc_platform_intrinsics \ + log syntax serialize rustc_llvm rustc_platform_intrinsics rustc_i128 \ rustc_const_math rustc_const_eval rustc_incremental rustc_errors syntax_pos DEPS_rustc_incremental := rustc syntax_pos serialize rustc_data_structures DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize @@ -162,6 +165,7 @@ ONLY_RLIB_alloc := 1 ONLY_RLIB_rand := 1 ONLY_RLIB_collections := 1 ONLY_RLIB_rustc_unicode := 1 +ONLY_RLIB_rustc_i128 := 1 ONLY_RLIB_rustc_bitflags := 1 ONLY_RLIB_alloc_system := 1 ONLY_RLIB_alloc_jemalloc := 1 diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index fbcf5204d2537..3f23c9e414a88 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -17,3 +17,626 @@ #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] #![feature(staged_api)] +#![feature(core_intrinsics)] +#![feature(core_float)] +#![feature(associated_consts)] +#![cfg_attr(not(stage0), feature(i128_type))] + +#![allow(non_camel_case_types, unused_variables)] + + +#[cfg(any(target_pointer_width="32", target_pointer_width="16"))] +pub mod reimpls { + #![allow(unused_comparisons)] + // C API is expected to tolerate some amount of size mismatch in ABI. Hopefully the amount of + // handling is sufficient for bootstrapping. + #[cfg(stage0)] + type u128_ = u64; + #[cfg(stage0)] + type i128_ = i64; + #[cfg(not(stage0))] + type u128_ = u128; + #[cfg(not(stage0))] + type i128_ = i128; + + fn unimplemented() -> ! { + unsafe { ::core::intrinsics::abort() } + } + + macro_rules! ashl { + ($a:expr, $b:expr, $ty:ty) => {{ + let (a, b) = ($a, $b); + let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; + let half_bits = bits / 2; + if b & half_bits != 0 { + <$ty>::from_parts(0, a.low() << (b - half_bits)) + } else if b == 0 { + a + } else { + <$ty>::from_parts(a.low() << b, (a.high() << b) | (a.low() >> (half_bits - b))) + } + }} + } + + #[export_name="__ashlti3"] + pub extern fn shl(a: u128_, b: u128_) -> u128_ { + ashl!(a, b, u128_) + } + + macro_rules! ashr { + ($a: expr, $b: expr, $ty:ty) => {{ + let (a, b) = ($a, $b); + let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; + let half_bits = bits / 2; + if b & half_bits != 0 { + <$ty>::from_parts((a.high() >> (b - half_bits)) as <$ty as LargeInt>::LowHalf, + a.high() >> (half_bits - 1)) + } else if b == 0 { + a + } else { + let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; + <$ty>::from_parts((high_unsigned << (half_bits - b)) | (a.low() >> b), + a.high() >> b) + } + }} + } + + #[export_name="__ashrti3"] + pub extern fn shr(a: i128_, b: i128_) -> i128_ { + ashr!(a, b, i128_) + } + + macro_rules! lshr { + ($a: expr, $b: expr, $ty:ty) => {{ + let (a, b) = ($a, $b); + let bits = (::core::mem::size_of::<$ty>() * 8) as $ty; + let half_bits = bits / 2; + if b & half_bits != 0 { + <$ty>::from_parts(a.high() >> (b - half_bits), 0) + } else if b == 0 { + a + } else { + <$ty>::from_parts((a.high() << (half_bits - b)) | (a.low() >> b), a.high() >> b) + } + }} + } + + + #[export_name="__lshrti3"] + pub extern fn lshr(a: u128_, b: u128_) -> u128_ { + lshr!(a, b, u128_) + } + + #[cfg(stage0)] + #[export_name="__udivmodti4"] + pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + unsafe { + if !rem.is_null() { + *rem = n % d; + } + n / d + } + } + + #[cfg(not(stage0))] + #[export_name="__udivmodti4"] + pub extern fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + unsafe { + // NOTE X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + if !rem.is_null() { + *rem = u128::from(n.low() % d.low()); + } + return u128::from(n.low() / d.low()); + } else { + // 0 X + // --- + // K X + if !rem.is_null() { + *rem = n; + } + return 0; + }; + } + + let mut sr; + let mut q; + let mut r; + + if d.low() == 0 { + if d.high() == 0 { + // K X + // --- + // 0 0 + unimplemented() + } + + if n.low() == 0 { + // K 0 + // --- + // K 0 + if !rem.is_null() { + *rem = u128::from_parts(0, n.high() % d.high()); + } + return u128::from(n.high() / d.high()); + } + + // K K + // --- + // K 0 + + if d.high().is_power_of_two() { + if !rem.is_null() { + *rem = u128::from_parts(n.low(), n.high() & (d.high() - 1)); + } + return u128::from(n.high() >> d.high().trailing_zeros()); + } + + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > 64 - 2 { + if !rem.is_null() { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() - 1 + q = n << (128 - sr); + r = n >> sr; + } else { + if d.high() == 0 { + // K X + // --- + // 0 K + if d.low().is_power_of_two() { + if !rem.is_null() { + *rem = u128::from(n.low() & (d.low() - 1)); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n >> sr; + }; + } + + sr = 1 + 64 + d.low().leading_zeros() - n.high().leading_zeros(); + + // 2 <= sr <= u64::bits() - 1 + q = n << (128 - sr); + r = n >> sr; + } else { + // K X + // --- + // K K + sr = d.high().leading_zeros().wrapping_sub(n.high().leading_zeros()); + + // D > N + if sr > 64 - 1 { + if !rem.is_null() { + *rem = n; + } + return 0; + } + + sr += 1; + + // 1 <= sr <= u32::bits() + q = n << (128 - sr); + r = n >> sr; + } + } + + // Not a special case + // q and r are initialized with + // q = n << (u64::bits() - sr) + // r = n >> sr + // 1 <= sr <= u64::bits() - 1 + let mut carry = 0; + + for _ in 0..sr { + // r:q = ((r:q) << 1) | carry + r = (r << 1) | (q >> (128 - 1)); + q = (q << 1) | carry as u128; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = (d.wrapping_sub(r).wrapping_sub(1)) as i128 >> (128 - 1); + carry = (s & 1) as u64; + r -= d & s as u128; + } + + if !rem.is_null() { + *rem = r; + } + (q << 1) | carry as u128 + } + } + + #[export_name="__umodti3"] + pub extern fn u128_mod(a: u128_, b: u128_) -> u128_ { + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a, b, &mut r); + r + } + } + + #[export_name="__modti3"] + pub extern fn i128_mod(a: i128_, b: i128_) -> i128_ { + let b = b.abs(); + let sa = a.signum(); + let a = a.abs(); + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a as u128_, b as u128_, &mut r); + if sa == -1 { -(r as i128_) } else { r as i128_ } + } + } + + #[export_name="__divti3"] + pub extern fn i128_div(a: i128_, b: i128_) -> i128_ { + let sa = a.signum(); + let sb = b.signum(); + let a = a.abs(); + let b = b.abs(); + let sr = sa ^ sb; + unsafe { + let mut r = ::core::mem::zeroed(); + if sa == -1 { + -(u128_div_mod(a as u128_, b as u128_, &mut r) as i128_) + } else { + u128_div_mod(a as u128_, b as u128_, &mut r) as i128_ + } + } + } + + #[export_name="__udivti3"] + pub extern fn u128_div(a: u128_, b: u128_) -> u128_ { + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a, b, &mut r) + } + } + + macro_rules! mulo { + ($a:expr, $b:expr, $o: expr, $ty: ty) => {{ + let (a, b, overflow) = ($a, $b, $o); + *overflow = 0; + let result = a.wrapping_mul(b); + if a == <$ty>::min_value() { + if b != 0 && b != 1 { + *overflow = 1; + } + return result; + } + if b == <$ty>::min_value() { + if a != 0 && a != 1 { + *overflow = 1; + } + return result; + } + + let bits = ::core::mem::size_of::<$ty>() * 8; + let sa = a >> (bits - 1); + let abs_a = (a ^ sa) - sa; + let sb = b >> (bits - 1); + let abs_b = (b ^ sb) - sb; + if abs_a < 2 || abs_b < 2 { + return result; + } + if sa == sb { + if abs_a > <$ty>::max_value() / abs_b { + *overflow = 1; + } + } else { + if abs_a > <$ty>::min_value() / -abs_b { + *overflow = 1; + } + } + result + }} + } + + // FIXME: i32 here should be c_int. + #[export_name="__muloti4"] + pub extern fn i128_mul_oflow(a: i128_, b: i128_, o: &mut i32) -> i128_ { + if let Some(v) = (a as i64).checked_mul(b as i64) { + *o = 0; + v as i128_ + } else { + *o = 1; + 0 + } + } + + pub trait LargeInt { + type LowHalf; + type HighHalf; + + fn low(self) -> Self::LowHalf; + fn high(self) -> Self::HighHalf; + fn from_parts(low: Self::LowHalf, high: Self::HighHalf) -> Self; + } + impl LargeInt for u64 { + type LowHalf = u32; + type HighHalf = u32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> u32 { + (self >> 32) as u32 + } + fn from_parts(low: u32, high: u32) -> u64 { + low as u64 | ((high as u64) << 32) + } + } + impl LargeInt for i64 { + type LowHalf = u32; + type HighHalf = i32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> i32 { + (self >> 32) as i32 + } + fn from_parts(low: u32, high: i32) -> i64 { + low as i64 | ((high as i64) << 32) + } + } + #[cfg(not(stage0))] + impl LargeInt for u128 { + type LowHalf = u64; + type HighHalf = u64; + + fn low(self) -> u64 { + self as u64 + } + fn high(self) -> u64 { + unsafe { *(&self as *const u128 as *const u64) } + } + fn from_parts(low: u64, high: u64) -> u128 { + #[repr(C, packed)] struct Parts(u64, u64); + unsafe { ::core::mem::transmute(Parts(low, high)) } + } + } + #[cfg(not(stage0))] + impl LargeInt for i128 { + type LowHalf = u64; + type HighHalf = i64; + + fn low(self) -> u64 { + self as u64 + } + fn high(self) -> i64 { + unsafe { *(&self as *const i128 as *const i64) } + } + fn from_parts(low: u64, high: i64) -> i128 { + u128::from_parts(low, high as u64) as i128 + } + } + + macro_rules! mul { + ($a:expr, $b:expr, $ty: ty) => {{ + let (a, b) = ($a, $b); + let bits = ::core::mem::size_of::<$ty>() * 8; + let half_bits = bits / 4; + let lower_mask = !0 >> half_bits; + let mut low = (a.low() & lower_mask) * (b.low() & lower_mask); + let mut t = low >> half_bits; + low &= lower_mask; + t += (a.low() >> half_bits) * (b.low() & lower_mask); + low += (t & lower_mask) << half_bits; + let mut high = t >> half_bits; + t = low >> half_bits; + low &= lower_mask; + t += (b.low() >> half_bits) * (a.low() & lower_mask); + low += (t & lower_mask) << half_bits; + high += t >> half_bits; + high += (a.low() >> half_bits) * (b.low() >> half_bits); + high = high.wrapping_add(a.high().wrapping_mul(b.low()).wrapping_add(a.low().wrapping_mul(b.high()))); + <$ty>::from_parts(low, high) + }} + } + + + #[export_name="__multi3"] + pub extern fn u128_mul(a: u128_, b: u128_) -> u128_ { + (a as u64 * b as u64) as u128_ + // mul!(a, b, u128_) + } + + trait FloatStuff: Sized { + type ToBytes; + + const MANTISSA_BITS: u32; + const MAX_EXP: i32; + const EXP_MASK: Self::ToBytes; + const MANTISSA_MASK: Self::ToBytes; + + fn to_bytes(self) -> Self::ToBytes; + fn get_exponent(self) -> i32; + } + + impl FloatStuff for f32 { + type ToBytes = u32; + const MANTISSA_BITS: u32 = 23; + const MAX_EXP: i32 = 127; + const MANTISSA_MASK: u32 = 0x007F_FFFF; + const EXP_MASK: u32 = 0x7F80_0000; + + fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } } + fn get_exponent(self) -> i32 { + (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP + } + } + + impl FloatStuff for f64 { + type ToBytes = u64; + const MANTISSA_BITS: u32 = 52; + const MAX_EXP: i32 = 1023; + const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; + const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; + + fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } } + fn get_exponent(self) -> i32 { + (((self.to_bytes() & Self::EXP_MASK) >> Self::MANTISSA_BITS) as i32) - Self::MAX_EXP + } + } + + macro_rules! float_as_unsigned { + ($from: expr, $fromty: ty, $outty: ty) => { { + use core::num::Float; + let repr = $from.to_bytes(); + let sign = $from.signum(); + let exponent = $from.get_exponent(); + let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + if sign == -1.0 || exponent < 0 { return 0; } + if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + return !0; + } + if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { + mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent) + } else { + mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32) + } + } } + } + + #[export_name="__fixunsdfti"] + pub extern fn f64_as_u128(a: f64) -> u128_ { + float_as_unsigned!(a, f64, u128_) + } + + #[export_name="__fixunssfti"] + pub extern fn f32_as_u128(a: f32) -> u128_ { + float_as_unsigned!(a, f32, u128_) + } + + macro_rules! float_as_signed { + ($from: expr, $fromty: ty, $outty: ty) => {{ + use core::num::Float; + let repr = $from.to_bytes(); + let sign = $from.signum(); + let exponent = $from.get_exponent(); + let mantissa = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + + if exponent < 0 { return 0; } + if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + return if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; + } + let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { + mantissa as $outty >> (<$fromty as FloatStuff>::MANTISSA_BITS as i32 - exponent) + } else { + mantissa as $outty << (exponent - <$fromty as FloatStuff>::MANTISSA_BITS as i32) + }; + if sign >= 0.0 { r } else { -r } + }} + } + + #[export_name="__fixdfti"] + pub extern fn f64_as_i128(a: f64) -> i128_ { + float_as_signed!(a, f64, i128_) + } + + #[export_name="__fixsfti"] + pub extern fn f32_as_i128(a: f32) -> i128_ { + float_as_signed!(a, f32, i128_) + } + + #[export_name="__floattidf"] + pub extern fn i128_as_f64(a: i128_) -> f64 { + match a.signum() { + 1 => u128_as_f64(a.abs() as u128_), + 0 => 0.0, + -1 => -u128_as_f64(a.abs() as u128_), + _ => unimplemented() + } + } + + #[export_name="__floattisf"] + pub extern fn i128_as_f32(a: i128_) -> f32 { + match a.signum() { + 1 => u128_as_f32(a.abs() as u128_), + 0 => 0.0, + -1 => -u128_as_f32(a.abs() as u128_), + _ => unimplemented() + } + } + + #[export_name="__floatuntidf"] + pub extern fn u128_as_f64(mut a: u128_) -> f64 { + use ::core::f64::MANTISSA_DIGITS; + if a == 0 { return 0.0; } + let sd = 128 - a.leading_zeros(); + let mut e = sd - 1; + const MD1 : u32 = MANTISSA_DIGITS + 1; + const MD2 : u32 = MANTISSA_DIGITS + 2; + + if sd > MANTISSA_DIGITS { + a = match sd { + MD1 => a << 1, + MD2 => a, + _ => (a >> (sd - (MANTISSA_DIGITS + 2))) | + (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 }) + }; + a |= if (a & 4) == 0 { 0 } else { 1 }; + a += 1; + a >>= 2; + if a & (1 << MANTISSA_DIGITS) != 0 { + a >>= 1; + e += 1; + } + } else { + a <<= MANTISSA_DIGITS - sd; + } + unsafe { + ::core::mem::transmute(((e as u64 + 1023) << 52) | (a as u64 & 0x000f_ffff_ffff_ffff)) + } + } + + #[export_name="__floatuntisf"] + pub extern fn u128_as_f32(mut a: u128_) -> f32 { + use ::core::f32::MANTISSA_DIGITS; + if a == 0 { return 0.0; } + let sd = 128 - a.leading_zeros(); + let mut e = sd - 1; + const MD1 : u32 = MANTISSA_DIGITS + 1; + const MD2 : u32 = MANTISSA_DIGITS + 2; + + if sd > MANTISSA_DIGITS { + a = match sd { + MD1 => a << 1, + MD2 => a, + _ => (a >> (sd - (MANTISSA_DIGITS + 2))) | + (if (a & (!0 >> (128 + MANTISSA_DIGITS + 2) - sd)) == 0 { 0 } else { 1 }) + }; + a |= if (a & 4) == 0 { 0 } else { 1 }; + a += 1; + a >>= 2; + if a & (1 << MANTISSA_DIGITS) != 0 { + a >>= 1; + e += 1; + } + } else { + a <<= MANTISSA_DIGITS - sd; + } + unsafe { + ::core::mem::transmute(((e + 127) << 23) | (a as u32 & 0x007f_ffff)) + } + } +} diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 0b800cacfc19a..195f3bdffa517 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -160,12 +160,16 @@ clone_impl! { i8 } clone_impl! { i16 } clone_impl! { i32 } clone_impl! { i64 } +#[cfg(not(stage0))] +clone_impl! { i128 } clone_impl! { usize } clone_impl! { u8 } clone_impl! { u16 } clone_impl! { u32 } clone_impl! { u64 } +#[cfg(not(stage0))] +clone_impl! { u128 } clone_impl! { f32 } clone_impl! { f64 } diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index f990a27e52b31..d794d4b3f3bfa 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -604,6 +604,8 @@ mod impls { partial_eq_impl! { bool char usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } + #[cfg(not(stage0))] + partial_eq_impl! { u128 i128 } macro_rules! eq_impl { ($($t:ty)*) => ($( @@ -613,6 +615,8 @@ mod impls { } eq_impl! { () bool char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + #[cfg(not(stage0))] + eq_impl! { u128 i128 } macro_rules! partial_ord_impl { ($($t:ty)*) => ($( @@ -702,6 +706,8 @@ mod impls { } ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + #[cfg(not(stage0))] + ord_impl! { u128 i128 } #[unstable(feature = "never_type", issue = "35121")] impl PartialEq for ! { diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 85e4b2a006769..ccd4343336f5e 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -144,12 +144,16 @@ default_impl! { u8, 0 } default_impl! { u16, 0 } default_impl! { u32, 0 } default_impl! { u64, 0 } +#[cfg(not(stage0))] +default_impl! { u128, 0 } default_impl! { isize, 0 } default_impl! { i8, 0 } default_impl! { i16, 0 } default_impl! { i32, 0 } default_impl! { i64, 0 } +#[cfg(not(stage0))] +default_impl! { i128, 0 } default_impl! { f32, 0.0f32 } default_impl! { f64, 0.0f64 } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 0145897d8f690..7b6c2d4888965 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -30,6 +30,8 @@ trait Int: Zero + PartialEq + PartialOrd + Div + Rem + fn to_u16(&self) -> u16; fn to_u32(&self) -> u32; fn to_u64(&self) -> u64; + #[cfg(not(stage0))] + fn to_u128(&self) -> u128; } macro_rules! doit { @@ -39,9 +41,13 @@ macro_rules! doit { fn to_u16(&self) -> u16 { *self as u16 } fn to_u32(&self) -> u32 { *self as u32 } fn to_u64(&self) -> u64 { *self as u64 } + #[cfg(not(stage0))] + fn to_u128(&self) -> u128 { *self as u128 } })*) } doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } +#[cfg(not(stage0))] +doit! { i128 u128 } /// A type that represents a specific radix #[doc(hidden)] @@ -59,11 +65,11 @@ trait GenericRadix { /// Format an integer using the radix using a formatter. fn fmt_int(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result { - // The radix can be as low as 2, so we need a buffer of at least 64 + // The radix can be as low as 2, so we need a buffer of at least 128 // characters for a base 2 number. let zero = T::zero(); let is_nonnegative = x >= zero; - let mut buf = [0; 64]; + let mut buf = [0; 128]; let mut curr = buf.len(); let base = T::from_u8(self.base()); if is_nonnegative { @@ -182,6 +188,8 @@ integer! { i8, u8 } integer! { i16, u16 } integer! { i32, u32 } integer! { i64, u64 } +#[cfg(not(stage0))] +integer! { i128, u128 } const DEC_DIGITS_LUT: &'static[u8] = b"0001020304050607080910111213141516171819\ @@ -203,14 +211,15 @@ macro_rules! impl_Display { // convert the negative num to positive by summing 1 to it's 2 complement (!self.$conv_fn()).wrapping_add(1) }; - let mut buf: [u8; 20] = unsafe { mem::uninitialized() }; + let mut buf: [u8; 40] = unsafe { mem::uninitialized() }; let mut curr = buf.len() as isize; let buf_ptr = buf.as_mut_ptr(); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); unsafe { - // eagerly decode 4 characters at a time - if <$t>::max_value() as u64 >= 10000 { + // need at least 16 bits for the 4-characters-at-a-time to work. + if ::mem::size_of::<$t>() >= 2 { + // eagerly decode 4 characters at a time while n >= 10000 { let rem = (n % 10000) as isize; n /= 10000; @@ -256,6 +265,8 @@ macro_rules! impl_Display { impl_Display!(i8, u8, i16, u16, i32, u32: to_u32); impl_Display!(i64, u64: to_u64); +#[cfg(not(stage0))] +impl_Display!(i128, u128: to_u128); #[cfg(target_pointer_width = "16")] impl_Display!(isize, usize: to_u16); #[cfg(target_pointer_width = "32")] diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 081f0c14ec30c..888337108dd07 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -177,6 +177,13 @@ pub trait Hasher { fn write_u64(&mut self, i: u64) { self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) } + #[cfg(not(stage0))] + /// Write a single `u128` into this hasher. + #[inline] + #[unstable(feature = "i128", issue = "35118")] + fn write_u128(&mut self, i: u128) { + self.write(&unsafe { mem::transmute::<_, [u8; 16]>(i) }) + } /// Write a single `usize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -211,6 +218,13 @@ pub trait Hasher { fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } + #[cfg(not(stage0))] + /// Write a single `i128` into this hasher. + #[inline] + #[unstable(feature = "i128", issue = "35118")] + fn write_i128(&mut self, i: i128) { + self.write_u128(i as u128) + } /// Write a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -319,6 +333,11 @@ mod impls { (i64, write_i64), (isize, write_isize), } + #[cfg(not(stage0))] + impl_write! { + (u128, write_u128), + (i128, write_i128), + } #[stable(feature = "rust1", since = "1.0.0")] impl Hash for bool { diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 66d05d81d80cd..53f31d0ff3cc4 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -242,6 +242,8 @@ step_impl_signed!(i64); // assume here that it is less than 64-bits. #[cfg(not(target_pointer_width = "64"))] step_impl_no_between!(u64 i64); +#[cfg(not(stage0))] +step_impl_no_between!(u128 i128); /// An adapter for stepping range iterators by a custom amount. /// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 1ae4cf8e5ef5f..18d39a9d848b6 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -91,6 +91,7 @@ #![feature(unboxed_closures)] #![feature(question_mark)] #![feature(never_type)] +#![cfg_attr(not(stage0), feature(i128_type))] #![feature(prelude_import)] #[prelude_import] @@ -118,12 +119,20 @@ mod uint_macros; #[path = "num/i32.rs"] pub mod i32; #[path = "num/i64.rs"] pub mod i64; +// SNAP +#[cfg(not(stage0))] +#[path = "num/i128.rs"] pub mod i128; + #[path = "num/usize.rs"] pub mod usize; #[path = "num/u8.rs"] pub mod u8; #[path = "num/u16.rs"] pub mod u16; #[path = "num/u32.rs"] pub mod u32; #[path = "num/u64.rs"] pub mod u64; +// SNAP +#[cfg(not(stage0))] +#[path = "num/u128.rs"] pub mod u128; + #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 47afaf77353ee..539ad00bd30e0 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -30,6 +30,10 @@ unsafe impl Zeroable for i32 {} unsafe impl Zeroable for u32 {} unsafe impl Zeroable for i64 {} unsafe impl Zeroable for u64 {} +#[cfg(not(stage0))] +unsafe impl Zeroable for i128 {} +#[cfg(not(stage0))] +unsafe impl Zeroable for u128 {} /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. diff --git a/src/libcore/num/i128.rs b/src/libcore/num/i128.rs new file mode 100644 index 0000000000000..6268271a1dcc5 --- /dev/null +++ b/src/libcore/num/i128.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The 128-bit signed integer type. +//! +//! *[See also the `i128` primitive type](../../std/primitive.i128.html).* + +#![unstable(feature = "i128", issue="35118")] + +int_module! { i128 } diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 1dd820980f496..0f3a5baa2dd9e 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i16, 16 } +int_module! { i16 } diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index 8a2168933dc66..ea8b3a9145c6e 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i32, 32 } +int_module! { i32 } diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 2ce9eb11936bc..aa21b1190aef5 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i64, 64 } +int_module! { i64 } diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index 8b5a7f1910e20..1bed4861594c9 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -int_module! { i8, 8 } +int_module! { i8 } diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index e74c30d5e5af8..630fac9d92f0f 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -10,7 +10,7 @@ #![doc(hidden)] -macro_rules! int_module { ($T:ident, $bits:expr) => ( +macro_rules! int_module { ($T:ident) => ( /// The smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/isize.rs b/src/libcore/num/isize.rs index 86bcef4011d02..e0917f79c43dc 100644 --- a/src/libcore/num/isize.rs +++ b/src/libcore/num/isize.rs @@ -14,9 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(target_pointer_width = "16")] -int_module! { isize, 16 } -#[cfg(target_pointer_width = "32")] -int_module! { isize, 32 } -#[cfg(target_pointer_width = "64")] -int_module! { isize, 64 } +int_module! { isize } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 7b797631dfd57..c79222e74336a 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -144,6 +144,8 @@ macro_rules! zero_one_impl { )*) } zero_one_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +zero_one_impl! { u128 i128 } macro_rules! zero_one_impl_float { ($($t:ty)*) => ($( @@ -190,7 +192,7 @@ macro_rules! int_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn min_value() -> Self { - (-1 as Self) << ($BITS - 1) + !0 ^ ((!0 as $UnsignedT) >> 1) as Self } /// Returns the largest value that can be represented by this integer type. @@ -1305,6 +1307,16 @@ impl i64 { intrinsics::mul_with_overflow } } +// SNAP +#[cfg(not(stage0))] +#[lang = "i128"] +impl i128 { + int_impl! { i128, u128, 128, + intrinsics::add_with_overflow, + intrinsics::sub_with_overflow, + intrinsics::mul_with_overflow } +} + #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { @@ -2337,6 +2349,20 @@ impl u64 { intrinsics::mul_with_overflow } } +// SNAP +#[cfg(not(stage0))] +#[lang = "u128"] +impl u128 { + uint_impl! { u128, 128, + intrinsics::ctpop, + intrinsics::ctlz, + intrinsics::cttz, + intrinsics::bswap, + intrinsics::add_with_overflow, + intrinsics::sub_with_overflow, + intrinsics::mul_with_overflow } +} + #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { @@ -2550,6 +2576,8 @@ macro_rules! from_str_radix_int_impl { )*} } from_str_radix_int_impl! { isize i8 i16 i32 i64 usize u8 u16 u32 u64 } +#[cfg(not(stage0))] +from_str_radix_int_impl! { u128 i128 } /// The error type returned when a checked integral type conversion fails. #[unstable(feature = "try_from", issue = "33417")] @@ -2574,7 +2602,7 @@ impl fmt::Display for TryFromIntError { } } -macro_rules! same_sign_from_int_impl { +macro_rules! same_sign_try_from_int_impl { ($storage:ty, $target:ty, $($source:ty),*) => {$( #[stable(feature = "rust1", since = "1.0.0")] impl TryFrom<$source> for $target { @@ -2593,16 +2621,30 @@ macro_rules! same_sign_from_int_impl { )*} } -same_sign_from_int_impl!(u64, u8, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i8, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, u16, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i16, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, u32, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i32, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, u64, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, i64, i8, i16, i32, i64, isize); -same_sign_from_int_impl!(u64, usize, u8, u16, u32, u64, usize); -same_sign_from_int_impl!(i64, isize, i8, i16, i32, i64, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u8, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i8, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u16, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i16, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u32, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i32, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u64, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i64, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, u128, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, i128, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(u128, usize, u8, u16, u32, u64, u128, usize); +#[cfg(not(stage0))] +same_sign_try_from_int_impl!(i128, isize, i8, i16, i32, i64, i128, isize); macro_rules! cross_sign_from_int_impl { ($unsigned:ty, $($signed:ty),*) => {$( @@ -2636,12 +2678,30 @@ macro_rules! cross_sign_from_int_impl { )*} } +#[cfg(stage0)] cross_sign_from_int_impl!(u8, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(u16, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(u32, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(u64, i8, i16, i32, i64, isize); +#[cfg(stage0)] cross_sign_from_int_impl!(usize, i8, i16, i32, i64, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u8, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u16, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u32, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u64, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(u128, i8, i16, i32, i64, i128, isize); +#[cfg(not(stage0))] +cross_sign_from_int_impl!(usize, i8, i16, i32, i64, i128, isize); + #[doc(hidden)] trait FromStrRadixHelper: PartialOrd + Copy { fn min_value() -> Self; @@ -2669,6 +2729,8 @@ macro_rules! doit { })*) } doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } +#[cfg(not(stage0))] +doit! { i128 u128 } fn from_str_radix(src: &str, radix: u32) -> Result { @@ -2801,27 +2863,51 @@ macro_rules! impl_from { impl_from! { u8, u16 } impl_from! { u8, u32 } impl_from! { u8, u64 } +#[cfg(not(stage0))] +impl_from! { u8, u128 } impl_from! { u8, usize } impl_from! { u16, u32 } impl_from! { u16, u64 } +#[cfg(not(stage0))] +impl_from! { u16, u128 } impl_from! { u32, u64 } +#[cfg(not(stage0))] +impl_from! { u32, u128 } +#[cfg(not(stage0))] +impl_from! { u64, u128 } // Signed -> Signed impl_from! { i8, i16 } impl_from! { i8, i32 } impl_from! { i8, i64 } +#[cfg(not(stage0))] +impl_from! { i8, i128 } impl_from! { i8, isize } impl_from! { i16, i32 } impl_from! { i16, i64 } +#[cfg(not(stage0))] +impl_from! { i16, i128 } impl_from! { i32, i64 } +#[cfg(not(stage0))] +impl_from! { i32, i128 } +#[cfg(not(stage0))] +impl_from! { i64, i128 } // Unsigned -> Signed impl_from! { u8, i16 } impl_from! { u8, i32 } impl_from! { u8, i64 } +#[cfg(not(stage0))] +impl_from! { u8, i128 } impl_from! { u16, i32 } impl_from! { u16, i64 } +#[cfg(not(stage0))] +impl_from! { u16, i128 } impl_from! { u32, i64 } +#[cfg(not(stage0))] +impl_from! { u32, i128 } +#[cfg(not(stage0))] +impl_from! { u64, i128 } // Note: integers can only be represented with full precision in a float if // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. diff --git a/src/libcore/num/u128.rs b/src/libcore/num/u128.rs new file mode 100644 index 0000000000000..77291f687255e --- /dev/null +++ b/src/libcore/num/u128.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The 128-bit unsigned integer type. +//! +//! *[See also the `u128` primitive type](../../std/primitive.u128.html).* + +#![unstable(feature = "i128", issue="35118")] +uint_module! { u128 } diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index d34d87caa55fa..9c318216f1fba 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u16, 16 } +uint_module! { u16 } diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index f9c9099e47f18..84367c2073833 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u32, 32 } +uint_module! { u32 } diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index 8dfe4335a3d72..cc48a28b22f69 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u64, 64 } +uint_module! { u64 } diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 0106ee8e401c9..6c0daa7763ae1 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -14,4 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -uint_module! { u8, 8 } +uint_module! { u8 } diff --git a/src/libcore/num/uint_macros.rs b/src/libcore/num/uint_macros.rs index cc9256ab6bf4e..a3a2dc73e9c8e 100644 --- a/src/libcore/num/uint_macros.rs +++ b/src/libcore/num/uint_macros.rs @@ -10,7 +10,7 @@ #![doc(hidden)] -macro_rules! uint_module { ($T:ident, $bits:expr) => ( +macro_rules! uint_module { ($T:ident) => ( /// The smallest value that can be represented by this integer type. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/num/usize.rs b/src/libcore/num/usize.rs index 685c52e271ec0..0b6f1c73c5834 100644 --- a/src/libcore/num/usize.rs +++ b/src/libcore/num/usize.rs @@ -14,9 +14,4 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(target_pointer_width = "16")] -uint_module! { usize, 16 } -#[cfg(target_pointer_width = "32")] -uint_module! { usize, 32 } -#[cfg(target_pointer_width = "64")] -uint_module! { usize, 64 } +uint_module! { usize } diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 4857817e84e4f..aaa93ea9f9922 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -288,6 +288,8 @@ macro_rules! wrapping_impl { } wrapping_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +wrapping_impl! { u128 i128 } mod shift_max { #![allow(non_upper_case_globals)] diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 85a52da332db5..7430c5ed11671 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -316,6 +316,8 @@ macro_rules! add_impl { } add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +add_impl! { u128 i128 } /// The `Sub` trait is used to specify the functionality of `-`. /// @@ -389,6 +391,8 @@ macro_rules! sub_impl { } sub_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +sub_impl! { u128 i128 } /// The `Mul` trait is used to specify the functionality of `*`. /// @@ -511,6 +515,8 @@ macro_rules! mul_impl { } mul_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +mul_impl! { u128 i128 } /// The `Div` trait is used to specify the functionality of `/`. /// @@ -640,6 +646,8 @@ macro_rules! div_impl_integer { } div_impl_integer! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +div_impl_integer! { u128 i128 } macro_rules! div_impl_float { ($($t:ty)*) => ($( @@ -719,6 +727,9 @@ macro_rules! rem_impl_integer { } rem_impl_integer! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +rem_impl_integer! { u128 i128 } + macro_rules! rem_impl_float { ($($t:ty)*) => ($( @@ -814,6 +825,8 @@ macro_rules! neg_impl_unsigned { // neg_impl_unsigned! { usize u8 u16 u32 u64 } neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +neg_impl_numeric! { i128 } /// The `Not` trait is used to specify the functionality of unary `!`. /// @@ -872,6 +885,8 @@ macro_rules! not_impl { } not_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +not_impl! { u128 i128 } /// The `BitAnd` trait is used to specify the functionality of `&`. /// @@ -955,6 +970,8 @@ macro_rules! bitand_impl { } bitand_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitand_impl! { u128 i128 } /// The `BitOr` trait is used to specify the functionality of `|`. /// @@ -1038,6 +1055,8 @@ macro_rules! bitor_impl { } bitor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitor_impl! { u128 i128 } /// The `BitXor` trait is used to specify the functionality of `^`. /// @@ -1124,6 +1143,8 @@ macro_rules! bitxor_impl { } bitxor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitxor_impl! { u128 i128 } /// The `Shl` trait is used to specify the functionality of `<<`. /// @@ -1214,17 +1235,23 @@ macro_rules! shl_impl_all { shl_impl! { $t, u16 } shl_impl! { $t, u32 } shl_impl! { $t, u64 } + #[cfg(not(stage0))] + shl_impl! { $t, u128 } shl_impl! { $t, usize } shl_impl! { $t, i8 } shl_impl! { $t, i16 } shl_impl! { $t, i32 } shl_impl! { $t, i64 } + #[cfg(not(stage0))] + shl_impl! { $t, i128 } shl_impl! { $t, isize } )*) } shl_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shl_impl_all! { u128 i128 } /// The `Shr` trait is used to specify the functionality of `>>`. /// @@ -1315,17 +1342,23 @@ macro_rules! shr_impl_all { shr_impl! { $t, u16 } shr_impl! { $t, u32 } shr_impl! { $t, u64 } + #[cfg(not(stage0))] + shr_impl! { $t, u128 } shr_impl! { $t, usize } shr_impl! { $t, i8 } shr_impl! { $t, i16 } shr_impl! { $t, i32 } shr_impl! { $t, i64 } + #[cfg(not(stage0))] + shr_impl! { $t, i128 } shr_impl! { $t, isize } )*) } shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shr_impl_all! { u128 i128 } /// The `AddAssign` trait is used to specify the functionality of `+=`. /// @@ -1382,6 +1415,8 @@ macro_rules! add_assign_impl { } add_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +add_assign_impl! { u128 i128 } /// The `SubAssign` trait is used to specify the functionality of `-=`. /// @@ -1438,6 +1473,8 @@ macro_rules! sub_assign_impl { } sub_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +sub_assign_impl! { u128 i128 } /// The `MulAssign` trait is used to specify the functionality of `*=`. /// @@ -1483,6 +1520,8 @@ macro_rules! mul_assign_impl { } mul_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +mul_assign_impl! { u128 i128 } /// The `DivAssign` trait is used to specify the functionality of `/=`. /// @@ -1527,6 +1566,8 @@ macro_rules! div_assign_impl { } div_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +div_assign_impl! { u128 i128 } /// The `RemAssign` trait is used to specify the functionality of `%=`. /// @@ -1571,6 +1612,8 @@ macro_rules! rem_assign_impl { } rem_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } +#[cfg(not(stage0))] +rem_assign_impl! { u128 i128 } /// The `BitAndAssign` trait is used to specify the functionality of `&=`. /// @@ -1657,6 +1700,8 @@ macro_rules! bitand_assign_impl { } bitand_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitand_assign_impl! { u128 i128 } /// The `BitOrAssign` trait is used to specify the functionality of `|=`. /// @@ -1701,6 +1746,8 @@ macro_rules! bitor_assign_impl { } bitor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitor_assign_impl! { u128 i128 } /// The `BitXorAssign` trait is used to specify the functionality of `^=`. /// @@ -1745,6 +1792,8 @@ macro_rules! bitxor_assign_impl { } bitxor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } +#[cfg(not(stage0))] +bitxor_assign_impl! { u128 i128 } /// The `ShlAssign` trait is used to specify the functionality of `<<=`. /// @@ -1797,17 +1846,23 @@ macro_rules! shl_assign_impl_all { shl_assign_impl! { $t, u16 } shl_assign_impl! { $t, u32 } shl_assign_impl! { $t, u64 } + #[cfg(not(stage0))] + shl_assign_impl! { $t, u128 } shl_assign_impl! { $t, usize } shl_assign_impl! { $t, i8 } shl_assign_impl! { $t, i16 } shl_assign_impl! { $t, i32 } shl_assign_impl! { $t, i64 } + #[cfg(not(stage0))] + shl_assign_impl! { $t, i128 } shl_assign_impl! { $t, isize } )*) } shl_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shl_assign_impl_all! { u128 i128 } /// The `ShrAssign` trait is used to specify the functionality of `>>=`. /// @@ -1860,17 +1915,23 @@ macro_rules! shr_assign_impl_all { shr_assign_impl! { $t, u16 } shr_assign_impl! { $t, u32 } shr_assign_impl! { $t, u64 } + #[cfg(not(stage0))] + shr_assign_impl! { $t, u128 } shr_assign_impl! { $t, usize } shr_assign_impl! { $t, i8 } shr_assign_impl! { $t, i16 } shr_assign_impl! { $t, i32 } shr_assign_impl! { $t, i64 } + #[cfg(not(stage0))] + shr_assign_impl! { $t, i128 } shr_assign_impl! { $t, isize } )*) } shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +#[cfg(not(stage0))] +shr_assign_impl_all! { u128 i128 } /// The `Index` trait is used to specify the functionality of indexing operations /// like `arr[idx]` when used in an immutable context. diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 578ef68b00386..51494885e7369 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -20,6 +20,7 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } +rustc_i128 = { path = "../librustc_i128" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c34286f0195bf..0ab5abfcaa080 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -64,6 +64,9 @@ extern crate rustc_errors as errors; extern crate serialize as rustc_serialize; // used by deriving +// SNAP: +extern crate rustc_i128; + #[cfg(test)] extern crate test; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 078cce9c49ff4..306872fbd812d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -279,11 +279,13 @@ language_item_table! { I16ImplItem, "i16", i16_impl; I32ImplItem, "i32", i32_impl; I64ImplItem, "i64", i64_impl; + I128ImplItem, "i128", i128_impl; IsizeImplItem, "isize", isize_impl; U8ImplItem, "u8", u8_impl; U16ImplItem, "u16", u16_impl; U32ImplItem, "u32", u32_impl; U64ImplItem, "u64", u64_impl; + U128ImplItem, "u128", u128_impl; UsizeImplItem, "usize", usize_impl; F32ImplItem, "f32", f32_impl; F64ImplItem, "f64", f64_impl; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0c7c387b67ea3..0711fe192220e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -184,11 +184,13 @@ pub struct CommonTypes<'tcx> { pub i16: Ty<'tcx>, pub i32: Ty<'tcx>, pub i64: Ty<'tcx>, + pub i128: Ty<'tcx>, pub usize: Ty<'tcx>, pub u8: Ty<'tcx>, pub u16: Ty<'tcx>, pub u32: Ty<'tcx>, pub u64: Ty<'tcx>, + pub u128: Ty<'tcx>, pub f32: Ty<'tcx>, pub f64: Ty<'tcx>, pub never: Ty<'tcx>, @@ -265,11 +267,13 @@ impl<'tcx> CommonTypes<'tcx> { i16: mk(TyInt(ast::IntTy::I16)), i32: mk(TyInt(ast::IntTy::I32)), i64: mk(TyInt(ast::IntTy::I64)), + i128: mk(TyInt(ast::IntTy::I128)), usize: mk(TyUint(ast::UintTy::Us)), u8: mk(TyUint(ast::UintTy::U8)), u16: mk(TyUint(ast::UintTy::U16)), u32: mk(TyUint(ast::UintTy::U32)), u64: mk(TyUint(ast::UintTy::U64)), + u128: mk(TyUint(ast::UintTy::U128)), f32: mk(TyFloat(ast::FloatTy::F32)), f64: mk(TyFloat(ast::FloatTy::F64)), } @@ -1235,6 +1239,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ast::IntTy::I16 => self.types.i16, ast::IntTy::I32 => self.types.i32, ast::IntTy::I64 => self.types.i64, + ast::IntTy::I128 => self.types.i128, } } @@ -1245,6 +1250,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ast::UintTy::U16 => self.types.u16, ast::UintTy::U32 => self.types.u32, ast::UintTy::U64 => self.types.u64, + ast::UintTy::U128 => self.types.u128, } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index ed945534e1e5f..1f2702a2f9207 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -20,6 +20,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; +use rustc_i128::{i128, u128}; use std::cmp; use std::fmt; @@ -34,6 +35,7 @@ pub struct TargetDataLayout { pub i16_align: Align, pub i32_align: Align, pub i64_align: Align, + pub i128_align: Align, pub f32_align: Align, pub f64_align: Align, pub pointer_size: Size, @@ -54,6 +56,7 @@ impl Default for TargetDataLayout { i16_align: Align::from_bits(16, 16).unwrap(), i32_align: Align::from_bits(32, 32).unwrap(), i64_align: Align::from_bits(32, 64).unwrap(), + i128_align: Align::from_bits(32, 64).unwrap(), f32_align: Align::from_bits(32, 32).unwrap(), f64_align: Align::from_bits(64, 64).unwrap(), pointer_size: Size::from_bits(64), @@ -98,6 +101,7 @@ impl TargetDataLayout { }; let mut dl = TargetDataLayout::default(); + let mut i128_align_src = 64; for spec in sess.target.target.data_layout.split("-") { match &spec.split(":").collect::>()[..] { &["e"] => dl.endian = Endian::Little, @@ -110,19 +114,28 @@ impl TargetDataLayout { dl.pointer_align = align(a, p); } &[s, ref a..] if s.starts_with("i") => { - let ty_align = match s[1..].parse::() { - Ok(1) => &mut dl.i8_align, - Ok(8) => &mut dl.i8_align, - Ok(16) => &mut dl.i16_align, - Ok(32) => &mut dl.i32_align, - Ok(64) => &mut dl.i64_align, - Ok(_) => continue, + let bits = match s[1..].parse::() { + Ok(bits) => bits, Err(_) => { size(&s[1..], "i"); // For the user error. continue; } }; - *ty_align = align(a, s); + let a = align(a, s); + match bits { + 1 => dl.i1_align = a, + 8 => dl.i8_align = a, + 16 => dl.i16_align = a, + 32 => dl.i32_align = a, + 64 => dl.i64_align = a, + _ => {} + } + if bits >= i128_align_src && bits <= 128 { + // Default alignment for i128 is decided by taking the alignment of + // largest-sized i{64...128}. + i128_align_src = bits; + dl.i128_align = a; + } } &[s, ref a..] if s.starts_with("v") => { let v_size = size(&s[1..], "v"); @@ -324,7 +337,8 @@ pub enum Integer { I8, I16, I32, - I64 + I64, + I128, } impl Integer { @@ -335,6 +349,7 @@ impl Integer { I16 => Size::from_bytes(2), I32 => Size::from_bytes(4), I64 => Size::from_bytes(8), + I128 => Size::from_bytes(16), } } @@ -345,6 +360,7 @@ impl Integer { I16 => dl.i16_align, I32 => dl.i32_align, I64 => dl.i64_align, + I128 => dl.i128_align, } } @@ -356,33 +372,37 @@ impl Integer { (I16, false) => tcx.types.u16, (I32, false) => tcx.types.u32, (I64, false) => tcx.types.u64, + (I128, false) => tcx.types.u128, (I1, true) => tcx.types.i8, (I8, true) => tcx.types.i8, (I16, true) => tcx.types.i16, (I32, true) => tcx.types.i32, (I64, true) => tcx.types.i64, + (I128, true) => tcx.types.i128, } } /// Find the smallest Integer type which can represent the signed value. pub fn fit_signed(x: i64) -> Integer { match x { - -0x0000_0001...0x0000_0000 => I1, - -0x0000_0080...0x0000_007f => I8, - -0x0000_8000...0x0000_7fff => I16, - -0x8000_0000...0x7fff_ffff => I32, - _ => I64 + -0x0000_0000_0000_0001...0x0000_0000_0000_0000 => I1, + -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, + -0x0000_0000_0000_8000...0x0000_0000_0000_7fff => I16, + -0x0000_0000_8000_0000...0x0000_0000_7fff_ffff => I32, + -0x8000_0000_0000_0000...0x7fff_ffff_ffff_ffff => I64, + _ => I128 } } /// Find the smallest Integer type which can represent the unsigned value. pub fn fit_unsigned(x: u64) -> Integer { match x { - 0...0x0000_0001 => I1, - 0...0x0000_00ff => I8, - 0...0x0000_ffff => I16, - 0...0xffff_ffff => I32, - _ => I64 + 0...0x0000_0000_0000_0001 => I1, + 0...0x0000_0000_0000_00ff => I8, + 0...0x0000_0000_0000_ffff => I16, + 0...0x0000_0000_ffff_ffff => I32, + 0...0xffff_ffff_ffff_ffff => I64, + _ => I128, } } @@ -405,6 +425,7 @@ impl Integer { attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16, attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32, attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64, + attr::SignedInt(IntTy::I128) | attr::UnsignedInt(UintTy::U128) => I128, attr::SignedInt(IntTy::Is) | attr::UnsignedInt(UintTy::Us) => { dl.ptr_sized_integer() } @@ -478,6 +499,7 @@ impl Primitive { Int(I16) => Size::from_bits(16), Int(I32) | F32 => Size::from_bits(32), Int(I64) | F64 => Size::from_bits(64), + Int(I128) => Size::from_bits(128), Pointer => dl.pointer_size } } @@ -489,6 +511,7 @@ impl Primitive { Int(I16) => dl.i16_align, Int(I32) => dl.i32_align, Int(I64) => dl.i64_align, + Int(I128) => dl.i128_align, F32 => dl.f32_align, F64 => dl.f64_align, Pointer => dl.pointer_align @@ -1013,17 +1036,21 @@ impl<'a, 'gcx, 'tcx> Layout { if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); + let (mut min, mut max) = (i128::max_value(), i128::min_value()); for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; + let x = v.disr_val.to_u128_unchecked() as i128; if x < min { min = x; } if x > max { max = x; } } - let (discr, signed) = Integer::repr_discr(tcx, ty, hint, min, max); + // FIXME: should take i128? + let (discr, signed) = Integer::repr_discr(tcx, ty, hint, + min as i64, + max as i64); return success(CEnum { discr: discr, signed: signed, + // FIXME: should be u128? min: min as u64, max: max as u64 }); @@ -1054,7 +1081,7 @@ impl<'a, 'gcx, 'tcx> Layout { // non-empty body, explicit discriminants should have // been rejected by a checker before this point. for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { + if i as u128 != v.disr_val.to_u128_unchecked() { bug!("non-C-like enum {} with specified discriminants", tcx.item_path_str(def.did)); } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c8fd27f066cac..32959af0575f0 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -46,11 +46,13 @@ impl IntTypeExt for attr::IntType { SignedInt(ast::IntTy::I16) => tcx.types.i16, SignedInt(ast::IntTy::I32) => tcx.types.i32, SignedInt(ast::IntTy::I64) => tcx.types.i64, + SignedInt(ast::IntTy::I128) => tcx.types.i128, SignedInt(ast::IntTy::Is) => tcx.types.isize, UnsignedInt(ast::UintTy::U8) => tcx.types.u8, UnsignedInt(ast::UintTy::U16) => tcx.types.u16, UnsignedInt(ast::UintTy::U32) => tcx.types.u32, UnsignedInt(ast::UintTy::U64) => tcx.types.u64, + UnsignedInt(ast::UintTy::U128) => tcx.types.u128, UnsignedInt(ast::UintTy::Us) => tcx.types.usize, } } @@ -61,6 +63,7 @@ impl IntTypeExt for attr::IntType { SignedInt(ast::IntTy::I16) => ConstInt::I16(0), SignedInt(ast::IntTy::I32) => ConstInt::I32(0), SignedInt(ast::IntTy::I64) => ConstInt::I64(0), + SignedInt(ast::IntTy::I128) => ConstInt::I128(0), SignedInt(ast::IntTy::Is) => match tcx.sess.target.int_type { ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16(0)), ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32(0)), @@ -71,6 +74,7 @@ impl IntTypeExt for attr::IntType { UnsignedInt(ast::UintTy::U16) => ConstInt::U16(0), UnsignedInt(ast::UintTy::U32) => ConstInt::U32(0), UnsignedInt(ast::UintTy::U64) => ConstInt::U64(0), + UnsignedInt(ast::UintTy::U128) => ConstInt::U128(0), UnsignedInt(ast::UintTy::Us) => match tcx.sess.target.uint_type { ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16(0)), ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32(0)), @@ -86,11 +90,13 @@ impl IntTypeExt for attr::IntType { (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {}, (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {}, (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {}, + (SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {}, (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::U128), ConstInt::U128(_)) => {}, (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {}, _ => bug!("disr type mismatch: {:?} vs {:?}", self, val), } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 8967672548b10..468aafbadc093 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -17,4 +17,5 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } graphviz = { path = "../libgraphviz" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4ae3c7d37db8d..feaa33d4d48d0 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -47,6 +47,8 @@ use std::collections::hash_map::Entry::Vacant; use rustc_const_math::*; use rustc_errors::DiagnosticBuilder; +use rustc_i128::{i128, u128}; + macro_rules! math { ($e:expr, $op:expr) => { match $op { @@ -619,38 +621,43 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let hir::ExprLit(ref lit) = inner.node { use syntax::ast::*; use syntax::ast::LitIntType::*; - const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1; - const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1; - const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1; - const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1; + const I8_OVERFLOW: u128 = i8::max_value() as u128 + 1; + const I16_OVERFLOW: u128 = i16::max_value() as u128 + 1; + const I32_OVERFLOW: u128 = i32::max_value() as u128 + 1; + const I64_OVERFLOW: u128 = i64::max_value() as u128 + 1; + const I128_OVERFLOW: u128 = i128::max_value() as u128 + 1; match (&lit.node, ety.map(|t| &t.sty)) { (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) | (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => { - return Ok(Integral(I8(::std::i8::MIN))) + return Ok(Integral(I8(i8::min_value()))) }, (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) | (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => { - return Ok(Integral(I16(::std::i16::MIN))) + return Ok(Integral(I16(i16::min_value()))) }, (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) | (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => { - return Ok(Integral(I32(::std::i32::MIN))) + return Ok(Integral(I32(i32::min_value()))) }, (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) | (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => { - return Ok(Integral(I64(::std::i64::MIN))) + return Ok(Integral(I64(i64::min_value()))) + }, + (&LitKind::Int(I128_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I128))) | + (&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => { + return Ok(Integral(I128(i128::min_value()))) }, (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) | (&LitKind::Int(n, Signed(IntTy::Is)), _) => { match tcx.sess.target.int_type { IntTy::I16 => if n == I16_OVERFLOW { - return Ok(Integral(Isize(Is16(::std::i16::MIN)))); + return Ok(Integral(Isize(Is16(i16::min_value())))); }, IntTy::I32 => if n == I32_OVERFLOW { - return Ok(Integral(Isize(Is32(::std::i32::MIN)))); + return Ok(Integral(Isize(Is32(i32::min_value())))); }, IntTy::I64 => if n == I64_OVERFLOW { - return Ok(Integral(Isize(Is64(::std::i64::MIN)))); + return Ok(Integral(Isize(Is64(i64::min_value())))); }, _ => bug!(), } @@ -999,26 +1006,30 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result), (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result), (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result), + (&ty::TyInt(IntTy::I128), result @ I128(_)) => Ok(result), (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result), (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result), (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result), (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result), (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result), + (&ty::TyUint(UintTy::U128), result @ U128(_)) => Ok(result), (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result), - (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i64 as i8)), - (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i64 as i16)), - (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i64 as i32)), - (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i64)), + (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i128 as i8)), + (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i128 as i16)), + (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i128 as i32)), + (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i128 as i64)), + (&ty::TyInt(IntTy::I128), Infer(i)) => Ok(I128(i as i128)), (&ty::TyInt(IntTy::Is), Infer(i)) => { - Ok(Isize(ConstIsize::new_truncating(i as i64, tcx.sess.target.int_type))) + Ok(Isize(ConstIsize::new_truncating(i as i128, tcx.sess.target.int_type))) }, (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)), (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)), (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)), - (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i)), + (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i as i64)), + (&ty::TyInt(IntTy::I128), InferSigned(i)) => Ok(I128(i)), (&ty::TyInt(IntTy::Is), InferSigned(i)) => { Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type))) }, @@ -1026,7 +1037,8 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)), (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)), (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)), - (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i)), + (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i as u64)), + (&ty::TyUint(UintTy::U128), Infer(i)) => Ok(U128(i)), (&ty::TyUint(UintTy::Us), Infer(i)) => { Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type))) }, @@ -1105,21 +1117,23 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult { - let v = val.to_u64_unchecked(); + let v = val.to_u128_unchecked(); match ty.sty { ty::TyBool if v == 0 => Ok(Bool(false)), ty::TyBool if v == 1 => Ok(Bool(true)), - ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i64 as i8))), - ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i64 as i16))), - ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i64 as i32))), - ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i64))), + ty::TyInt(ast::IntTy::I8) => Ok(Integral(I8(v as i128 as i8))), + ty::TyInt(ast::IntTy::I16) => Ok(Integral(I16(v as i128 as i16))), + ty::TyInt(ast::IntTy::I32) => Ok(Integral(I32(v as i128 as i32))), + ty::TyInt(ast::IntTy::I64) => Ok(Integral(I64(v as i128 as i64))), + ty::TyInt(ast::IntTy::I128) => Ok(Integral(I128(v as i128))), ty::TyInt(ast::IntTy::Is) => { - Ok(Integral(Isize(ConstIsize::new_truncating(v as i64, tcx.sess.target.int_type)))) + Ok(Integral(Isize(ConstIsize::new_truncating(v as i128, tcx.sess.target.int_type)))) }, ty::TyUint(ast::UintTy::U8) => Ok(Integral(U8(v as u8))), ty::TyUint(ast::UintTy::U16) => Ok(Integral(U16(v as u16))), ty::TyUint(ast::UintTy::U32) => Ok(Integral(U32(v as u32))), - ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v))), + ty::TyUint(ast::UintTy::U64) => Ok(Integral(U64(v as u64))), + ty::TyUint(ast::UintTy::U128) => Ok(Integral(U128(v as u128))), ty::TyUint(ast::UintTy::Us) => { Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type)))) }, @@ -1149,13 +1163,13 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match ty.sty { ty::TyInt(_) | ty::TyUint(_) => { let i = match val { - F32(f) if f >= 0.0 => Infer(f as u64), + F32(f) if f >= 0.0 => Infer(f as u128), FInfer { f64: f, .. } | - F64(f) if f >= 0.0 => Infer(f as u64), + F64(f) if f >= 0.0 => Infer(f as u128), - F32(f) => InferSigned(f as i64), + F32(f) => InferSigned(f as i128), FInfer { f64: f, .. } | - F64(f) => InferSigned(f as i64) + F64(f) => InferSigned(f as i128) }; if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) { @@ -1179,9 +1193,9 @@ fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult { match val { Integral(i) => cast_const_int(tcx, i, ty), - Bool(b) => cast_const_int(tcx, Infer(b as u64), ty), + Bool(b) => cast_const_int(tcx, Infer(b as u128), ty), Float(f) => cast_const_float(tcx, f, ty), - Char(c) => cast_const_int(tcx, Infer(c as u64), ty), + Char(c) => cast_const_int(tcx, Infer(c as u128), ty), Function(_) => Err(UnimplementedConstVal("casting fn pointers")), ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { @@ -1219,28 +1233,29 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())), LitKind::Byte(n) => Ok(Integral(U8(n))), LitKind::Int(n, Signed(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) + infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral) }, + // FIXME: this should become u128. LitKind::Int(n, Unsuffixed) => { match ty_hint.map(|t| &t.sty) { Some(&ty::TyInt(ity)) => { - infer(InferSigned(n as i64), tcx, &ty::TyInt(ity)).map(Integral) + infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral) }, Some(&ty::TyUint(uty)) => { - infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) + infer(Infer(n as u128), tcx, &ty::TyUint(uty)).map(Integral) }, - None => Ok(Integral(Infer(n))), + None => Ok(Integral(Infer(n as u128))), Some(&ty::TyAdt(adt, _)) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); - infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) + infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral) }, Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit), } }, LitKind::Int(n, Unsigned(ity)) => { - infer(Infer(n), tcx, &ty::TyUint(ity)).map(Integral) + infer(Infer(n as u128), tcx, &ty::TyUint(ity)).map(Integral) }, LitKind::Float(ref n, fty) => { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index f926fef065ea6..8b7e6da4662bd 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -30,6 +30,7 @@ #![feature(question_mark)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_fn)] #[macro_use] extern crate syntax; #[macro_use] extern crate log; @@ -41,6 +42,8 @@ extern crate graphviz; extern crate syntax_pos; extern crate serialize as rustc_serialize; // used by deriving +extern crate rustc_i128; + // NB: This module needs to be declared first so diagnostics are // registered before they are used. pub mod diagnostics; diff --git a/src/librustc_const_math/Cargo.toml b/src/librustc_const_math/Cargo.toml index 10aadabe22ed7..3d7a4865e45af 100644 --- a/src/librustc_const_math/Cargo.toml +++ b/src/librustc_const_math/Cargo.toml @@ -12,3 +12,4 @@ crate-type = ["dylib"] log = { path = "../liblog" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_const_math/err.rs b/src/librustc_const_math/err.rs index e2e30ef026c2f..1e9c2badd6860 100644 --- a/src/librustc_const_math/err.rs +++ b/src/librustc_const_math/err.rs @@ -74,11 +74,13 @@ impl ConstMathErr { ULitOutOfRange(ast::UintTy::U16) => "literal out of range for u16", ULitOutOfRange(ast::UintTy::U32) => "literal out of range for u32", ULitOutOfRange(ast::UintTy::U64) => "literal out of range for u64", + ULitOutOfRange(ast::UintTy::U128) => "literal out of range for u128", ULitOutOfRange(ast::UintTy::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::I128) => "literal out of range for i128", LitOutOfRange(ast::IntTy::Is) => "literal out of range for isize", } } diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs index 28a5887847252..59eb4b70aa8ff 100644 --- a/src/librustc_const_math/int.rs +++ b/src/librustc_const_math/int.rs @@ -11,6 +11,7 @@ use std::cmp::Ordering; use syntax::attr::IntType; use syntax::ast::{IntTy, UintTy}; +use rustc_i128::{i128, u128}; use super::is::*; use super::us::*; @@ -22,45 +23,98 @@ pub enum ConstInt { I16(i16), I32(i32), I64(i64), + I128(i128), Isize(ConstIsize), U8(u8), U16(u16), U32(u32), U64(u64), + U128(u128), Usize(ConstUsize), - Infer(u64), - InferSigned(i64), + Infer(u128), + InferSigned(i128), } 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; - )* - } + ($ct: ty, $($t:ident $min:ident $max:ident)*) => { + $( + pub const $min: $ct = $t::min_value() as $ct; + pub const $max: $ct = $t::max_value() as $ct; + )* + }; + ($ct: ty: $min_val: expr, $($t:ident $min:ident $max:ident)*) => { + $( + pub const $min: $ct = $min_val; + pub const $max: $ct = $t::max_value() as $ct; + )* + } +} + +mod ubounds { + #![allow(dead_code)] + use rustc_i128::{u128, i128}; + bounds!{u128: 0, + i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX + u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX u64 U64MIN U64MAX u128 U128MIN U128MAX + // do not add constants for isize/usize, because these are guaranteed to be wrong for + // arbitrary host/target combinations } } -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 +mod ibounds { + #![allow(dead_code)] + use rustc_i128::i128; + #[cfg(stage0)] + pub const U64MIN: i128 = 0; + #[cfg(stage0)] + pub const U64MAX: i128 = i128::max_value(); + #[cfg(not(stage0))] + bounds!(i128, u64 U64MIN U64MAX); + + pub const U128MIN: i128 = 0; + pub const U128MAX: i128 = i128::max_value(); + + bounds!{i128, + i8 I8MIN I8MAX i16 I16MIN I16MAX i32 I32MIN I32MAX i64 I64MIN I64MAX i128 I128MIN I128MAX + u8 U8MIN U8MAX u16 U16MIN U16MAX u32 U32MIN U32MAX + // do not add constants for isize/usize, because these are guaranteed to be wrong for + // arbitrary host/target combinations + } } impl ConstInt { + /// Creates a new unsigned ConstInt with matching type while also checking that overflow does + /// not happen. + pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option { + match ty { + UintTy::U8 if val <= ubounds::U8MAX => Some(U8(val as u8)), + UintTy::U16 if val <= ubounds::U16MAX => Some(U16(val as u16)), + UintTy::U32 if val <= ubounds::U32MAX => Some(U32(val as u32)), + UintTy::U64 if val <= ubounds::U64MAX => Some(U64(val as u64)), + UintTy::Us if val <= ubounds::U64MAX => ConstUsize::new(val as u64, usize_ty).ok() + .map(Usize), + UintTy::U128 => Some(U128(val)), + _ => None + } + } + + /// Creates a new unsigned ConstInt with matching type while also checking that overflow does + /// not happen. + pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option { + match ty { + IntTy::I8 if val <= ibounds::I8MAX => Some(I8(val as i8)), + IntTy::I16 if val <= ibounds::I16MAX => Some(I16(val as i16)), + IntTy::I32 if val <= ibounds::I32MAX => Some(I32(val as i32)), + IntTy::I64 if val <= ibounds::I64MAX => Some(I64(val as i64)), + IntTy::Is if val <= ibounds::I64MAX => ConstIsize::new(val as i64, isize_ty).ok() + .map(Isize), + IntTy::I128 => Some(I128(val)), + _ => None + } + } + /// 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> { @@ -68,46 +122,54 @@ impl ConstInt { (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(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128), (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::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)), - (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::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), - (Infer(a @ 0...as_u64::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), - (Infer(a), Usize(Us64(_))) => Usize(Us64(a)), + (Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8), + (Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16), + (Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32), + (Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64), + (Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128), + (Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)), + (Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)), + (Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)), + (Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8), + (Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16), + (Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32), + (Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64), + (Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128), + (Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), + (Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), + (Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)), (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::I16MIN...as_i64::I16MAX), Isize(Is16(_))) => { + (InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8), + (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16), + (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32), + (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64), + (InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128), + (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => { Isize(Is16(a as i16)) }, - (InferSigned(a @ as_i64::I32MIN...as_i64::I32MAX), Isize(Is32(_))) => { + (InferSigned(a @ ibounds::I32MIN...ibounds::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::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), - (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(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => { + Isize(Is64(a as i64)) + }, + (InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8), + (InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16), + (InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32), + // SNAP: replace with U64MAX + (InferSigned(a @ 0...ibounds::I64MAX), U64(_)) => U64(a as u64), + (InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128), + (InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)), + (InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)), + // SNAP: replace with U64MAX + (InferSigned(a @ 0...ibounds::I64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)), (InferSigned(_), _) => return Err(ConstMathErr::NotInRange), _ => self, // already known types }; @@ -119,28 +181,31 @@ impl ConstInt { 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(Is16(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(Is16(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(Us16(i)) => Infer(i as u64), - Usize(Us32(i)) => Infer(i as u64), - Usize(Us64(i)) => Infer(i), + I8(i) if i < 0 => InferSigned(i as i128), + I16(i) if i < 0 => InferSigned(i as i128), + I32(i) if i < 0 => InferSigned(i as i128), + I64(i) if i < 0 => InferSigned(i as i128), + I128(i) if i < 0 => InferSigned(i as i128), + Isize(Is16(i)) if i < 0 => InferSigned(i as i128), + Isize(Is32(i)) if i < 0 => InferSigned(i as i128), + Isize(Is64(i)) if i < 0 => InferSigned(i as i128), + InferSigned(i) => Infer(i as u128), + I8(i) => Infer(i as u128), + I16(i) => Infer(i as u128), + I32(i) => Infer(i as u128), + I64(i) => Infer(i as u128), + I128(i) => Infer(i as u128), + Isize(Is16(i)) => Infer(i as u128), + Isize(Is32(i)) => Infer(i as u128), + Isize(Is64(i)) => Infer(i as u128), + U8(i) => Infer(i as u128), + U16(i) => Infer(i as u128), + U32(i) => Infer(i as u128), + U64(i) => Infer(i as u128), + U128(i) => Infer(i as u128), + Usize(Us16(i)) => Infer(i as u128), + Usize(Us32(i)) => Infer(i as u128), + Usize(Us64(i)) => Infer(i as u128), } } @@ -153,67 +218,66 @@ impl ConstInt { I16(_) => "i16", I32(_) => "i32", I64(_) => "i64", + I128(_) => "i128", Isize(_) => "isize", U8(_) => "u8", U16(_) => "u16", U32(_) => "u32", U64(_) => "u64", + U128(_) => "u128", 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 { + /// Erases the type and returns a u128. + /// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128` + pub fn to_u128_unchecked(self) -> u128 { match self.erase_type() { ConstInt::Infer(i) => i, - ConstInt::InferSigned(i) => i as u64, + ConstInt::InferSigned(i) => i as u128, _ => unreachable!(), } } /// Converts the value to a `u32` if it's in the range 0...std::u32::MAX pub fn to_u32(&self) -> Option { - 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), - Isize(Is16(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), - Usize(Us16(v)) => Some(v as u32), - _ => None, - } + self.to_u128().and_then(|v| if v <= u32::max_value() as u128 { + Some(v as u32) + } else { + None + }) } - /// Converts the value to a `u64` if it's >= 0 + /// Converts the value to a `u64` if it's in the range 0...std::u64::MAX pub fn to_u64(&self) -> Option { + self.to_u128().and_then(|v| if v <= u64::max_value() as u128 { + Some(v as u64) + } else { + None + }) + } + + /// Converts the value to a `u128` if it's in the range 0...std::u128::MAX + pub fn to_u128(&self) -> Option { 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(Is16(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(Us16(v)) => Some(v as u64), - Usize(Us32(v)) => Some(v as u64), - Usize(Us64(v)) => Some(v), + InferSigned(v) if v >= 0 => Some(v as u128), + I8(v) if v >= 0 => Some(v as u128), + I16(v) if v >= 0 => Some(v as u128), + I32(v) if v >= 0 => Some(v as u128), + I64(v) if v >= 0 => Some(v as u128), + I128(v) if v >= 0 => Some(v as u128), + Isize(Is16(v)) if v >= 0 => Some(v as u128), + Isize(Is32(v)) if v >= 0 => Some(v as u128), + Isize(Is64(v)) if v >= 0 => Some(v as u128), + U8(v) => Some(v as u128), + U16(v) => Some(v as u128), + U32(v) => Some(v as u128), + U64(v) => Some(v as u128), + U128(v) => Some(v as u128), + Usize(Us16(v)) => Some(v as u128), + Usize(Us32(v)) => Some(v as u128), + Usize(Us64(v)) => Some(v as u128), _ => None, } } @@ -224,6 +288,7 @@ impl ConstInt { I16(v) => v < 0, I32(v) => v < 0, I64(v) => v < 0, + I128(v) => v < 0, Isize(Is16(v)) => v < 0, Isize(Is32(v)) => v < 0, Isize(Is64(v)) => v < 0, @@ -239,6 +304,7 @@ impl ConstInt { (I16(a), I16(b)) => Ok(a.cmp(&b)), (I32(a), I32(b)) => Ok(a.cmp(&b)), (I64(a), I64(b)) => Ok(a.cmp(&b)), + (I128(a), I128(b)) => Ok(a.cmp(&b)), (Isize(Is16(a)), Isize(Is16(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)), @@ -246,6 +312,7 @@ impl ConstInt { (U16(a), U16(b)) => Ok(a.cmp(&b)), (U32(a), U32(b)) => Ok(a.cmp(&b)), (U64(a), U64(b)) => Ok(a.cmp(&b)), + (U128(a), U128(b)) => Ok(a.cmp(&b)), (Usize(Us16(a)), Usize(Us16(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)), @@ -265,6 +332,7 @@ impl ConstInt { ConstInt::I16(i) => ConstInt::I16(add1!(i)), ConstInt::I32(i) => ConstInt::I32(add1!(i)), ConstInt::I64(i) => ConstInt::I64(add1!(i)), + ConstInt::I128(i) => ConstInt::I128(add1!(i)), ConstInt::Isize(ConstIsize::Is16(i)) => ConstInt::Isize(ConstIsize::Is16(add1!(i))), ConstInt::Isize(ConstIsize::Is32(i)) => ConstInt::Isize(ConstIsize::Is32(add1!(i))), ConstInt::Isize(ConstIsize::Is64(i)) => ConstInt::Isize(ConstIsize::Is64(add1!(i))), @@ -272,6 +340,7 @@ impl ConstInt { ConstInt::U16(i) => ConstInt::U16(add1!(i)), ConstInt::U32(i) => ConstInt::U32(add1!(i)), ConstInt::U64(i) => ConstInt::U64(add1!(i)), + ConstInt::U128(i) => ConstInt::U128(add1!(i)), ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))), ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))), ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))), @@ -285,11 +354,13 @@ impl ConstInt { ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)), ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)), ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)), + ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)), 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::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)), ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)), _ => None, } @@ -317,6 +388,7 @@ impl ::std::fmt::Display for ConstInt { I16(i) => write!(fmt, "{}i16", i), I32(i) => write!(fmt, "{}i32", i), I64(i) => write!(fmt, "{}i64", i), + I128(i) => write!(fmt, "{}i128", i), Isize(ConstIsize::Is64(i)) => write!(fmt, "{}isize", i), Isize(ConstIsize::Is32(i)) => write!(fmt, "{}isize", i), Isize(ConstIsize::Is16(i)) => write!(fmt, "{}isize", i), @@ -324,6 +396,7 @@ impl ::std::fmt::Display for ConstInt { U16(i) => write!(fmt, "{}u16", i), U32(i) => write!(fmt, "{}u32", i), U64(i) => write!(fmt, "{}u64", i), + U128(i) => write!(fmt, "{}u128", i), Usize(ConstUsize::Us64(i)) => write!(fmt, "{}usize", i), Usize(ConstUsize::Us32(i)) => write!(fmt, "{}usize", i), Usize(ConstUsize::Us16(i)) => write!(fmt, "{}usize", i), @@ -351,6 +424,7 @@ macro_rules! impl_binop { (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), + (I128(a), I128(b)) => a.$checked_func(b).map(I128), (Isize(Is16(a)), Isize(Is16(b))) => a.$checked_func(b).map(Is16).map(Isize), (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), @@ -358,6 +432,7 @@ macro_rules! impl_binop { (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), + (U128(a), U128(b)) => a.$checked_func(b).map(U128), (Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize), (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), @@ -380,6 +455,7 @@ macro_rules! derive_binop { (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))), + (I128(a), I128(b)) => Ok(I128(a.$func(b))), (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(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)))), @@ -387,6 +463,7 @@ macro_rules! derive_binop { (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))), + (U128(a), U128(b)) => Ok(U128(a.$func(b))), (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(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)))), @@ -406,6 +483,11 @@ derive_binop!(BitAnd, bitand); derive_binop!(BitOr, bitor); derive_binop!(BitXor, bitxor); +#[cfg(not(stage0))] +const I128_MIN: i128 = ::std::i128::MIN; +#[cfg(stage0)] +const I128_MIN: i128 = ::std::i64::MIN; + fn check_division( lhs: ConstInt, rhs: ConstInt, @@ -417,6 +499,7 @@ fn check_division( (I16(_), I16(0)) => Err(zerr), (I32(_), I32(0)) => Err(zerr), (I64(_), I64(0)) => Err(zerr), + (I128(_), I128(0)) => Err(zerr), (Isize(_), Isize(Is16(0))) => Err(zerr), (Isize(_), Isize(Is32(0))) => Err(zerr), (Isize(_), Isize(Is64(0))) => Err(zerr), @@ -426,6 +509,7 @@ fn check_division( (U16(_), U16(0)) => Err(zerr), (U32(_), U32(0)) => Err(zerr), (U64(_), U64(0)) => Err(zerr), + (U128(_), U128(0)) => Err(zerr), (Usize(_), Usize(Us16(0))) => Err(zerr), (Usize(_), Usize(Us32(0))) => Err(zerr), (Usize(_), Usize(Us64(0))) => Err(zerr), @@ -435,10 +519,11 @@ fn check_division( (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)), + (I128(I128_MIN), I128(-1)) => Err(Overflow(op)), (Isize(Is16(::std::i16::MIN)), Isize(Is16(-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)), + (InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)), _ => Ok(()), } @@ -454,6 +539,7 @@ impl ::std::ops::Div for ConstInt { (I16(a), I16(b)) => Ok(I16(a/b)), (I32(a), I32(b)) => Ok(I32(a/b)), (I64(a), I64(b)) => Ok(I64(a/b)), + (I128(a), I128(b)) => Ok(I128(a/b)), (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))), (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))), (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))), @@ -463,6 +549,7 @@ impl ::std::ops::Div for ConstInt { (U16(a), U16(b)) => Ok(U16(a/b)), (U32(a), U32(b)) => Ok(U32(a/b)), (U64(a), U64(b)) => Ok(U64(a/b)), + (U128(a), U128(b)) => Ok(U128(a/b)), (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))), @@ -484,6 +571,7 @@ impl ::std::ops::Rem for ConstInt { (I16(a), I16(b)) => Ok(I16(a%b)), (I32(a), I32(b)) => Ok(I32(a%b)), (I64(a), I64(b)) => Ok(I64(a%b)), + (I128(a), I128(b)) => Ok(I128(a%b)), (Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))), (Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))), (Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))), @@ -493,6 +581,7 @@ impl ::std::ops::Rem for ConstInt { (U16(a), U16(b)) => Ok(U16(a%b)), (U32(a), U32(b)) => Ok(U32(a%b)), (U64(a), U64(b)) => Ok(U64(a%b)), + (U128(a), U128(b)) => Ok(U128(a%b)), (Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))), (Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))), (Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))), @@ -512,6 +601,7 @@ impl ::std::ops::Shl for ConstInt { 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))), + I128(a) => Ok(I128(overflowing!(a.overflowing_shl(b), Op::Shl))), Isize(Is16(a)) => Ok(Isize(Is16(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)))), @@ -519,6 +609,7 @@ impl ::std::ops::Shl for ConstInt { 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))), + U128(a) => Ok(U128(overflowing!(a.overflowing_shl(b), Op::Shl))), Usize(Us16(a)) => Ok(Usize(Us16(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)))), @@ -537,6 +628,7 @@ impl ::std::ops::Shr for ConstInt { 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::Shr))), + I128(a) => Ok(I128(overflowing!(a.overflowing_shr(b), Op::Shr))), Isize(Is16(a)) => Ok(Isize(Is16(overflowing!(a.overflowing_shr(b), Op::Shr)))), 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)))), @@ -544,6 +636,7 @@ impl ::std::ops::Shr for ConstInt { 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))), + U128(a) => Ok(U128(overflowing!(a.overflowing_shr(b), Op::Shr))), Usize(Us16(a)) => Ok(Usize(Us16(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)))), @@ -561,22 +654,14 @@ impl ::std::ops::Neg for ConstInt { 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))), + I128(a) => Ok(I128(overflowing!(a.overflowing_neg(), Op::Neg))), Isize(Is16(a)) => Ok(Isize(Is16(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(Us16(0)) => Ok(Usize(Us16(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))), + a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) | + a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a), + U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation), + Infer(a @ 0...ubounds::I64MAX) => Ok(InferSigned(-(a as i128))), Infer(_) => Err(Overflow(Op::Neg)), InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))), } @@ -591,6 +676,7 @@ impl ::std::ops::Not for ConstInt { I16(a) => Ok(I16(!a)), I32(a) => Ok(I32(!a)), I64(a) => Ok(I64(!a)), + I128(a) => Ok(I128(!a)), Isize(Is16(a)) => Ok(Isize(Is16(!a))), Isize(Is32(a)) => Ok(Isize(Is32(!a))), Isize(Is64(a)) => Ok(Isize(Is64(!a))), @@ -598,6 +684,7 @@ impl ::std::ops::Not for ConstInt { U16(a) => Ok(U16(!a)), U32(a) => Ok(U32(!a)), U64(a) => Ok(U64(!a)), + U128(a) => Ok(U128(!a)), Usize(Us16(a)) => Ok(Usize(Us16(!a))), Usize(Us32(a)) => Ok(Usize(Us32(!a))), Usize(Us64(a)) => Ok(Usize(Us64(!a))), diff --git a/src/librustc_const_math/is.rs b/src/librustc_const_math/is.rs index ef92b628523e7..19ae0c91fc5f9 100644 --- a/src/librustc_const_math/is.rs +++ b/src/librustc_const_math/is.rs @@ -10,6 +10,7 @@ use syntax::ast; use super::err::*; +use rustc_i128::i128; /// 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 @@ -41,11 +42,11 @@ impl ConstIsize { _ => unreachable!(), } } - pub fn new_truncating(i: i64, target_int_ty: ast::IntTy) -> Self { + pub fn new_truncating(i: i128, target_int_ty: ast::IntTy) -> Self { match target_int_ty { ast::IntTy::I16 => Is16(i as i16), ast::IntTy::I32 => Is32(i as i32), - ast::IntTy::I64 => Is64(i), + ast::IntTy::I64 => Is64(i as i64), _ => unreachable!(), } } diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs index 741dd4107e001..5ba5f8bd075d8 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -26,10 +26,14 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(question_mark)] +#![feature(const_fn)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; +// SNAP: remove use of this crate +extern crate rustc_i128; + extern crate serialize as rustc_serialize; // used by deriving mod float; diff --git a/src/librustc_const_math/us.rs b/src/librustc_const_math/us.rs index bf73ff03c9895..9ebf5cab6bb06 100644 --- a/src/librustc_const_math/us.rs +++ b/src/librustc_const_math/us.rs @@ -10,6 +10,7 @@ use syntax::ast; use super::err::*; +use rustc_i128::u128; /// 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 @@ -41,11 +42,11 @@ impl ConstUsize { _ => unreachable!(), } } - pub fn new_truncating(i: u64, target_uint_ty: ast::UintTy) -> Self { + pub fn new_truncating(i: u128, target_uint_ty: ast::UintTy) -> Self { match target_uint_ty { ast::UintTy::U16 => Us16(i as u16), ast::UintTy::U32 => Us32(i as u32), - ast::UintTy::U64 => Us64(i), + ast::UintTy::U64 => Us64(i as u64), _ => unreachable!(), } } diff --git a/src/librustc_i128/Cargo.toml b/src/librustc_i128/Cargo.toml new file mode 100644 index 0000000000000..79632394bf6b0 --- /dev/null +++ b/src/librustc_i128/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_i128" +version = "0.0.0" + +[lib] +name = "rustc_i128" +path = "lib.rs" +crate-type = ["dylib"] diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs new file mode 100644 index 0000000000000..a9770396e7882 --- /dev/null +++ b/src/librustc_i128/lib.rs @@ -0,0 +1,28 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(non_camel_case_types)] +#![cfg_attr(not(stage0), feature(i128_type))] +#![crate_type="rlib"] +#![crate_name="rustc_i128"] + +#[cfg(stage0)] +pub type i128 = i64; +#[cfg(stage0)] +pub type u128 = u64; + +#[cfg(not(stage0))] +pub type i128 = int::_i128; +#[cfg(not(stage0))] +pub type u128 = int::_u128; +#[cfg(not(stage0))] +mod int { + pub type _i128 = i128; + pub type _u128 = u128; +} diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0ae1..272f8b4f64dbd 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -14,5 +14,6 @@ log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_eval = { path = "../librustc_const_eval" } +rustc_i128 = { path = "../librustc_i128" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index bc2979c806f65..90027e8cc20d3 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -48,6 +48,8 @@ extern crate rustc_back; extern crate rustc_const_eval; extern crate syntax_pos; +extern crate rustc_i128; + pub use rustc::lint as lint; pub use rustc::middle as middle; pub use rustc::session as session; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1209ced8dd3d7..5d08a62243ba5 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -33,6 +33,8 @@ use syntax::codemap; use rustc::hir; +use rustc_i128::{i128, u128}; + register_long_diagnostics! { E0519: r##" It is not allowed to negate an unsigned integer. @@ -145,7 +147,7 @@ impl LateLintPass for TypeLimits { if let Some(bits) = opt_ty_bits { let exceeding = if let hir::ExprLit(ref lit) = r.node { - if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits } + if let ast::LitKind::Int(shift, _) = lit.node { shift as u64 >= bits } else { false } } else { match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) { @@ -176,12 +178,13 @@ impl LateLintPass for TypeLimits { t }; let (_, max) = int_ty_range(int_type); + let max = max as u128; let negative = self.negated_expr_id == e.id; // Detect literal value out of range [min, max] inclusive // avoiding use of -min to prevent overflow/panic - if (negative && v > max as u64 + 1) || - (!negative && v > max as u64) { + if (negative && v > max + 1) || + (!negative && v > max) { cx.span_lint(OVERFLOWING_LITERALS, e.span, &format!("literal out of range for {:?}", t)); return; @@ -197,7 +200,7 @@ impl LateLintPass for TypeLimits { t }; let (min, max) = uint_ty_range(uint_type); - let lit_val: u64 = match lit.node { + let lit_val: u128 = match lit.node { // _v is u8, within range by definition ast::LitKind::Byte(_v) => return, ast::LitKind::Int(v, _) => v, @@ -255,23 +258,25 @@ impl LateLintPass for TypeLimits { // for isize & usize, be conservative with the warnings, so that the // warnings are consistent between 32- and 64-bit platforms - fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) { + fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) { match int_ty { - ast::IntTy::Is => (i64::MIN, i64::MAX), - ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64), - ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64), - ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64), - ast::IntTy::I64 => (i64::MIN, i64::MAX) + ast::IntTy::I8 => (i8::min_value() as i128, i8::max_value() as i128), + ast::IntTy::I16 => (i16::min_value() as i128, i16::max_value() as i128), + ast::IntTy::I32 => (i32::min_value() as i128, i32::max_value() as i128), + ast::IntTy::I64 => (i64::min_value() as i128, i64::max_value() as i128), + ast::IntTy::I128 =>(i128::min_value() as i128, i128::max_value() as i128), + ast::IntTy::Is => (i64::min_value() as i128, i64::max_value() as i128), } } - fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) { + fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) { match uint_ty { - ast::UintTy::Us => (u64::MIN, u64::MAX), - ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64), - ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64), - ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64), - ast::UintTy::U64 => (u64::MIN, u64::MAX) + ast::UintTy::U8 => (u8::min_value() as u128, u8::max_value() as u128), + ast::UintTy::U16 => (u16::min_value() as u128, u16::max_value() as u128), + ast::UintTy::U32 => (u32::min_value() as u128, u32::max_value() as u128), + ast::UintTy::U64 => (u64::min_value() as u128, u64::max_value() as u128), + ast::UintTy::U128 => (u128::min_value() as u128, u128::max_value() as u128), + ast::UintTy::Us => (u64::min_value() as u128, u64::max_value() as u128), } } @@ -289,6 +294,7 @@ impl LateLintPass for TypeLimits { ast::IntTy::I16 => 16 as u64, ast::IntTy::I32 => 32, ast::IntTy::I64 => 64, + ast::IntTy::I128 => 128, } } @@ -299,6 +305,7 @@ impl LateLintPass for TypeLimits { ast::UintTy::U16 => 16, ast::UintTy::U32 => 32, ast::UintTy::U64 => 64, + ast::UintTy::U128 => 128, } } @@ -321,10 +328,10 @@ impl LateLintPass for TypeLimits { match tcx.node_id_to_type(expr.id).sty { ty::TyInt(int_ty) => { let (min, max) = int_ty_range(int_ty); - let lit_val: i64 = match lit.node { + let lit_val: i128 = match lit.node { hir::ExprLit(ref li) => match li.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_)) | - ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64, + ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i128, _ => return true }, _ => bug!() @@ -332,8 +339,8 @@ impl LateLintPass for TypeLimits { is_valid(norm_binop, lit_val, min, max) } ty::TyUint(uint_ty) => { - let (min, max): (u64, u64) = uint_ty_range(uint_ty); - let lit_val: u64 = match lit.node { + let (min, max) = uint_ty_range(uint_ty); + let lit_val: u128 = match lit.node { hir::ExprLit(ref li) => match li.node { ast::LitKind::Int(v, _) => v, _ => return true diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 50c68d5e75eef..2a0981d7ec017 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -636,6 +636,8 @@ extern { /* Operations on scalar constants */ pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef; + pub fn LLVMConstIntOfArbitraryPrecision(IntTy: TypeRef, Wn: c_uint, Ws: *const u64) + -> ValueRef; pub fn LLVMConstIntOfString(IntTy: TypeRef, Text: *const c_char, Radix: u8) -> ValueRef; pub fn LLVMConstIntOfStringAndSize(IntTy: TypeRef, @@ -652,6 +654,8 @@ extern { -> ValueRef; pub fn LLVMConstIntGetZExtValue(ConstantVal: ValueRef) -> c_ulonglong; pub fn LLVMConstIntGetSExtValue(ConstantVal: ValueRef) -> c_longlong; + pub fn LLVMRustConstInt128Get(ConstantVal: ValueRef, SExt: bool, + high: *mut u64, low: *mut u64) -> bool; /* Operations on composite constants */ diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 680d55955bb96..256a82c1e7e67 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -18,6 +18,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } rustc_macro = { path = "../librustc_macro" } +rustc_i128 = { path = "../librustc_i128" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3e4a2542b270b..600291855da93 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -44,6 +44,7 @@ use syntax::attr; use syntax::ast::{self, NodeId}; use syntax::codemap; use syntax_pos::{self, Span, BytePos, Pos}; +use rustc_i128::{u128, i128}; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, @@ -186,12 +187,14 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { decoder_methods! { read_nil -> (); + read_u128 -> u128; read_u64 -> u64; read_u32 -> u32; read_u16 -> u16; read_u8 -> u8; read_usize -> usize; + read_i128 -> i128; read_i64 -> i64; read_i32 -> i32; read_i16 -> i16; diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0f067270b80f5..82d6cdf89c6f4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -42,6 +42,8 @@ use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; +use rustc_i128::{u128, i128}; + use super::index_builder::{FromId, IndexBuilder, Untracked}; pub struct EncodeContext<'a, 'tcx: 'a> { @@ -75,12 +77,14 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { encoder_methods! { emit_usize(usize); + emit_u128(u128); emit_u64(u64); emit_u32(u32); emit_u16(u16); emit_u8(u8); emit_isize(isize); + emit_i128(i128); emit_i64(i64); emit_i32(i32); emit_i16(i16); @@ -259,7 +263,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = VariantData { kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: None }; @@ -410,7 +414,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = VariantData { kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: Some(def_id.index) }; @@ -672,7 +676,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; EntryKind::Struct(self.lazy(&VariantData { kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: struct_ctor })) } @@ -681,7 +685,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Union(self.lazy(&VariantData { kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: None })) } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 4fc5a46762d12..036a0262e19b9 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -45,9 +45,12 @@ extern crate rustc_back; extern crate rustc_llvm; extern crate rustc_macro; extern crate rustc_const_math; +extern crate rustc_i128; mod diagnostics; +pub use rustc::middle; + mod astencode; mod index_builder; mod index; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index f4d1e8e17f842..0ed9b534b39c8 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -26,6 +26,8 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; +use rustc_i128::u128; + #[cfg(not(test))] pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION")); @@ -264,7 +266,7 @@ pub struct FnData { #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData { pub kind: ty::VariantKind, - pub disr: u64, + pub disr: u128, /// If this is a struct's only variant, this /// is the index of the "struct ctor" item. diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 2a1a815330675..7e26aa9a57bf5 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -17,5 +17,6 @@ rustc_const_eval = { path = "../librustc_const_eval" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_bitflags = { path = "../librustc_bitflags" } +rustc_i128 = { path = "../librustc_i128" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index a40571c5d8597..8b4a3655c368a 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -15,6 +15,7 @@ use std; use rustc_const_math::{ConstMathErr, Op}; use rustc_data_structures::fnv::FnvHashMap; use rustc_data_structures::indexed_vec::Idx; +use rustc_i128::i128; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; @@ -343,6 +344,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I16 => ConstInt::I16(-1), ast::IntTy::I32 => ConstInt::I32(-1), ast::IntTy::I64 => ConstInt::I64(-1), + ast::IntTy::I128 => ConstInt::I128(-1), ast::IntTy::Is => { let int_ty = self.hir.tcx().sess.target.int_type; let val = ConstIsize::new(-1, int_ty).unwrap(); @@ -365,10 +367,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let literal = match ty.sty { ty::TyInt(ity) => { let val = match ity { - ast::IntTy::I8 => ConstInt::I8(std::i8::MIN), - ast::IntTy::I16 => ConstInt::I16(std::i16::MIN), - ast::IntTy::I32 => ConstInt::I32(std::i32::MIN), - ast::IntTy::I64 => ConstInt::I64(std::i64::MIN), + ast::IntTy::I8 => ConstInt::I8(i8::min_value()), + ast::IntTy::I16 => ConstInt::I16(i16::min_value()), + ast::IntTy::I32 => ConstInt::I32(i32::min_value()), + ast::IntTy::I64 => ConstInt::I64(i64::min_value()), + ast::IntTy::I128 => ConstInt::I128(i128::min_value()), ast::IntTy::Is => { let int_ty = self.hir.tcx().sess.target.int_type; let min = match int_ty { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 79a4cf73041d7..a7debfe82ab85 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -66,6 +66,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::UintTy::U16 => ConstInt::U16(0), ast::UintTy::U32 => ConstInt::U32(0), ast::UintTy::U64 => ConstInt::U64(0), + ast::UintTy::U128 => ConstInt::U128(0), ast::UintTy::Us => { let uint_ty = self.hir.tcx().sess.target.uint_type; let val = ConstUsize::new(0, uint_ty).unwrap(); @@ -81,6 +82,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast::IntTy::I16 => ConstInt::I16(0), ast::IntTy::I32 => ConstInt::I32(0), ast::IntTy::I64 => ConstInt::I64(0), + ast::IntTy::I128 => ConstInt::I128(0), ast::IntTy::Is => { let int_ty = self.hir.tcx().sess.target.int_type; let val = ConstIsize::new(0, int_ty).unwrap(); diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 12f1eb8535a3e..272823d6e09c5 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -43,6 +43,8 @@ extern crate syntax_pos; extern crate rustc_const_math; extern crate rustc_const_eval; +extern crate rustc_i128; + pub mod diagnostics; pub mod build; diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fb9819b72ab3e..2cb0577bfa979 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -59,6 +59,7 @@ use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy}; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::visit::{self, FnKind, Visitor}; use syntax::attr; @@ -964,13 +965,14 @@ impl PrimitiveTypeTable { table.intern("i16", TyInt(IntTy::I16)); table.intern("i32", TyInt(IntTy::I32)); table.intern("i64", TyInt(IntTy::I64)); + table.intern("i128", TyInt(IntTy::I128)); table.intern("str", TyStr); table.intern("usize", TyUint(UintTy::Us)); table.intern("u8", TyUint(UintTy::U8)); table.intern("u16", TyUint(UintTy::U16)); table.intern("u32", TyUint(UintTy::U32)); table.intern("u64", TyUint(UintTy::U64)); - + table.intern("u128", TyUint(UintTy::U128)); table } @@ -2491,11 +2493,20 @@ impl<'a> Resolver<'a> { let resolve_identifier_with_fallback = |this: &mut Self, record_used| { let def = this.resolve_identifier(last_ident, namespace, record_used); match def { - None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS => - this.primitive_type_table - .primitive_types - .get(&last_ident.name) - .map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))), + None | Some(LocalDef{def: Def::Mod(..), ..}) if namespace == TypeNS => { + let prim = this.primitive_type_table.primitive_types.get(&last_ident.name); + match prim { + Some(&TyUint(UintTy::U128)) | Some(&TyInt(IntTy::I128)) => { + if !this.session.features.borrow().i128_type { + emit_feature_err(&this.session.parse_sess, + "i128_type", span, GateIssue::Language, + "128-bit type is unstable"); + } + } + _ => {} + } + prim.map_or(def, |prim_ty| Some(LocalDef::from_def(Def::PrimTy(*prim_ty)))) + } _ => def } }; diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 38f9e7ab0c51c..abca78c1fb5df 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -22,7 +22,8 @@ rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_incremental = { path = "../librustc_incremental" } rustc_llvm = { path = "../librustc_llvm" } +rustc_i128 = { path = "../librustc_i128" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 446042b839ad3..b29b40e6e71e7 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -727,7 +727,7 @@ pub fn with_cond<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, val: ValueRef, f: F) -> { let _icx = push_ctxt("with_cond"); - if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) { + if bcx.unreachable.get() || common::const_to_opt_u128(val, false) == Some(0) { return bcx; } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 5b1f691af8df7..893bcdf94a8e9 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -53,6 +53,8 @@ use syntax::parse::token::InternedString; use syntax::parse::token; use syntax_pos::{DUMMY_SP, Span}; +use rustc_i128::u128; + pub use context::{CrateContext, SharedCrateContext}; /// Is the type's representation size known at compile time? @@ -730,6 +732,16 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { } } +pub fn C_big_integral(t: Type, u: u128) -> ValueRef { + if ::std::mem::size_of::() == 16 { + unsafe { + llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, &u as *const u128 as *const u64) + } + } else { + C_integral(t, u as u64, false) + } +} + pub fn C_floating_f64(f: f64, t: Type) -> ValueRef { unsafe { llvm::LLVMConstReal(t.to_ref(), f) @@ -887,20 +899,34 @@ fn is_const_integral(v: ValueRef) -> bool { } } -pub fn const_to_opt_int(v: ValueRef) -> Option { + +#[cfg(stage0)] +pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { unsafe { if is_const_integral(v) { - Some(llvm::LLVMConstIntGetSExtValue(v)) + if !sign_ext { + Some(llvm::LLVMConstIntGetZExtValue(v)) + } else { + Some(llvm::LLVMConstIntGetSExtValue(v) as u64) + } } else { None } } } -pub fn const_to_opt_uint(v: ValueRef) -> Option { +#[cfg(not(stage0))] +pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { unsafe { if is_const_integral(v) { - Some(llvm::LLVMConstIntGetZExtValue(v)) + let (mut lo, mut hi) = (0u64, 0u64); + let success = llvm::LLVMRustConstInt128Get(v, sign_ext, + &mut hi as *mut u64, &mut lo as *mut u64); + if success { + Some(((hi as u128) << 64) | (lo as u128)) + } else { + None + } } else { None } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 1b67516a9e6d0..e75d357622bbf 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -1070,6 +1070,7 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option { let t_i16 = Type::i16(ccx); let t_i32 = Type::i32(ccx); let t_i64 = Type::i64(ccx); + let t_i128 = Type::i128(ccx); let t_f32 = Type::f32(ccx); let t_f64 = Type::f64(ccx); @@ -1136,50 +1137,60 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option { ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); + ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); ifn!("llvm.ctlz.i8", fn(t_i8 , i1) -> t_i8); ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); ifn!("llvm.cttz.i8", fn(t_i8 , i1) -> t_i8); ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void); ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void); diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index a441800795b96..bf62b448be802 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1650,7 +1650,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), name.as_ptr(), - v.disr_val.to_u64_unchecked()) + // FIXME: what if enumeration has i128 discriminant? + v.disr_val.to_u128_unchecked() as u64) } }) .collect(); diff --git a/src/librustc_trans/disr.rs b/src/librustc_trans/disr.rs index fc79fa813aa5a..c5737c6e5f12c 100644 --- a/src/librustc_trans/disr.rs +++ b/src/librustc_trans/disr.rs @@ -26,7 +26,8 @@ impl ::std::ops::BitAnd for Disr { impl From<::rustc::ty::Disr> for Disr { fn from(i: ::rustc::ty::Disr) -> Disr { - Disr(i.to_u64_unchecked()) + // FIXME: what if discr has 128 bit discr? + Disr(i.to_u128_unchecked() as u64) } } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index fe76ec05f6ead..b10a6e59ebb50 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -378,11 +378,12 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, // Choose max of two known alignments (combined value must // be aligned according to more restrictive of the two). - let align = match (const_to_opt_uint(sized_align), const_to_opt_uint(unsized_align)) { + let align = match (const_to_opt_u128(sized_align, false), + const_to_opt_u128(unsized_align, false)) { (Some(sized_align), Some(unsized_align)) => { // If both alignments are constant, (the sized_align should always be), then // pick the correct alignment statically. - C_uint(ccx, std::cmp::max(sized_align, unsized_align)) + C_uint(ccx, std::cmp::max(sized_align, unsized_align) as u64) } _ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align), sized_align, diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 4cacbc0f35eff..bbec27fa1c674 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -35,6 +35,8 @@ use syntax::parse::token; use rustc::session::Session; use syntax_pos::{Span, DUMMY_SP}; +use rustc_i128::u128; + use std::cmp::Ordering; fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { @@ -1170,7 +1172,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> in_elem, in_ty, ret_ty, ret_ty.simd_type(tcx)); - let total_len = in_len as u64 * 2; + let total_len = in_len as u128 * 2; let vector = llargs[2]; @@ -1178,7 +1180,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> .map(|i| { let arg_idx = i; let val = const_get_elt(vector, &[i as libc::c_uint]); - match const_to_opt_uint(val) { + match const_to_opt_u128(val, true) { None => { emit_error!("shuffle index #{} is not a constant", arg_idx); None @@ -1318,6 +1320,8 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> // Returns the width of an int TypeVariant, and if it's signed or not // Returns None if the type is not an integer +// FIXME: there’s multiple of this functions, investigate using some of the already existing +// stuffs. fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) -> Option<(u64, bool)> { use rustc::ty::{TyInt, TyUint}; @@ -1335,6 +1339,7 @@ fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) ast::IntTy::I16 => 16, ast::IntTy::I32 => 32, ast::IntTy::I64 => 64, + ast::IntTy::I128 => 128, }, true)), TyUint(t) => Some((match t { ast::UintTy::Us => { @@ -1349,6 +1354,7 @@ fn int_type_width_signed<'tcx>(sty: &ty::TypeVariants<'tcx>, ccx: &CrateContext) ast::UintTy::U16 => 16, ast::UintTy::U32 => 32, ast::UintTy::U64 => 64, + ast::UintTy::U128 => 128, }, false)), _ => None, } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 41c8d565d418c..3eb438f38b442 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -54,6 +54,7 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; extern crate rustc_const_math; extern crate rustc_const_eval; +extern crate rustc_i128; #[macro_use] extern crate log; #[macro_use] extern crate syntax; diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 003830123ff3b..b8a2ad550fcba 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -278,7 +278,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { let cond = self.trans_operand(&bcx, cond).immediate(); - let mut const_cond = common::const_to_opt_uint(cond).map(|c| c == 1); + let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1); // This case can currently arise only from functions marked // with #[rustc_inherit_overflow_checks] and inlined from @@ -331,14 +331,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let len = self.trans_operand(&mut bcx, len).immediate(); let index = self.trans_operand(&mut bcx, index).immediate(); - let const_err = common::const_to_opt_uint(len).and_then(|len| { - common::const_to_opt_uint(index).map(|index| { - ErrKind::IndexOutOfBounds { - len: len, - index: index - } - }) - }); + let const_err = common::const_to_opt_u128(len, false) + .and_then(|len| common::const_to_opt_u128(index, false) + .map(|index| ErrKind::IndexOutOfBounds { + len: len as u64, + index: index as u64 + })); let file_line = C_struct(bcx.ccx(), &[filename, line], false); let align = llalign_of_min(bcx.ccx(), common::val_ty(file_line)); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index b74d56ce368a9..1d728709d4d29 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -13,7 +13,7 @@ use rustc::middle::const_val::ConstVal; use rustc_const_eval::{ErrKind, ConstEvalErr, report_const_eval_err}; use rustc_const_math::ConstInt::*; use rustc_const_math::ConstFloat::*; -use rustc_const_math::{ConstInt, ConstIsize, ConstUsize, ConstMathErr}; +use rustc_const_math::{ConstInt, ConstMathErr}; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; use rustc::mir::repr as mir; @@ -26,17 +26,17 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use {abi, adt, base, Disr, machine}; use callee::Callee; use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty, type_is_sized}; -use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral}; +use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral, C_big_integral}; use common::{C_null, C_struct, C_str_slice, C_undef, C_uint}; -use common::{const_to_opt_int, const_to_opt_uint}; +use common::{const_to_opt_u128}; use consts; use monomorphize::{self, Instance}; use type_of; use type_::Type; use value::Value; -use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; +use rustc_i128::u128; use std::fmt; use std::ptr; @@ -44,6 +44,8 @@ use std::ptr; use super::operand::{OperandRef, OperandValue}; use super::MirContext; +use rustc_i128::{i128}; + /// A sized constant rvalue. /// The LLVM type might not be the same for a single Rust type, /// e.g. each enum variant would have its own LLVM struct type. @@ -76,6 +78,7 @@ impl<'tcx> Const<'tcx> { 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(I128(v)) => C_big_integral(Type::i128(ccx), v as u128), ConstVal::Integral(Isize(v)) => { let i = v.as_i64(ccx.tcx().sess.target.int_type); C_integral(Type::int(ccx), i as u64, true) @@ -84,6 +87,7 @@ impl<'tcx> Const<'tcx> { 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(U128(v)) => C_big_integral(Type::i128(ccx), v), ConstVal::Integral(Usize(v)) => { let u = v.as_u64(ccx.tcx().sess.target.uint_type); C_integral(Type::int(ccx), u, false) @@ -453,7 +457,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::ProjectionElem::Index(ref index) => { let llindex = self.const_operand(index, span)?.llval; - let iv = if let Some(iv) = common::const_to_opt_uint(llindex) { + let iv = if let Some(iv) = common::const_to_opt_u128(llindex, false) { iv } else { span_bug!(span, "index is not an integer-constant expression") @@ -461,7 +465,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { // Produce an undef instead of a LLVM assertion on OOB. let len = common::const_to_uint(tr_base.len(self.ccx)); - let llelem = if iv < len { + let llelem = if iv < len as u128 { const_get_elt(base.llval, &[iv as u32]) } else { C_undef(type_of::type_of(self.ccx, projected_ty)) @@ -827,49 +831,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn to_const_int(value: ValueRef, t: Ty, tcx: TyCtxt) -> Option { 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, + ty::TyInt(int_type) => const_to_opt_u128(value, true) + .and_then(|input| ConstInt::new_signed(input as i128, int_type, + tcx.sess.target.int_type)), + ty::TyUint(uint_type) => const_to_opt_u128(value, false) + .and_then(|input| ConstInt::new_unsigned(input, uint_type, + tcx.sess.target.uint_type)), + _ => None + } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b643dcd9871b0..5133b5ab96523 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -660,11 +660,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val TyInt(I16) => "llvm.sadd.with.overflow.i16", TyInt(I32) => "llvm.sadd.with.overflow.i32", TyInt(I64) => "llvm.sadd.with.overflow.i64", + TyInt(I128) => "llvm.sadd.with.overflow.i128", TyUint(U8) => "llvm.uadd.with.overflow.i8", TyUint(U16) => "llvm.uadd.with.overflow.i16", TyUint(U32) => "llvm.uadd.with.overflow.i32", TyUint(U64) => "llvm.uadd.with.overflow.i64", + TyUint(U128) => "llvm.uadd.with.overflow.i128", _ => unreachable!(), }, @@ -673,11 +675,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val TyInt(I16) => "llvm.ssub.with.overflow.i16", TyInt(I32) => "llvm.ssub.with.overflow.i32", TyInt(I64) => "llvm.ssub.with.overflow.i64", + TyInt(I128) => "llvm.ssub.with.overflow.i128", TyUint(U8) => "llvm.usub.with.overflow.i8", TyUint(U16) => "llvm.usub.with.overflow.i16", TyUint(U32) => "llvm.usub.with.overflow.i32", TyUint(U64) => "llvm.usub.with.overflow.i64", + TyUint(U128) => "llvm.usub.with.overflow.i128", _ => unreachable!(), }, @@ -686,11 +690,13 @@ fn get_overflow_intrinsic(oop: OverflowOp, bcx: &BlockAndBuilder, ty: Ty) -> Val TyInt(I16) => "llvm.smul.with.overflow.i16", TyInt(I32) => "llvm.smul.with.overflow.i32", TyInt(I64) => "llvm.smul.with.overflow.i64", + TyInt(I128) => "llvm.smul.with.overflow.i128", TyUint(U8) => "llvm.umul.with.overflow.i8", TyUint(U16) => "llvm.umul.with.overflow.i16", TyUint(U32) => "llvm.umul.with.overflow.i32", TyUint(U64) => "llvm.umul.with.overflow.i64", + TyUint(U128) => "llvm.umul.with.overflow.i128", _ => unreachable!(), }, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 5c7cbbbd88d46..66246d17daedf 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -396,11 +396,13 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), + ty::TyInt(ast::IntTy::I128) => output.push_str("i128"), ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), + ty::TyUint(ast::UintTy::U128) => output.push_str("u128"), ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), ty::TyAdt(adt_def, substs) => { diff --git a/src/librustc_trans/type_.rs b/src/librustc_trans/type_.rs index 03a71827b473b..724e96884f223 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -96,6 +96,10 @@ impl Type { ty!(llvm::LLVMInt64TypeInContext(ccx.llcx())) } + pub fn i128(ccx: &CrateContext) -> Type { + ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), 128)) + } + // Creates an integer type with the given number of bits, e.g. i24 pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type { ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint)) @@ -136,7 +140,8 @@ impl Type { ast::IntTy::I8 => Type::i8(ccx), ast::IntTy::I16 => Type::i16(ccx), ast::IntTy::I32 => Type::i32(ccx), - ast::IntTy::I64 => Type::i64(ccx) + ast::IntTy::I64 => Type::i64(ccx), + ast::IntTy::I128 => Type::i128(ccx), } } @@ -146,7 +151,8 @@ impl Type { ast::UintTy::U8 => Type::i8(ccx), ast::UintTy::U16 => Type::i16(ccx), ast::UintTy::U32 => Type::i32(ccx), - ast::UintTy::U64 => Type::i64(ccx) + ast::UintTy::U64 => Type::i64(ccx), + ast::UintTy::U128 => Type::i128(ccx), } } @@ -309,6 +315,7 @@ impl Type { I16 => Type::i16(cx), I32 => Type::i32(cx), I64 => Type::i64(cx), + I128 => Type::i128(cx), } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 93d8b3e1563d9..ed30048cae0e2 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -437,7 +437,9 @@ fn match_intrinsic_type_to_type<'tcx, 'a>( (true, 32, &ty::TyInt(ast::IntTy::I32)) | (false, 32, &ty::TyUint(ast::UintTy::U32)) | (true, 64, &ty::TyInt(ast::IntTy::I64)) | - (false, 64, &ty::TyUint(ast::UintTy::U64)) => {}, + (false, 64, &ty::TyUint(ast::UintTy::U64)) | + (true, 128, &ty::TyInt(ast::IntTy::I128)) | + (false, 128, &ty::TyUint(ast::UintTy::U128)) => {}, _ => simple_error(&format!("`{}`", t), &format!("`{}{n}`", if signed {"i"} else {"u"}, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 9fba9bcb757b6..5c6d531221e7b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -339,6 +339,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = self.tcx.lang_items.i64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } + ty::TyInt(ast::IntTy::I128) => { + let lang_def_id = self.tcx.lang_items.i128_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } ty::TyInt(ast::IntTy::Is) => { let lang_def_id = self.tcx.lang_items.isize_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); @@ -359,6 +363,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = self.tcx.lang_items.u64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); } + ty::TyUint(ast::UintTy::U128) => { + let lang_def_id = self.tcx.lang_items.u128_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + } ty::TyUint(ast::UintTy::Us) => { let lang_def_id = self.tcx.lang_items.usize_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ee00cb2f5a3e4..369a9f44ccbbc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1244,6 +1244,13 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, } let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx); + if repr_type_ty == ccx.tcx.types.i128 || repr_type_ty == ccx.tcx.types.u128 { + if !ccx.tcx.sess.features.borrow().i128_type { + emit_feature_err(&ccx.tcx.sess.parse_sess, + "i128_type", sp, GateIssue::Language, "128-bit type is unstable"); + } + } + for v in vs { if let Some(ref e) = v.node.disr_expr { check_const_with_type(ccx, e, repr_type_ty, e.id); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index 70342a0cd258e..b14b8290fa4d6 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -149,6 +149,13 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { "i64", item.span); } + ty::TyInt(ast::IntTy::I128) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.i128_impl(), + "i128", + "i128", + item.span); + } ty::TyInt(ast::IntTy::Is) => { self.check_primitive_impl(def_id, self.tcx.lang_items.isize_impl(), @@ -184,6 +191,13 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { "u64", item.span); } + ty::TyUint(ast::UintTy::U128) => { + self.check_primitive_impl(def_id, + self.tcx.lang_items.u128_impl(), + "u128", + "u128", + item.span); + } ty::TyUint(ast::UintTy::Us) => { self.check_primitive_impl(def_id, self.tcx.lang_items.usize_impl(), diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index e5d4d4a9dae2c..a38cd4f6eac71 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1119,11 +1119,13 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) | (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) | (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) | + (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) | (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) | (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) | (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) | (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) | (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) | + (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) | (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => Some(i), (_, i) => { print_err(ConstVal::Integral(i)); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0ae059509bd10..c1ed80402a50e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1461,8 +1461,8 @@ pub enum Type { #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Copy, Debug)] pub enum PrimitiveType { - Isize, I8, I16, I32, I64, - Usize, U8, U16, U32, U64, + Isize, I8, I16, I32, I64, I128, + Usize, U8, U16, U32, U64, U128, F32, F64, Char, Bool, @@ -1568,26 +1568,29 @@ impl PrimitiveType { } pub fn to_string(&self) -> &'static str { + use self::PrimitiveType::*; match *self { - PrimitiveType::Isize => "isize", - PrimitiveType::I8 => "i8", - PrimitiveType::I16 => "i16", - PrimitiveType::I32 => "i32", - PrimitiveType::I64 => "i64", - PrimitiveType::Usize => "usize", - PrimitiveType::U8 => "u8", - PrimitiveType::U16 => "u16", - PrimitiveType::U32 => "u32", - PrimitiveType::U64 => "u64", - PrimitiveType::F32 => "f32", - PrimitiveType::F64 => "f64", - PrimitiveType::Str => "str", - PrimitiveType::Bool => "bool", - PrimitiveType::Char => "char", - PrimitiveType::Array => "array", - PrimitiveType::Slice => "slice", - PrimitiveType::Tuple => "tuple", - PrimitiveType::RawPointer => "pointer", + Isize => "isize", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + I128 => "i128", + Usize => "usize", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + U128 => "u128", + F32 => "f32", + F64 => "f64", + Str => "str", + Bool => "bool", + Char => "char", + Array => "array", + Slice => "slice", + Tuple => "tuple", + RawPointer => "pointer", } } @@ -1612,6 +1615,7 @@ impl From for PrimitiveType { ast::IntTy::I16 => PrimitiveType::I16, ast::IntTy::I32 => PrimitiveType::I32, ast::IntTy::I64 => PrimitiveType::I64, + ast::IntTy::I128 => PrimitiveType::I128, } } } @@ -1624,6 +1628,7 @@ impl From for PrimitiveType { ast::UintTy::U16 => PrimitiveType::U16, ast::UintTy::U32 => PrimitiveType::U32, ast::UintTy::U64 => PrimitiveType::U64, + ast::UintTy::U128 => PrimitiveType::U128, } } } @@ -2417,6 +2422,7 @@ impl Clean> for doctree::Impl { fn build_deref_target_impls(cx: &DocContext, items: &[Item], ret: &mut Vec) { + use self::PrimitiveType::*; let tcx = match cx.tcx_opt() { Some(t) => t, None => return, @@ -2439,25 +2445,27 @@ fn build_deref_target_impls(cx: &DocContext, } }; let did = match primitive { - PrimitiveType::Isize => tcx.lang_items.isize_impl(), - PrimitiveType::I8 => tcx.lang_items.i8_impl(), - PrimitiveType::I16 => tcx.lang_items.i16_impl(), - PrimitiveType::I32 => tcx.lang_items.i32_impl(), - PrimitiveType::I64 => tcx.lang_items.i64_impl(), - PrimitiveType::Usize => tcx.lang_items.usize_impl(), - PrimitiveType::U8 => tcx.lang_items.u8_impl(), - PrimitiveType::U16 => tcx.lang_items.u16_impl(), - PrimitiveType::U32 => tcx.lang_items.u32_impl(), - PrimitiveType::U64 => tcx.lang_items.u64_impl(), - PrimitiveType::F32 => tcx.lang_items.f32_impl(), - PrimitiveType::F64 => tcx.lang_items.f64_impl(), - PrimitiveType::Char => tcx.lang_items.char_impl(), - PrimitiveType::Bool => None, - PrimitiveType::Str => tcx.lang_items.str_impl(), - PrimitiveType::Slice => tcx.lang_items.slice_impl(), - PrimitiveType::Array => tcx.lang_items.slice_impl(), - PrimitiveType::Tuple => None, - PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(), + Isize => tcx.lang_items.isize_impl(), + I8 => tcx.lang_items.i8_impl(), + I16 => tcx.lang_items.i16_impl(), + I32 => tcx.lang_items.i32_impl(), + I64 => tcx.lang_items.i64_impl(), + I128 => tcx.lang_items.i128_impl(), + Usize => tcx.lang_items.usize_impl(), + U8 => tcx.lang_items.u8_impl(), + U16 => tcx.lang_items.u16_impl(), + U32 => tcx.lang_items.u32_impl(), + U64 => tcx.lang_items.u64_impl(), + U128 => tcx.lang_items.u128_impl(), + F32 => tcx.lang_items.f32_impl(), + F64 => tcx.lang_items.f64_impl(), + Char => tcx.lang_items.char_impl(), + Bool => None, + Str => tcx.lang_items.str_impl(), + Slice => tcx.lang_items.slice_impl(), + Array => tcx.lang_items.slice_impl(), + Tuple => None, + RawPointer => tcx.lang_items.const_ptr_impl(), }; if let Some(did) = did { if !did.is_local() { diff --git a/src/libserialize/Cargo.toml b/src/libserialize/Cargo.toml index 919cda49c004c..3213b4e4208be 100644 --- a/src/libserialize/Cargo.toml +++ b/src/libserialize/Cargo.toml @@ -10,3 +10,4 @@ crate-type = ["dylib", "rlib"] [dependencies] log = { path = "../liblog" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 6ccc0be41bc0f..0f3651db67dc1 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -210,6 +210,8 @@ use std::string; use std::{char, f64, fmt, str}; use std; +use rustc_i128::{i128, u128}; + use Encodable; /// Represents a json value @@ -495,12 +497,14 @@ impl<'a> ::Encoder for Encoder<'a> { } fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u128(&mut self, v: u128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i128(&mut self, v: i128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } @@ -743,12 +747,14 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } fn emit_usize(&mut self, v: usize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_u128(&mut self, v: u128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u64(&mut self, v: u64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u32(&mut self, v: u32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u16(&mut self, v: u16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_u8(&mut self, v: u8) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_isize(&mut self, v: isize) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } + fn emit_i128(&mut self, v: i128) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i64(&mut self, v: i64) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i32(&mut self, v: i32) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } fn emit_i16(&mut self, v: i16) -> EncodeResult { emit_enquoted_if_mapkey!(self, v) } @@ -2141,11 +2147,13 @@ impl ::Decoder for Decoder { read_primitive! { read_u16, u16 } read_primitive! { read_u32, u32 } read_primitive! { read_u64, u64 } + read_primitive! { read_u128, u128 } read_primitive! { read_isize, isize } read_primitive! { read_i8, i8 } read_primitive! { read_i16, i16 } read_primitive! { read_i32, i32 } read_primitive! { read_i64, i64 } + read_primitive! { read_i128, i128 } fn read_f32(&mut self) -> DecodeResult { self.read_f64().map(|x| x as f32) } diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs index 0c5356c022235..627e9b369737f 100644 --- a/src/libserialize/leb128.rs +++ b/src/libserialize/leb128.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_i128::{i128, u128}; + #[inline] pub fn write_to_vec(vec: &mut Vec, position: &mut usize, byte: u8) { if *position == vec.len() { @@ -19,7 +21,7 @@ pub fn write_to_vec(vec: &mut Vec, position: &mut usize, byte: u8) { *position += 1; } -pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, mut value: u64) -> usize { +pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, mut value: u128) -> usize { let mut position = start_position; loop { let mut byte = (value & 0x7F) as u8; @@ -38,14 +40,14 @@ pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, mut value return position - start_position; } -pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) { +pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u128, usize) { let mut result = 0; let mut shift = 0; let mut position = start_position; loop { let byte = data[position]; position += 1; - result |= ((byte & 0x7F) as u64) << shift; + result |= ((byte & 0x7F) as u128) << shift; if (byte & 0x80) == 0 { break; } @@ -56,14 +58,13 @@ pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) } -pub fn write_signed_leb128(out: &mut Vec, start_position: usize, mut value: i64) -> usize { +pub fn write_signed_leb128(out: &mut Vec, start_position: usize, mut value: i128) -> usize { let mut position = start_position; - loop { - let mut byte = (value as u8) & 0x7f; + let mut byte = (value & 0x7f) as u8; value >>= 7; let more = !((((value == 0) && ((byte & 0x40) == 0)) || - ((value == -1) && ((byte & 0x40) != 0)))); + ((value == !0) && ((byte & 0x40) != 0)))); if more { byte |= 0x80; // Mark this byte to show that more bytes will follow. } @@ -78,7 +79,7 @@ pub fn write_signed_leb128(out: &mut Vec, start_position: usize, mut value: return position - start_position; } -pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) { +pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) { let mut result = 0; let mut shift = 0; let mut position = start_position; @@ -87,7 +88,7 @@ pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) { loop { byte = data[position]; position += 1; - result |= ((byte & 0x7F) as i64) << shift; + result |= ((byte & 0x7F) as i128) << shift; shift += 7; if (byte & 0x80) == 0 { @@ -97,7 +98,7 @@ pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) { if (shift < 64) && ((byte & 0x40) != 0) { // sign extend - result |= -(1i64 << shift); + result |= -(1 << shift); } (result, position - start_position) @@ -125,22 +126,13 @@ fn test_unsigned_leb128() { #[test] fn test_signed_leb128() { - let mut values = Vec::new(); - - let mut i = -500; - while i < 500 { - values.push(i * 123457i64); - i += 1; - } - + let values: Vec<_> = (-500..500).map(|i| i * 0x12345789ABCDEF).collect(); let mut stream = Vec::new(); - for &x in &values { let pos = stream.len(); let bytes_written = write_signed_leb128(&mut stream, pos, x); assert_eq!(stream.len(), pos + bytes_written); } - let mut pos = 0; for &x in &values { let (value, bytes_read) = read_signed_leb128(&mut stream, pos); diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 7cb02e2412c65..67cba3eb4e9de 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -45,6 +45,8 @@ Core encoding and decoding interfaces. extern crate rustc_unicode; extern crate collections; +extern crate rustc_i128; + pub use self::serialize::{Decoder, Encoder, Decodable, Encodable}; pub use self::serialize::{SpecializationError, SpecializedEncoder, SpecializedDecoder}; diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs index e97834f63cee4..17f1a112dbd0a 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -12,6 +12,8 @@ use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, writ use std::io::{self, Write}; use serialize; +use rustc_i128::{i128, u128}; + // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- @@ -32,7 +34,7 @@ impl<'a> Encoder<'a> { macro_rules! write_uleb128 { ($enc:expr, $value:expr) => {{ let pos = $enc.cursor.position() as usize; - let bytes_written = write_unsigned_leb128($enc.cursor.get_mut(), pos, $value as u64); + let bytes_written = write_unsigned_leb128($enc.cursor.get_mut(), pos, $value as u128); $enc.cursor.set_position((pos + bytes_written) as u64); Ok(()) }} @@ -41,7 +43,7 @@ macro_rules! write_uleb128 { macro_rules! write_sleb128 { ($enc:expr, $value:expr) => {{ let pos = $enc.cursor.position() as usize; - let bytes_written = write_signed_leb128($enc.cursor.get_mut(), pos, $value as i64); + let bytes_written = write_signed_leb128($enc.cursor.get_mut(), pos, $value as i128); $enc.cursor.set_position((pos + bytes_written) as u64); Ok(()) }} @@ -58,6 +60,10 @@ impl<'a> serialize::Encoder for Encoder<'a> { write_uleb128!(self, v) } + fn emit_u128(&mut self, v: u128) -> EncodeResult { + write_uleb128!(self, v) + } + fn emit_u64(&mut self, v: u64) -> EncodeResult { write_uleb128!(self, v) } @@ -79,6 +85,10 @@ impl<'a> serialize::Encoder for Encoder<'a> { write_sleb128!(self, v) } + fn emit_i128(&mut self, v: i128) -> EncodeResult { + write_sleb128!(self, v) + } + fn emit_i64(&mut self, v: i64) -> EncodeResult { write_sleb128!(self, v) } @@ -182,6 +192,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { Ok(()) } + fn read_u128(&mut self) -> Result { + read_uleb128!(self, u128) + } + fn read_u64(&mut self) -> Result { read_uleb128!(self, u64) } @@ -204,6 +218,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { read_uleb128!(self, usize) } + fn read_i128(&mut self) -> Result { + read_sleb128!(self, i128) + } + fn read_i64(&mut self) -> Result { read_sleb128!(self, i64) } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 6650a981884d8..3f2b8b13a6da9 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -19,6 +19,7 @@ use std::path; use std::rc::Rc; use std::cell::{Cell, RefCell}; use std::sync::Arc; +use rustc_i128::{i128, u128}; pub trait Encoder { type Error; @@ -26,11 +27,13 @@ pub trait Encoder { // Primitive types: fn emit_nil(&mut self) -> Result<(), Self::Error>; fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error>; + fn emit_u128(&mut self, v: u128) -> Result<(), Self::Error>; fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error>; fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error>; fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error>; fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error>; fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error>; + fn emit_i128(&mut self, v: i128) -> Result<(), Self::Error>; fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error>; fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error>; fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error>; @@ -143,11 +146,13 @@ pub trait Decoder { // Primitive types: fn read_nil(&mut self) -> Result<(), Self::Error>; fn read_usize(&mut self) -> Result; + fn read_u128(&mut self) -> Result; fn read_u64(&mut self) -> Result; fn read_u32(&mut self) -> Result; fn read_u16(&mut self) -> Result; fn read_u8(&mut self) -> Result; fn read_isize(&mut self) -> Result; + fn read_i128(&mut self) -> Result; fn read_i64(&mut self) -> Result; fn read_i32(&mut self) -> Result; fn read_i16(&mut self) -> Result; @@ -327,6 +332,20 @@ impl Decodable for u64 { } } +#[cfg(not(stage0))] +impl Encodable for u128 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u128(*self) + } +} + +#[cfg(not(stage0))] +impl Decodable for u128 { + fn decode(d: &mut D) -> Result { + d.read_u128() + } +} + impl Encodable for isize { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_isize(*self) @@ -387,6 +406,20 @@ impl Decodable for i64 { } } +#[cfg(not(stage0))] +impl Encodable for i128 { + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_i128(*self) + } +} + +#[cfg(not(stage0))] +impl Decodable for i128 { + fn decode(d: &mut D) -> Result { + d.read_i128() + } +} + impl Encodable for str { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_str(self) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 912045453e086..c7a7be577c3e2 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -282,6 +282,7 @@ #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] +#![feature(i128)] #![cfg_attr(test, feature(update_panic_count))] // Issue# 30592: Systematically use alloc_system during stage0 since jemalloc @@ -415,6 +416,9 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; +#[unstable(feature = "i128", issue = "35118")] +#[cfg(not(stage0))] +pub use core::i128; #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; @@ -426,6 +430,9 @@ pub use core::u16; pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::u64; +#[unstable(feature = "i128", issue = "35118")] +#[cfg(not(stage0))] +pub use core::u128; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 8b61e1b0d3a38..a2b269371a85a 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -14,3 +14,4 @@ log = { path = "../liblog" } rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index c18b36161dfcf..665980a24ce87 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -31,6 +31,8 @@ use std::u32; use serialize::{self, Encodable, Decodable, Encoder, Decoder}; +use rustc_i128::{u128, i128}; + /// A name is a part of an identifier, representing a string or gensym. It's /// the result of interning. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1147,7 +1149,7 @@ pub enum LitKind { /// A character literal (`'a'`) Char(char), /// An integer literal (`1`) - Int(u64, LitIntType), + Int(u128, LitIntType), /// A float literal (`1f64` or `1E10f64`) Float(InternedString, FloatTy), /// A float literal without a suffix (`1.0 or 1.0E10`) @@ -1256,6 +1258,7 @@ pub enum IntTy { I16, I32, I64, + I128, } impl fmt::Debug for IntTy { @@ -1277,24 +1280,16 @@ impl IntTy { IntTy::I8 => "i8", IntTy::I16 => "i16", IntTy::I32 => "i32", - IntTy::I64 => "i64" + IntTy::I64 => "i64", + IntTy::I128 => "i128", } } - pub fn val_to_string(&self, val: i64) -> String { - // cast to a u64 so we can correctly print INT64_MIN. All integral types - // are parsed as u64, so we wouldn't want to print an extra negative + pub fn val_to_string(&self, val: i128) -> String { + // cast to a u128 so we can correctly print INT128_MIN. All integral types + // are parsed as u128, so we wouldn't want to print an extra negative // sign. - format!("{}{}", val as u64, self.ty_to_string()) - } - - pub fn ty_max(&self) -> u64 { - match *self { - IntTy::I8 => 0x80, - IntTy::I16 => 0x8000, - IntTy::Is | IntTy::I32 => 0x80000000, // FIXME: actually ni about Is - IntTy::I64 => 0x8000000000000000 - } + format!("{}{}", val as u128, self.ty_to_string()) } pub fn bit_width(&self) -> Option { @@ -1304,6 +1299,7 @@ impl IntTy { IntTy::I16 => 16, IntTy::I32 => 32, IntTy::I64 => 64, + IntTy::I128 => 128, }) } } @@ -1315,6 +1311,7 @@ pub enum UintTy { U16, U32, U64, + U128, } impl UintTy { @@ -1324,23 +1321,15 @@ impl UintTy { UintTy::U8 => "u8", UintTy::U16 => "u16", UintTy::U32 => "u32", - UintTy::U64 => "u64" + UintTy::U64 => "u64", + UintTy::U128 => "u128", } } - pub fn val_to_string(&self, val: u64) -> String { + pub fn val_to_string(&self, val: u128) -> String { format!("{}{}", val, self.ty_to_string()) } - pub fn ty_max(&self) -> u64 { - match *self { - UintTy::U8 => 0xff, - UintTy::U16 => 0xffff, - UintTy::Us | UintTy::U32 => 0xffffffff, // FIXME: actually ni about Us - UintTy::U64 => 0xffffffffffffffff - } - } - pub fn bit_width(&self) -> Option { Some(match *self { UintTy::Us => return None, @@ -1348,6 +1337,7 @@ impl UintTy { UintTy::U16 => 16, UintTy::U32 => 32, UintTy::U64 => 64, + UintTy::U128 => 128, }) } } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index dc02c26039c15..87a72cc4bd462 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -930,6 +930,8 @@ fn int_type_of_word(s: &str) -> Option { "u32" => Some(UnsignedInt(ast::UintTy::U32)), "i64" => Some(SignedInt(ast::IntTy::I64)), "u64" => Some(UnsignedInt(ast::UintTy::U64)), + "i128" => Some(SignedInt(ast::IntTy::I128)), + "u128" => Some(UnsignedInt(ast::UintTy::U128)), "isize" => Some(SignedInt(ast::IntTy::Is)), "usize" => Some(UnsignedInt(ast::UintTy::Us)), _ => None @@ -976,7 +978,8 @@ impl IntType { SignedInt(ast::IntTy::I8) | UnsignedInt(ast::UintTy::U8) | SignedInt(ast::IntTy::I16) | UnsignedInt(ast::UintTy::U16) | SignedInt(ast::IntTy::I32) | UnsignedInt(ast::UintTy::U32) | - SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) => true, + SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) | + SignedInt(ast::IntTy::I128) | UnsignedInt(ast::UintTy::U128) => true, SignedInt(ast::IntTy::Is) | UnsignedInt(ast::UintTy::Us) => false } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index b81d95a6998c3..f8400a96c1459 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -16,6 +16,7 @@ use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use parse::token::{self, keywords, InternedString}; use ptr::P; +use rustc_i128::u128; // Transitional reexports so qquote can find the paths it is looking for mod syntax { @@ -721,23 +722,26 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr(sp, ast::ExprKind::Lit(P(respan(sp, lit)))) } fn expr_usize(&self, span: Span, i: usize) -> P { - self.expr_lit(span, ast::LitKind::Int(i as u64, ast::LitIntType::Unsigned(ast::UintTy::Us))) + self.expr_lit(span, ast::LitKind::Int(i as u128, + ast::LitIntType::Unsigned(ast::UintTy::Us))) } fn expr_isize(&self, sp: Span, i: isize) -> P { if i < 0 { - let i = (-i) as u64; + let i = (-i) as u128; let lit_ty = ast::LitIntType::Signed(ast::IntTy::Is); let lit = self.expr_lit(sp, ast::LitKind::Int(i, lit_ty)); self.expr_unary(sp, ast::UnOp::Neg, lit) } else { - self.expr_lit(sp, ast::LitKind::Int(i as u64, ast::LitIntType::Signed(ast::IntTy::Is))) + self.expr_lit(sp, ast::LitKind::Int(i as u128, + ast::LitIntType::Signed(ast::IntTy::Is))) } } fn expr_u32(&self, sp: Span, u: u32) -> P { - self.expr_lit(sp, ast::LitKind::Int(u as u64, ast::LitIntType::Unsigned(ast::UintTy::U32))) + self.expr_lit(sp, ast::LitKind::Int(u as u128, + ast::LitIntType::Unsigned(ast::UintTy::U32))) } fn expr_u8(&self, sp: Span, u: u8) -> P { - self.expr_lit(sp, ast::LitKind::Int(u as u64, ast::LitIntType::Unsigned(ast::UintTy::U8))) + self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U8))) } fn expr_bool(&self, sp: Span, value: bool) -> P { self.expr_lit(sp, ast::LitKind::Bool(value)) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index b70e270df54d2..7ff4c9e095183 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -19,6 +19,7 @@ use parse::token; use ptr::P; use tokenstream::{self, TokenTree}; + /// Quasiquoting works via token trees. /// /// This is registered as a set of expression syntax extension called quote! @@ -39,6 +40,7 @@ pub mod rt { pub use parse::new_parser_from_tts; pub use syntax_pos::{BytePos, Span, DUMMY_SP}; pub use codemap::{dummy_spanned}; + use rustc_i128::{u128}; pub trait ToTokens { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec; @@ -278,7 +280,7 @@ pub mod rt { } else { *self }; - let lit = ast::LitKind::Int(val as u64, ast::LitIntType::Signed($tag)); + let lit = ast::LitKind::Int(val as u128, ast::LitIntType::Signed($tag)); let lit = P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Lit(P(dummy_spanned(lit))), @@ -300,7 +302,7 @@ pub mod rt { (unsigned, $t:ty, $tag:expr) => ( impl ToTokens for $t { fn to_tokens(&self, cx: &ExtCtxt) -> Vec { - let lit = ast::LitKind::Int(*self as u64, ast::LitIntType::Unsigned($tag)); + let lit = ast::LitKind::Int(*self as u128, ast::LitIntType::Unsigned($tag)); dummy_spanned(lit).to_tokens(cx) } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b687e4f92be73..c471f6f38da54 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -303,6 +303,9 @@ declare_features! ( // Used to identify the `compiler_builtins` crate // rustc internal (active, compiler_builtins, "1.13.0", None), + + // The `i128` type + (active, i128_type, "1.14.0", Some(35118)), ); declare_features! ( @@ -1075,6 +1078,18 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { ast::ExprKind::InPlace(..) => { gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); } + ast::ExprKind::Lit(ref lit) => { + if let ast::LitKind::Int(_, ref ty) = lit.node { + match *ty { + ast::LitIntType::Signed(ast::IntTy::I128) | + ast::LitIntType::Unsigned(ast::UintTy::U128) => { + gate_feature_post!(&self, i128_type, e.span, + "128-bit integers are not stable"); + } + _ => {} + } + } + } _ => {} } visit::walk_expr(self, e); diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 118ceb17ab4a4..09946c4f2cad3 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -44,8 +44,9 @@ extern crate rustc_unicode; pub extern crate rustc_errors as errors; extern crate syntax_pos; -extern crate serialize as rustc_serialize; // used by deriving +extern crate rustc_i128; +extern crate serialize as rustc_serialize; // used by deriving // A variant of 'try!' that panics on an Err. This is used as a crutch on the // way towards a non-panic!-prone parser. It should be used for fatal parsing diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 1e286c143de9b..9cd8c85df46bf 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -27,6 +27,8 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::str; +use rustc_i128::u128; + pub type PResult<'a, T> = Result>; #[macro_use] @@ -608,18 +610,20 @@ pub fn integer_lit(s: &str, "i16" => ast::LitIntType::Signed(ast::IntTy::I16), "i32" => ast::LitIntType::Signed(ast::IntTy::I32), "i64" => ast::LitIntType::Signed(ast::IntTy::I64), + "i128" => ast::LitIntType::Signed(ast::IntTy::I128), "usize" => ast::LitIntType::Unsigned(ast::UintTy::Us), "u8" => ast::LitIntType::Unsigned(ast::UintTy::U8), "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16), "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32), "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64), + "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128), _ => { // i and u look like widths, so lets // give an error message along those lines if looks_like_width_suffix(&['i', 'u'], suf) { sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", &suf[1..])) - .help("valid widths are 8, 16, 32 and 64") + .help("valid widths are 8, 16, 32, 64 and 128") .emit(); } else { sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) @@ -636,7 +640,7 @@ pub fn integer_lit(s: &str, debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - match u64::from_str_radix(s, base) { + match u128::from_str_radix(s, base) { Ok(r) => ast::LitKind::Int(r, ty), Err(_) => { // small bases are lexed as if they were base 10, e.g, the string diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d5ed1d157e47a..e27dc1a64a016 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -64,6 +64,8 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::slice; +use rustc_i128::u128; + bitflags! { flags Restrictions: u8 { const RESTRICTION_STMT_EXPR = 1 << 0, @@ -2081,7 +2083,7 @@ impl<'a> Parser<'a> { pub fn mk_lit_u32(&mut self, i: u32, attrs: ThinVec) -> P { let span = &self.span; let lv_lit = P(codemap::Spanned { - node: LitKind::Int(i as u64, ast::LitIntType::Unsigned(UintTy::U32)), + node: LitKind::Int(i as u128, ast::LitIntType::Unsigned(UintTy::U32)), span: *span }); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 8563d27908db6..32750bb9b761e 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -29,6 +29,8 @@ use ptr::P; use std_inject; use tokenstream::{self, TokenTree}; +use rustc_i128::i128; + use std::ascii; use std::io::{self, Write, Read}; use std::iter; @@ -649,8 +651,7 @@ pub trait PrintState<'a> { ast::LitKind::Int(i, t) => { match t { ast::LitIntType::Signed(st) => { - word(self.writer(), - &st.val_to_string(i as i64)) + word(self.writer(), &st.val_to_string(i as i128)) } ast::LitIntType::Unsigned(ut) => { word(self.writer(), &ut.val_to_string(i)) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index e307925a6ed83..d0c898bcfeaa5 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -785,12 +785,14 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & attr::ReprInt(attr::SignedInt(ast::IntTy::I16)) => "i16", attr::ReprInt(attr::SignedInt(ast::IntTy::I32)) => "i32", attr::ReprInt(attr::SignedInt(ast::IntTy::I64)) => "i64", + attr::ReprInt(attr::SignedInt(ast::IntTy::I128)) => "i128", attr::ReprInt(attr::UnsignedInt(ast::UintTy::Us)) => "usize", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32", attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::U128)) => "u128", } } } diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 69e3eab22e912..0218be179ea9d 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -64,6 +64,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "rustc_llvm 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -107,6 +108,7 @@ dependencies = [ "rustc_back 0.0.0", "rustc_const_math 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -117,6 +119,7 @@ name = "rustc_const_math" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax 0.0.0", ] @@ -170,6 +173,10 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_i128" +version = "0.0.0" + [[package]] name = "rustc_incremental" version = "0.0.0" @@ -191,6 +198,7 @@ dependencies = [ "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", + "rustc_i128 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -222,6 +230,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "rustc_llvm 0.0.0", "rustc_macro 0.0.0", "serialize 0.0.0", @@ -242,6 +251,7 @@ dependencies = [ "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", + "rustc_i128 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -323,6 +333,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "rustc_incremental 0.0.0", "rustc_llvm 0.0.0", "rustc_platform_intrinsics 0.0.0", @@ -377,6 +388,7 @@ name = "serialize" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", ] [[package]] @@ -386,6 +398,7 @@ dependencies = [ "log 0.0.0", "rustc_bitflags 0.0.0", "rustc_errors 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 672ab117f15f3..50d259b272098 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1302,7 +1302,7 @@ static LLVMLinkage from_rust(LLVMRustLinkage linkage) { return LLVMCommonLinkage; default: llvm_unreachable("Invalid LLVMRustLinkage value!"); - } + } } extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { @@ -1312,3 +1312,20 @@ extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) { extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) { LLVMSetLinkage(V, from_rust(RustLinkage)); } + +// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of +// the common sizes (1, 8, 16, 32, 64, 128 bits) +extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low) +{ + auto C = unwrap(CV); + if (C->getBitWidth() > 128) { return false; } + APInt AP; + if (sext) { + AP = C->getValue().sextOrSelf(128); + } else { + AP = C->getValue().zextOrSelf(128); + } + *low = AP.getLoBits(64).getZExtValue(); + *high = AP.getHiBits(64).getZExtValue(); + return true; +} diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 8f7ec9de58af2..f3fb92e2b2206 100644 --- a/src/test/compile-fail/const-tup-index-span.rs +++ b/src/test/compile-fail/const-tup-index-span.rs @@ -10,7 +10,7 @@ // Test spans of errors -const TUP: (usize,) = 5 << 64; +const TUP: (usize,) = 5usize << 64; //~^ ERROR E0080 //~| attempt to shift left with overflow const ARR: [i32; TUP.0] = []; diff --git a/src/test/compile-fail/i128-feature-2.rs b/src/test/compile-fail/i128-feature-2.rs new file mode 100644 index 0000000000000..4a76d39921842 --- /dev/null +++ b/src/test/compile-fail/i128-feature-2.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +fn test1() -> i128 { //~ ERROR 128-bit type is unstable + 0 +} + +fn test1_2() -> u128 { //~ ERROR 128-bit type is unstable + 0 +} + +fn test3() { + let x: i128 = 0; //~ ERROR 128-bit type is unstable +} + +fn test3_2() { + let x: u128 = 0; //~ ERROR 128-bit type is unstable +} + +#[repr(u128)] +enum A { //~ ERROR 128-bit type is unstable + A(u64) +} diff --git a/src/test/compile-fail/oversized-literal.rs b/src/test/compile-fail/i128-feature.rs similarity index 66% rename from src/test/compile-fail/oversized-literal.rs rename to src/test/compile-fail/i128-feature.rs index 5416bcacf3d59..87dda469f9390 100644 --- a/src/test/compile-fail/oversized-literal.rs +++ b/src/test/compile-fail/i128-feature.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -7,7 +7,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +fn test2() { + 0i128; //~ ERROR 128-bit integers are not stable +} -fn main() { - println!("{}", 18446744073709551616u64); //~ error: int literal is too large +fn test2_2() { + 0u128; //~ ERROR 128-bit integers are not stable } + diff --git a/src/test/parse-fail/int-literal-too-large-span.rs b/src/test/parse-fail/int-literal-too-large-span.rs index c4b25d4357933..1af8df7d2f644 100644 --- a/src/test/parse-fail/int-literal-too-large-span.rs +++ b/src/test/parse-fail/int-literal-too-large-span.rs @@ -13,7 +13,7 @@ // issue #17123 fn main() { - 100000000000000000000000000000000 //~ ERROR int literal is too large - + 9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + //~^ ERROR int literal is too large ; // the span shouldn't point to this. } diff --git a/src/test/parse-fail/issue-5544-a.rs b/src/test/parse-fail/issue-5544-a.rs index f406b2cc803fc..cf1500e34d874 100644 --- a/src/test/parse-fail/issue-5544-a.rs +++ b/src/test/parse-fail/issue-5544-a.rs @@ -11,6 +11,6 @@ // compile-flags: -Z parse-only fn main() { - let __isize = 18446744073709551616; // 2^64 + let __isize = 340282366920938463463374607431768211456; // 2^128 //~^ ERROR int literal is too large } diff --git a/src/test/parse-fail/issue-5544-b.rs b/src/test/parse-fail/issue-5544-b.rs index 898b092064518..8c0b6741cb804 100644 --- a/src/test/parse-fail/issue-5544-b.rs +++ b/src/test/parse-fail/issue-5544-b.rs @@ -11,6 +11,6 @@ // compile-flags: -Z parse-only fn main() { - let __isize = 0xff_ffff_ffff_ffff_ffff; + let __isize = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ff; //~^ ERROR int literal is too large } diff --git a/src/test/parse-fail/lex-bad-numeric-literals.rs b/src/test/parse-fail/lex-bad-numeric-literals.rs index bb97b037a0028..d495a8edd09a4 100644 --- a/src/test/parse-fail/lex-bad-numeric-literals.rs +++ b/src/test/parse-fail/lex-bad-numeric-literals.rs @@ -23,8 +23,8 @@ fn main() { 0o; //~ ERROR: no valid digits 1e+; //~ ERROR: expected at least one digit in exponent 0x539.0; //~ ERROR: hexadecimal float literal is not supported - 99999999999999999999999999999999; //~ ERROR: int literal is too large - 99999999999999999999999999999999; //~ ERROR: int literal is too large + 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large + 9900000000000000000000000000999999999999999999999999999999; //~ ERROR: int literal is too large 0x; //~ ERROR: no valid digits 0xu32; //~ ERROR: no valid digits 0ou32; //~ ERROR: no valid digits diff --git a/src/test/run-pass/i128.rs b/src/test/run-pass/i128.rs new file mode 100644 index 0000000000000..2279a84ca5cc5 --- /dev/null +++ b/src/test/run-pass/i128.rs @@ -0,0 +1,52 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-stage0 +// ignore-stage1 +#![feature(i128_type)] + +fn main() { + let x: i128 = -1; + assert_eq!(0, !x); + let y: i128 = -2; + assert_eq!(!1, y); + let z: i128 = 0xABCD_EF; + assert_eq!(-z * -z * -z * -z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z + -z + -z + -z, -0x2AF3_7BC); + let k: i128 = -0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210; + assert_eq!(k + k, -0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420); + assert_eq!(0, k - k); + assert_eq!(-0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k + z); + assert_eq!(-0x1000_0000_0000_0000_0000_0000_0000_000, + k + 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!(-0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); + assert_eq!(-k, k / -1); + assert_eq!(-0x91A2_B3C4_D5E6_F8, k >> 65); + assert_eq!(-0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65); + assert!(k < z); + assert!(y > k); + assert!(y < x); + assert_eq!(x as i64, -1); + assert_eq!(z as i64, 0xABCD_EF); + assert_eq!(k as i64, -0xFEDC_BA98_7654_3210); + assert_eq!(k as u128, 0xFEDC_BA98_7654_3210_0123_4567_89AB_CDF0); + assert_eq!(-k as u128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + // formatting + let j: i128 = -(1 << 67); + assert_eq!("-147573952589676412928", format!("{}", j)); + assert_eq!("fffffffffffffff80000000000000000", format!("{:x}", j)); + assert_eq!("3777777777777777777760000000000000000000000", format!("{:o}", j)); + assert_eq!("1111111111111111111111111111111111111111111111111111111111111\ + 0000000000000000000000000000000000000000000000000000000000000000000", + format!("{:b}", j)); + assert_eq!("-147573952589676412928", format!("{:?}", j)); + // common traits + x.clone(); +} diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs new file mode 100644 index 0000000000000..9c87a5a8ee6fc --- /dev/null +++ b/src/test/run-pass/u128.rs @@ -0,0 +1,56 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-stage0 +// ignore-stage1 +#![feature(i128_type)] + +fn main() { + let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF; + assert_eq!(0, !x); + assert_eq!(0, !x); + let y: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFE; + assert_eq!(!1, y); + assert_eq!(x, y | 1); + assert_eq!(0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, + y & + 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF); + let z: u128 = 0xABCD_EF; + assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(z + z + z + z, 0x2AF3_7BC); + let k: u128 = 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210; + assert_eq!(k + k, 0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420); + assert_eq!(0, k - k); + assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z); + assert_eq!(0x1000_0000_0000_0000_0000_0000_0000_000, + k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); + assert_eq!(0, k % 42); + assert_eq!(15, z % 42); + assert_eq!(0x91A2_B3C4_D5E6_F7, k >> 65); + assert_eq!(0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65); + assert!(k > z); + assert!(y > k); + assert!(y < x); + assert_eq!(x as u64, !0); + assert_eq!(z as u64, 0xABCD_EF); + assert_eq!(k as u64, 0xFEDC_BA98_7654_3210); + assert_eq!(k as i128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210); + // formatting + let j: u128 = 1 << 67; + assert_eq!("147573952589676412928", format!("{}", j)); + assert_eq!("80000000000000000", format!("{:x}", j)); + assert_eq!("20000000000000000000000", format!("{:o}", j)); + assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", + format!("{:b}", j)); + assert_eq!("147573952589676412928", format!("{:?}", j)); + // common traits + x.clone(); +} diff --git a/src/tools/compiletest/Cargo.lock b/src/tools/compiletest/Cargo.lock index 755697806a00e..61dc07dc299ff 100644 --- a/src/tools/compiletest/Cargo.lock +++ b/src/tools/compiletest/Cargo.lock @@ -68,11 +68,16 @@ name = "regex-syntax" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc_i128" +version = "0.0.0" + [[package]] name = "serialize" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", ] [[package]]