diff --git a/mk/crates.mk b/mk/crates.mk index 79df941aeb3..9624a51dda0 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -54,7 +54,7 @@ TARGET_CRATES := libc std term \ compiler_builtins core alloc \ std_unicode rustc_bitflags \ alloc_system alloc_jemalloc \ - panic_abort panic_unwind unwind + panic_abort panic_unwind unwind rustc_i128 RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ @@ -92,23 +92,26 @@ 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 std_unicode rustc_errors syntax_pos rustc_data_structures +DEPS_syntax := std term serialize log arena libc rustc_bitflags std_unicode rustc_errors \ + syntax_pos rustc_data_structures rustc_i128 DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro +DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize DEPS_proc_macro_tokens := syntax syntax_pos log DEPS_proc_macro_plugin := syntax syntax_pos rustc_plugin log proc_macro_tokens -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 @@ -119,19 +122,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 proc_macro rustc_data_structures 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_proc_macro := std syntax DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \ - proc_macro syntax_ext + proc_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 @@ -159,6 +163,7 @@ ONLY_RLIB_alloc := 1 ONLY_RLIB_rand := 1 ONLY_RLIB_collections := 1 ONLY_RLIB_std_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/Cargo.lock b/src/Cargo.lock index 20ee2e1fcf3..3da29933c81 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -249,6 +249,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", @@ -308,6 +309,7 @@ dependencies = [ "rustc_const_math 0.0.0", "rustc_data_structures 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", @@ -318,6 +320,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", ] @@ -327,6 +330,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", ] @@ -372,6 +376,10 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_i128" +version = "0.0.0" + [[package]] name = "rustc_incremental" version = "0.0.0" @@ -380,6 +388,7 @@ dependencies = [ "log 0.0.0", "rustc 0.0.0", "rustc_data_structures 0.0.0", + "rustc_i128 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -393,6 +402,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", ] @@ -418,6 +428,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", @@ -437,6 +448,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", ] @@ -519,6 +531,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", @@ -574,6 +587,7 @@ name = "serialize" version = "0.0.0" dependencies = [ "log 0.0.0", + "rustc_i128 0.0.0", ] [[package]] @@ -619,6 +633,7 @@ dependencies = [ "rustc_bitflags 0.0.0", "rustc_data_structures 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/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 4a703b3da68..1bc9b660001 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -16,4 +16,787 @@ issue = "0")] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] -#![feature(staged_api)] +#![allow(unused_features)] +#![feature(staged_api, core_intrinsics, repr_simd, + i128_type, core_float, abi_unadjusted, associated_consts)] +#![allow(non_camel_case_types, unused_variables, unused_imports)] +#![cfg_attr(stage0, allow(dead_code))] + +#[cfg(any(target_pointer_width="32", target_pointer_width="16", target_os="windows", + target_arch="mips64"))] +pub mod reimpls { + + #![allow(unused_comparisons)] + + use core::intrinsics::unchecked_div; + use core::intrinsics::unchecked_rem; + use core::ptr; + + // 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; + + 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 >> 1; + if b & half_bits != 0 { + <$ty>::from_parts(0, a.low().wrapping_shl( + b.wrapping_sub(half_bits) as u32)) + } else if b == 0 { + a + } else { + <$ty>::from_parts(a.low().wrapping_shl(b as u32), + a.high().wrapping_shl(b as u32) + | a.low() + .wrapping_shr(half_bits.wrapping_sub(b) as u32)) + } + }} + } + + #[export_name="__ashlti3"] + pub extern "C" 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 >> 1; + if b & half_bits != 0 { + <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32) + as <$ty as LargeInt>::LowHalf, + a.high().wrapping_shr(half_bits.wrapping_sub(1) as u32)) + } else if b == 0 { + a + } else { + let high_unsigned = a.high() as <$ty as LargeInt>::LowHalf; + <$ty>::from_parts(high_unsigned.wrapping_shl(half_bits.wrapping_sub(b) as u32) + | a.low().wrapping_shr(b as u32), + a.high().wrapping_shr(b as u32)) + } + }} + } + + #[export_name="__ashrti3"] + pub extern "C" 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 >> 1; + if b & half_bits != 0 { + <$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0) + } else if b == 0 { + a + } else { + <$ty>::from_parts(a.high().wrapping_shl(half_bits.wrapping_sub(b) as u32) + | a.low().wrapping_shr(b as u32), + a.high().wrapping_shr(b as u32)) + } + }} + } + + + #[export_name="__lshrti3"] + pub extern "C" fn lshr(a: u128_, b: u128_) -> u128_ { + lshr!(a, b, u128_) + } + + #[cfg(stage0)] + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + unsafe { + if !rem.is_null() { + *rem = unchecked_rem(n, d); + } + unchecked_div(n, d) + } + } + + #[cfg(not(stage0))] + pub extern "C" fn u128_div_mod(n: u128_, d: u128_, rem: *mut u128_) -> u128_ { + // Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide + unsafe { + // special cases, X is unknown, K != 0 + if n.high() == 0 { + if d.high() == 0 { + // 0 X + // --- + // 0 X + if !rem.is_null() { + *rem = u128::from(unchecked_rem(n.low(), d.low())); + } + return u128::from(unchecked_div(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 + if !rem.is_null() { + *rem = u128::from(unchecked_rem(n.high(), d.low())); + } + return u128::from(unchecked_div(n.high(), d.low())); + } + + if n.low() == 0 { + // K 0 + // --- + // K 0 + if !rem.is_null() { + *rem = u128::from_parts(0, unchecked_rem(n.high(), d.high())); + } + return u128::from(unchecked_div(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().wrapping_sub(1))); + } + return u128::from(n.high().wrapping_shr(d.high().trailing_zeros())); + } + + // K K + // --- + // K 0 + 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 = sr.wrapping_add(1); + + // 1 <= sr <= u64::bits() - 1 + q = n.wrapping_shl(64u32.wrapping_sub(sr)); + r = n.wrapping_shr(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().wrapping_sub(1))); + } + + if d.low() == 1 { + return n; + } else { + let sr = d.low().trailing_zeros(); + return n.wrapping_shr(sr); + }; + } + + sr = (1 + 64u32) + .wrapping_add(d.low().leading_zeros()) + .wrapping_sub(n.high().leading_zeros()); + + // 2 <= sr <= u64::bits() - 1 + q = n.wrapping_shl(128u32.wrapping_sub(sr)); + r = n.wrapping_shr(sr); + // FIXME the C compiler-rt implementation has something here + // that looks like a speed optimisation. + // It would be worth a try to port it to Rust too and + // compare the speed. + } 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 = sr.wrapping_add(1); + + // 1 <= sr <= u32::bits() + q = n.wrapping_shl(128u32.wrapping_sub(sr)); + r = n.wrapping_shr(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; + + // FIXME: replace this with a for loop + // (atm not doable as this generates call to + // eh_personality when optimisations are turned off, + // which in turn gives a linker error in later + // compilation steps) + while sr > 0 { + // r:q = ((r:q) << 1) | carry + r = r.wrapping_shl(1) | q.wrapping_shr(128 - 1); + q = q.wrapping_shl(1) | carry as u128; + + // carry = 0 + // if r >= d { + // r -= d; + // carry = 1; + // } + let s = ((d.wrapping_sub(r).wrapping_sub(1)) as i128).wrapping_shr(128 - 1); + carry = (s & 1) as u64; + r = r.wrapping_sub(d & s as u128); + sr = sr.wrapping_sub(1); + } + + if !rem.is_null() { + *rem = r; + } + (q.wrapping_shl(1)) | carry as u128 + } + } + + fn i128_mod(a: i128_, b: i128_) -> i128_ { + let b = b.uabs(); + let sa = a.signum(); + let a = a.uabs(); + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a, b, &mut r); + if sa == -1 { (r as i128_).unchecked_neg() } else { r as i128_ } + } + } + + fn i128_div(a: i128_, b: i128_) -> i128_ { + let sa = a.signum(); + let sb = b.signum(); + let a = a.uabs(); + let b = b.uabs(); + let sr = sa.wrapping_mul(sb); // sign of quotient + (if sr == -1 { + (u128_div_mod(a, b, ptr::null_mut()) as i128_).unchecked_neg() + } else { + u128_div_mod(a, b, ptr::null_mut()) as i128_ + }) + } + + #[cfg(stage0)] + #[export_name="__udivti3"] + pub extern "C" fn u128_div(a: u128_, b: u128_) -> u128_ { + (a / b) + } + + 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 sa = a.signum(); + let abs_a = a.iabs(); + let sb = b.signum(); + let abs_b = b.iabs(); + if abs_a < 2 || abs_b < 2 { + return result; + } + if sa == sb { + if abs_a > unchecked_div(<$ty>::max_value(), abs_b) { + *overflow = 1; + } + } else { + if abs_a > unchecked_div(<$ty>::min_value(), abs_b.unchecked_neg()) { + *overflow = 1; + } + } + result + }} + } + + 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.wrapping_shr(32)) as u32 + } + fn from_parts(low: u32, high: u32) -> u64 { + low as u64 | (high as u64).wrapping_shl(32) + } + } + impl LargeInt for i64 { + type LowHalf = u32; + type HighHalf = i32; + + fn low(self) -> u32 { + self as u32 + } + fn high(self) -> i32 { + self.wrapping_shr(32) as i32 + } + fn from_parts(low: u32, high: i32) -> i64 { + low as i64 | (high as i64).wrapping_shl(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).offset(1) } + } + 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).offset(1) } + } + 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, $tyh: ty) => {{ + let (a, b) = ($a, $b); + let half_bits = ((::core::mem::size_of::<$tyh>() * 8) / 2) as u32; + let lower_mask = (!0u64).wrapping_shr(half_bits); + let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask); + let mut t = low.wrapping_shr(half_bits); + low &= lower_mask; + t = t.wrapping_add(a.low().wrapping_shr(half_bits) + .wrapping_mul(b.low() & lower_mask)); + low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits)); + let mut high = t.wrapping_shr(half_bits) as $tyh; + t = low.wrapping_shr(half_bits); + low &= lower_mask; + t = t.wrapping_add(b.low().wrapping_shr(half_bits) + .wrapping_mul(a.low() & lower_mask)); + low = low.wrapping_add((t & lower_mask).wrapping_shl(half_bits)); + high = high.wrapping_add(t.wrapping_shr(half_bits) as $tyh); + high = high.wrapping_add(a.low().wrapping_shr(half_bits) + .wrapping_mul(b.low().wrapping_shr(half_bits)) as $tyh); + high = high + .wrapping_add(a.high() + .wrapping_mul(b.low() as $tyh)) + .wrapping_add((a.low() as $tyh) + .wrapping_mul(b.high())); + <$ty>::from_parts(low, high) + }} + } + + #[cfg(stage0)] + #[export_name="__multi3"] + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { + ((a as i64).wrapping_mul(b as i64) as i128_) + } + + #[cfg(not(stage0))] + #[export_name="__multi3"] + pub extern "C" fn u128_mul(a: i128_, b: i128_) -> i128_ { + mul!(a, b, i128_, i64) + } + + trait AbsExt: Sized { + fn uabs(self) -> u128_ { + self.iabs() as u128_ + } + fn iabs(self) -> i128_; + } + + #[cfg(stage0)] + impl AbsExt for i128_ { + fn iabs(self) -> i128_ { + let s = self >> 63; + ((self ^ s).wrapping_sub(s)) + } + } + + #[cfg(not(stage0))] + impl AbsExt for i128_ { + fn iabs(self) -> i128_ { + let s = self >> 127; + ((self ^ s).wrapping_sub(s)) + } + } + + trait NegExt: Sized { + fn unchecked_neg(self) -> i128_; + } + + impl NegExt for i128_ { + fn unchecked_neg(self) -> i128_ { + (!self).wrapping_add(1) + } + } + + trait FloatStuff: Sized { + type ToBytes; + + const MANTISSA_BITS: u32; + const MAX_EXP: i32; + const EXP_MASK: Self::ToBytes; + const MANTISSA_MASK: Self::ToBytes; + const MANTISSA_LEAD_BIT: 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 EXP_MASK: u32 = 0x7F80_0000; + const MANTISSA_MASK: u32 = 0x007F_FFFF; + const MANTISSA_LEAD_BIT: u32 = 0x0080_0000; + + fn to_bytes(self) -> u32 { unsafe { ::core::mem::transmute(self) } } + fn get_exponent(self) -> i32 { + ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32) + .wrapping_sub(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; + const MANTISSA_LEAD_BIT: u64 = 0x0010_0000_0000_0000; + + fn to_bytes(self) -> u64 { unsafe { ::core::mem::transmute(self) } } + fn get_exponent(self) -> i32 { + ((self.to_bytes() & Self::EXP_MASK).wrapping_shr(Self::MANTISSA_BITS) as i32) + .wrapping_sub(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_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; + if sign == -1.0 || exponent < 0 { return 0 as u128_; } + if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + return !(0 as u128_); + } + (if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { + (mantissa as $outty) + .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32) + .wrapping_sub(exponent) as u32) + } else { + (mantissa as $outty) + .wrapping_shl(exponent.wrapping_sub( + <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) + }) + } } + } + + 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_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK; + let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT; + + if exponent < 0 { return 0 as i128_; } + if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 { + let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() }; + return ret + } + let r = if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 { + (mantissa as $outty) + .wrapping_shr((<$fromty as FloatStuff>::MANTISSA_BITS as i32) + .wrapping_sub(exponent) as u32) + } else { + (mantissa as $outty) + .wrapping_shl(exponent.wrapping_sub( + <$fromty as FloatStuff>::MANTISSA_BITS as i32) as u32) + }; + (if sign >= 0.0 { r } else { r.unchecked_neg() }) + }} + } + + + fn i128_as_f64(a: i128_) -> f64 { + match a.signum() { + 1 => u128_as_f64(a.uabs()), + 0 => 0.0, + _ => -u128_as_f64(a.uabs()), + } + } + + fn i128_as_f32(a: i128_) -> f32 { + match a.signum() { + 1 => u128_as_f32(a.uabs()), + 0 => 0.0, + _ => -u128_as_f32(a.uabs()), + } + } + + fn u128_as_f64(mut a: u128_) -> f64 { + use ::core::f64::MANTISSA_DIGITS; + if a == 0 { return 0.0; } + let sd = 128u32.wrapping_sub(a.leading_zeros()); + let mut e = sd.wrapping_sub(1); + const MD1 : u32 = MANTISSA_DIGITS + 1; + const MD2 : u32 = MANTISSA_DIGITS + 2; + + // SNAP: replace this with !0u128 + let negn :u128_ = !0; + + if sd > MANTISSA_DIGITS { + a = match sd { + MD1 => a.wrapping_shl(1), + MD2 => a, + _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) | + (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2) + .wrapping_sub(sd as u128_))) == 0 { 0 } else { 1 }) + }; + a |= if (a & 4) == 0 { 0 } else { 1 }; + a = a.wrapping_add(1); + a = a.wrapping_shr(2); + if a & (1 << MANTISSA_DIGITS) != 0 { + a = a.wrapping_shr(1); + e = e.wrapping_add(1); + } + } else { + a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd)); + } + unsafe { + ::core::mem::transmute((e as u64).wrapping_add(1023).wrapping_shl(52) + | (a as u64 & 0x000f_ffff_ffff_ffff)) + } + } + + fn u128_as_f32(mut a: u128_) -> f32 { + use ::core::f32::MANTISSA_DIGITS; + if a == 0 { return 0.0; } + let sd = 128u32.wrapping_sub(a.leading_zeros()); + let mut e = sd.wrapping_sub(1); + const MD1 : u32 = MANTISSA_DIGITS + 1; + const MD2 : u32 = MANTISSA_DIGITS + 2; + + // SNAP: replace this with !0u128 + let negn :u128_ = !0; + + if sd > MANTISSA_DIGITS { + a = match sd { + MD1 => a.wrapping_shl(1), + MD2 => a, + _ => a.wrapping_shr(sd.wrapping_sub(MANTISSA_DIGITS + 2)) | + (if (a & (negn.wrapping_shr(128 + MANTISSA_DIGITS + 2) + .wrapping_sub(sd as u128_))) == 0 { 0 } else { 1 }) + }; + a |= if (a & 4) == 0 { 0 } else { 1 }; + a = a.wrapping_add(1); + a = a.wrapping_shr(2); + if a & (1 << MANTISSA_DIGITS) != 0 { + a = a.wrapping_shr(1); + e = e.wrapping_add(1); + } + } else { + a = a.wrapping_shl(MANTISSA_DIGITS.wrapping_sub(sd)); + } + unsafe { + ::core::mem::transmute((e as u32).wrapping_add(127).wrapping_shl(23) + | (a as u32 & 0x007f_ffff)) + } + } + + + macro_rules! why_are_abi_strings_checked_by_parser { ($cret:ty, $conv:expr, $unadj:tt) => { + mod imp { + use super::{i128_, u128_, LargeInt, FloatStuff, NegExt, AbsExt}; + use super::{i128_as_f64, i128_as_f32, u128_as_f64, u128_as_f32, + i128_div, i128_mod, u128_div_mod, unchecked_div, ptr}; + // For x64 + // rdx:rcx, r9:r8, stack -> rdx:rax + // aka. + // define i128 @__muloti4(i128, i128, i32*) + #[export_name="__muloti4"] + pub unsafe extern $unadj fn i128_mul_oflow(a: i128_, b: i128_, o: *mut i32) -> i128_ { + mulo!(a, b, o, i128_) + } + + // For x64 + // rdx:rax -> xmm0 + // aka. + // define double @__muloti4(i128) + #[export_name="__floattidf"] + pub extern $unadj fn i128_as_f64_(a: i128_) -> f64 { + i128_as_f64(a) + } + #[export_name="__floattisf"] + pub extern $unadj fn i128_as_f32_(a: i128_) -> f32 { + i128_as_f32(a) + } + #[export_name="__floatuntidf"] + pub extern $unadj fn u128_as_f64_(a: u128_) -> f64 { + u128_as_f64(a) + } + #[export_name="__floatuntisf"] + pub extern $unadj fn u128_as_f32_(a: u128_) -> f32 { + u128_as_f32(a) + } + + // For x64 + // xmm0 -> rdx:rax + // aka. + // define i128 @stuff(double) + #[export_name="__fixunsdfti"] + pub extern $unadj fn f64_as_u128(a: f64) -> u128_ { + float_as_unsigned!(a, f64, u128_) + } + + #[export_name="__fixunssfti"] + pub extern "unadjusted" fn f32_as_u128(a: f32) -> u128_ { + float_as_unsigned!(a, f32, u128_) + } + + #[export_name="__fixdfti"] + pub extern "unadjusted" fn f64_as_i128(a: f64) -> i128_ { + float_as_signed!(a, f64, i128_) + } + + #[export_name="__fixsfti"] + pub extern "unadjusted" fn f32_as_i128(a: f32) -> i128_ { + float_as_signed!(a, f32, i128_) + } + + #[repr(simd)] + pub struct u64x2(u64, u64); + + // For x64 + // pointers -> xmm0 + // aka. + // define <2 x u64> @stuff(i128*, i128*, i128*) + // + // That almost matches the C ABI, so we simply use the C ABI + #[export_name="__udivmodti4"] + pub extern "C" fn u128_div_mod_(n: u128_, d: u128_, rem: *mut u128_) -> $cret { + let x = u128_div_mod(n, d, rem); + ($conv)(x) + } + + #[export_name="__udivti3"] + pub extern "C" fn u128_div_(a: u128_, b: u128_) -> $cret { + let x = u128_div_mod(a, b, ptr::null_mut()); + ($conv)(x) + } + + #[export_name="__umodti3"] + pub extern "C" fn u128_mod_(a: u128_, b: u128_) -> $cret { + unsafe { + let mut r = ::core::mem::zeroed(); + u128_div_mod(a, b, &mut r); + ($conv)(r) + } + } + + #[export_name="__divti3"] + pub extern "C" fn i128_div_(a: i128_, b: i128_) -> $cret { + let x = i128_div(a, b); + ($conv)(x as u128_) + } + + #[export_name="__modti3"] + pub extern "C" fn i128_mod_(a: i128_, b: i128_) -> $cret { + let x = i128_mod(a, b); + ($conv)(x as u128_) + } + } + } } + + // LLVM expectations for ABI on windows x64 are pure madness. + #[cfg(not(stage0))] + #[cfg(all(windows, target_pointer_width="64"))] + why_are_abi_strings_checked_by_parser!(u64x2, + |i: u128_| u64x2(i.low(), i.high()), + "unadjusted"); + + #[cfg(not(stage0))] + #[cfg(not(all(windows, target_pointer_width="64")))] + why_are_abi_strings_checked_by_parser!(u128_, |i|{ i }, "C"); + + #[cfg(not(stage0))] + pub use self::imp::*; +} diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index d72b18ae345..cd2e8f10181 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -153,12 +153,16 @@ fn clone(&self) -> $t { *self } 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 54fb70278ca..a78d27ea3af 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -681,6 +681,8 @@ fn ne(&self, _other: &()) -> bool { false } 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)*) => ($( @@ -690,6 +692,8 @@ impl Eq for $t {} } 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)*) => ($( @@ -779,6 +783,8 @@ fn cmp(&self, other: &bool) -> Ordering { } ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 } + #[cfg(not(stage0))] + ord_impl! { u128 i128 } #[unstable(feature = "never_type_impls", issue = "35121")] impl PartialEq for ! { diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 85e4b2a0067..ccd4343336f 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -144,12 +144,16 @@ fn default() -> $t { $v } 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 0145897d8f6..cd725392b66 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 @@ fn to_u8(&self) -> u8 { *self as u8 } 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 @@ fn prefix(&self) -> &'static str { /// 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 @@ macro_rules! integer { 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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // 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; 39] = 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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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 18b465d85a1..92657a6d0b1 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -186,6 +186,13 @@ fn write_u32(&mut self, i: u32) { fn write_u64(&mut self, i: u64) { self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) }) } + #[cfg(not(stage0))] + /// Writes 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) }) + } /// Writes a single `usize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -220,6 +227,13 @@ fn write_i32(&mut self, i: i32) { fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) } + #[cfg(not(stage0))] + /// Writes 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) + } /// Writes a single `isize` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] @@ -362,6 +376,11 @@ fn hash_slice(data: &[$ty], state: &mut H) { (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 e6f21d6c17a..9d22037882f 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -242,6 +242,8 @@ fn steps_between_by_one(start: &Self, end: &Self) -> Option { // 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 9834fca5fdc..2cb2f81fcff 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -90,6 +90,7 @@ #![feature(staged_api)] #![feature(unboxed_closures)] #![feature(never_type)] +#![cfg_attr(not(stage0), feature(i128_type))] #![feature(prelude_import)] #[prelude_import] @@ -120,12 +121,20 @@ #[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 47afaf77353..539ad00bd30 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 00000000000..6268271a1dc --- /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 1dd820980f4..0f3a5baa2dd 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 8a2168933dc..ea8b3a9145c 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 2ce9eb11936..aa21b1190ae 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 8b5a7f1910e..1bed4861594 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 e74c30d5e5a..630fac9d92f 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 86bcef4011d..e0917f79c43 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 a4529909e83..61c687313dc 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -145,6 +145,8 @@ fn one() -> Self { 1 } )*) } 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)*) => ($( @@ -191,7 +193,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. @@ -1298,6 +1300,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 { @@ -2330,6 +2342,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 { @@ -2543,6 +2569,8 @@ fn from_str(src: &str) -> Result { )*} } 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")] @@ -2567,7 +2595,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { } } -macro_rules! same_sign_from_int_impl { +macro_rules! same_sign_try_from_int_impl { ($storage:ty, $target:ty, $($source:ty),*) => {$( #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { @@ -2586,16 +2614,51 @@ fn try_from(u: $source) -> Result<$target, TryFromIntError> { )*} } -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(stage0)] +same_sign_try_from_int_impl!(u64, u8, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i8, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, u16, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i16, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, u32, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i32, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, u64, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(i64, i64, i8, i16, i32, i64, isize); +#[cfg(stage0)] +same_sign_try_from_int_impl!(u64, usize, u8, u16, u32, u64, usize); +#[cfg(stage0)] +same_sign_try_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),*) => {$( @@ -2629,12 +2692,30 @@ fn try_from(u: $signed) -> Result<$unsigned, TryFromIntError> { )*} } +#[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; @@ -2662,6 +2743,8 @@ fn checked_add(&self, other: u32) -> Option { })*) } 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 { use self::IntErrorKind::*; @@ -2795,27 +2878,51 @@ fn from(small: $Small) -> $Large { 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 00000000000..77291f68725 --- /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 d34d87caa55..9c318216f1f 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 f9c9099e47f..84367c20738 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 8dfe4335a3d..cc48a28b22f 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 0106ee8e401..6c0daa7763a 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 cc9256ab6bf..a3a2dc73e9c 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 685c52e271e..0b6f1c73c58 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 50d64838a5c..b3c2c25551e 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -298,6 +298,8 @@ fn neg(self) -> Self { } 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 07ae5b920b2..40d941a8b27 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -268,6 +268,8 @@ fn add(self, other: $t) -> $t { self + other } } 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 `-`. /// @@ -341,6 +343,8 @@ fn sub(self, other: $t) -> $t { self - other } } 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 `*`. /// @@ -463,6 +467,8 @@ fn mul(self, other: $t) -> $t { self * other } } 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 `/`. /// @@ -592,6 +598,8 @@ fn div(self, other: $t) -> $t { self / other } } 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)*) => ($( @@ -671,6 +679,9 @@ fn rem(self, other: $t) -> $t { self % other } } 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)*) => ($( @@ -766,6 +777,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 `!`. /// @@ -824,6 +837,8 @@ fn not(self) -> $t { !self } } 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 `&`. /// @@ -907,6 +922,8 @@ fn bitand(self, rhs: $t) -> $t { self & rhs } } 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 `|`. /// @@ -990,6 +1007,8 @@ fn bitor(self, rhs: $t) -> $t { self | rhs } } 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 `^`. /// @@ -1076,6 +1095,8 @@ fn bitxor(self, other: $t) -> $t { self ^ other } } 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 `<<`. /// @@ -1166,17 +1187,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 `>>`. /// @@ -1267,17 +1294,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 `+=`. /// @@ -1334,6 +1367,8 @@ fn add_assign(&mut self, other: $t) { *self += other } } 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 `-=`. /// @@ -1390,6 +1425,8 @@ fn sub_assign(&mut self, other: $t) { *self -= other } } 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 `*=`. /// @@ -1435,6 +1472,8 @@ fn mul_assign(&mut self, other: $t) { *self *= other } } 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 `/=`. /// @@ -1479,6 +1518,8 @@ fn div_assign(&mut self, other: $t) { *self /= other } } 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 `%=`. /// @@ -1523,6 +1564,8 @@ fn rem_assign(&mut self, other: $t) { *self %= other } } 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 `&=`. /// @@ -1609,6 +1652,8 @@ fn bitand_assign(&mut self, other: $t) { *self &= other } } 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 `|=`. /// @@ -1653,6 +1698,8 @@ fn bitor_assign(&mut self, other: $t) { *self |= other } } 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 `^=`. /// @@ -1697,6 +1744,8 @@ fn bitxor_assign(&mut self, other: $t) { *self ^= other } } 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 `<<=`. /// @@ -1749,17 +1798,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 `>>=`. /// @@ -1812,17 +1867,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 `container[index]` when used in an immutable context. diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 578ef68b003..51494885e73 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 efe855f0a39..73ec9d8f8c8 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -62,6 +62,9 @@ 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 4cae5b370eb..cd7859af8ee 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -260,11 +260,13 @@ pub fn collect_language_items(session: &Session, 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 cb1fc15c5f6..380c5b0eb6f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -194,11 +194,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>, @@ -359,11 +361,13 @@ fn new(interners: &CtxtInterners<'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)), } @@ -1304,6 +1308,7 @@ pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'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, } } @@ -1314,6 +1319,7 @@ pub fn mk_mach_uint(self, tm: ast::UintTy) -> Ty<'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 ebac30c8e50..ff95554dbbf 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -20,6 +20,8 @@ use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; +use rustc_i128::u128; +use rustc_const_math::ConstInt; use std::cmp; use std::fmt; @@ -35,6 +37,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, @@ -55,6 +58,7 @@ fn default() -> 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), @@ -99,6 +103,7 @@ pub fn parse(sess: &Session) -> 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, @@ -111,19 +116,28 @@ pub fn parse(sess: &Session) -> 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"); @@ -325,7 +339,8 @@ pub enum Integer { I8, I16, I32, - I64 + I64, + I128, } impl Integer { @@ -336,6 +351,7 @@ pub fn size(&self) -> Size { I16 => Size::from_bytes(2), I32 => Size::from_bytes(4), I64 => Size::from_bytes(8), + I128 => Size::from_bytes(16), } } @@ -346,6 +362,7 @@ pub fn align(&self, dl: &TargetDataLayout)-> Align { I16 => dl.i16_align, I32 => dl.i32_align, I64 => dl.i64_align, + I128 => dl.i128_align, } } @@ -357,33 +374,37 @@ pub fn to_ty<'a, 'tcx>(&self, tcx: &ty::TyCtxt<'a, 'tcx, 'tcx>, (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, } } @@ -406,6 +427,7 @@ pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> 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() } @@ -486,6 +508,7 @@ pub fn size(self, dl: &TargetDataLayout) -> Size { 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 } } @@ -497,6 +520,7 @@ pub fn align(self, dl: &TargetDataLayout) -> Align { 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 @@ -1175,19 +1199,30 @@ pub fn compute_uncached(ty: Ty<'gcx>, if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { // All bodies empty -> intlike - let (mut min, mut max, mut non_zero) = (i64::MAX, i64::MIN, true); + let (mut min, mut max, mut non_zero) = (i64::max_value(), + i64::min_value(), + true); for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; + let x = match v.disr_val.erase_type() { + ConstInt::InferSigned(i) => i as i64, + ConstInt::Infer(i) => i as u64 as i64, + _ => bug!() + }; if x == 0 { non_zero = false; } if x < min { min = x; } if x > max { max = x; } } - let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], min, max); + // FIXME: should handle i128? signed-value based impl is weird and hard to + // grok. + let (discr, signed) = Integer::repr_discr(tcx, ty, &hints[..], + min, + max); return success(CEnum { discr: discr, signed: signed, non_zero: non_zero, + // FIXME: should be u128? min: min as u64, max: max as u64 }); @@ -1232,7 +1267,7 @@ pub fn compute_uncached(ty: Ty<'gcx>, // 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 b4ac6b9d250..0b45ff94a93 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -51,11 +51,13 @@ fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { 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, } } @@ -66,6 +68,7 @@ fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { 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)), @@ -76,6 +79,7 @@ fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr { 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)), @@ -91,11 +95,13 @@ fn assert_ty_matches(&self, val: Disr) { (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 0e5cbce8639..7148e181bbd 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -19,4 +19,5 @@ rustc_data_structures = { path = "../librustc_data_structures" } 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 e8e7a2eb7ed..c736b4865e7 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -43,6 +43,8 @@ use rustc_const_math::*; use rustc_errors::DiagnosticBuilder; +use rustc_i128::{i128, u128}; + macro_rules! math { ($e:expr, $op:expr) => { match $op { @@ -588,38 +590,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!(), } @@ -973,26 +980,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))) }, @@ -1000,7 +1011,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))) }, @@ -1071,21 +1083,23 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( } 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)))) }, @@ -1115,13 +1129,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) { @@ -1145,9 +1159,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(_) => { @@ -1185,28 +1199,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(n, fty) => { diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 7a6cc493723..67b4efdbd1f 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -28,6 +28,7 @@ #![feature(slice_patterns)] #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(const_fn)] extern crate arena; #[macro_use] extern crate syntax; @@ -41,6 +42,8 @@ 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 10aadabe22e..3d7a4865e45 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 e2e30ef026c..1e9c2badd68 100644 --- a/src/librustc_const_math/err.rs +++ b/src/librustc_const_math/err.rs @@ -74,11 +74,13 @@ pub fn description(&self) -> &'static str { 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 28a58878472..59eb4b70aa8 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; + )* } } -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 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 + } +} + +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 @@ pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> { (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 @@ pub fn erase_type(self) -> Self { match self { Infer(i) => Infer(i), InferSigned(i) if i < 0 => InferSigned(i), - I8(i) if i < 0 => InferSigned(i as i64), - I16(i) if i < 0 => InferSigned(i as i64), - I32(i) if i < 0 => InferSigned(i as i64), - I64(i) if i < 0 => InferSigned(i as i64), - Isize(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 @@ pub fn description(&self) -> &'static str { 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 @@ pub fn is_negative(&self) -> bool { 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 @@ pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> { (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 @@ pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> { (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 @@ macro_rules! add1 { 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 @@ macro_rules! add1 { 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 @@ pub fn int_type(self) -> Option { 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 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> 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 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> 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 @@ fn $func(self, rhs: Self) -> Result { (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 @@ fn $func(self, rhs: Self) -> Result { (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 @@ fn $func(self, rhs: Self) -> Result { (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 @@ fn $func(self, rhs: Self) -> Result { (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 @@ fn $func(self, rhs: Self) -> Result { 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 @@ fn div(self, rhs: Self) -> Result { (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 @@ fn div(self, rhs: Self) -> Result { (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 @@ fn rem(self, rhs: Self) -> Result { (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 @@ fn rem(self, rhs: Self) -> Result { (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 @@ fn shl(self, rhs: Self) -> Result { 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 @@ fn shl(self, rhs: Self) -> Result { 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 @@ fn shr(self, rhs: Self) -> Result { 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 @@ fn shr(self, rhs: Self) -> Result { 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 @@ fn neg(self) -> Result { 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 @@ fn not(self) -> Result { 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 @@ fn not(self) -> Result { 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 ef92b628523..19ae0c91fc5 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 @@ pub fn new(i: i64, target_int_ty: ast::IntTy) -> Result { _ => 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 f667ff23b27..597344a2c82 100644 --- a/src/librustc_const_math/lib.rs +++ b/src/librustc_const_math/lib.rs @@ -25,10 +25,14 @@ #![feature(rustc_private)] #![feature(staged_api)] +#![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 bf73ff03c98..9ebf5cab6bb 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 @@ pub fn new(i: u64, target_uint_ty: ast::UintTy) -> Result { _ => 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_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d98..bb610374810 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["dylib"] [dependencies] log = { path = "../liblog" } serialize = { path = "../libserialize" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 86f244d65dd..d3ec674daed 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -44,6 +44,8 @@ #[cfg(unix)] extern crate libc; +extern crate rustc_i128; + pub use rustc_serialize::hex::ToHex; pub mod array_vec; diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index ed97c3dde5e..87048eff5b7 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -13,13 +13,14 @@ use std::mem; use blake2b::Blake2bHasher; use rustc_serialize::leb128; +use rustc_i128::{u128,i128}; fn write_unsigned_leb128_to_buf(buf: &mut [u8; 16], value: u64) -> usize { - leb128::write_unsigned_leb128_to(value, |i, v| buf[i] = v) + leb128::write_unsigned_leb128_to(value as u128, |i, v| buf[i] = v) } fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize { - leb128::write_signed_leb128_to(value, |i, v| buf[i] = v) + leb128::write_signed_leb128_to(value as i128, |i, v| buf[i] = v) } /// When hashing something that ends up affecting properties like symbol names. We diff --git a/src/librustc_i128/Cargo.toml b/src/librustc_i128/Cargo.toml new file mode 100644 index 00000000000..6fd67637db7 --- /dev/null +++ b/src/librustc_i128/Cargo.toml @@ -0,0 +1,8 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_i128" +version = "0.0.0" + +[lib] +name = "rustc_i128" +path = "lib.rs" diff --git a/src/librustc_i128/lib.rs b/src/librustc_i128/lib.rs new file mode 100644 index 00000000000..80f550c7f50 --- /dev/null +++ b/src/librustc_i128/lib.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. +#![allow(non_camel_case_types)] +#![cfg_attr(not(stage0), feature(i128_type))] +#![no_std] +#![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_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index e3ee7527545..8a38f36a5d1 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -16,3 +16,4 @@ serialize = { path = "../libserialize" } log = { path = "../liblog" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index ce73b14ef2d..d02e4f9b165 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -33,6 +33,8 @@ #[macro_use] extern crate syntax; extern crate syntax_pos; +extern crate rustc_i128; + const ATTR_DIRTY: &'static str = "rustc_dirty"; const ATTR_CLEAN: &'static str = "rustc_clean"; const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 4d5c0d7ba0a..272f8b4f64d 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 a53d43b2a25..a24edfaaac1 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -47,6 +47,8 @@ extern crate rustc_const_eval; extern crate syntax_pos; +extern crate rustc_i128; + pub use rustc::lint; pub use rustc::middle; pub use rustc::session; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a3aa4af493a..95e955bd683 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -33,6 +33,8 @@ use rustc::hir; +use rustc_i128::{i128, u128}; + register_long_diagnostics! { E0519: r##" It is not allowed to negate an unsigned integer. @@ -147,7 +149,7 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { 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 + shift as u64 >= bits } else { false } @@ -182,12 +184,13 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { 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)); @@ -204,7 +207,7 @@ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { 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, @@ -264,23 +267,25 @@ fn rev_binop(binop: hir::BinOp) -> hir::BinOp { // 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::Is => (i64::min_value() as i128, i64::max_value() as i128), + ast::IntTy::I8 => (i8::min_value() as i64 as i128, i8::max_value() as i128), + ast::IntTy::I16 => (i16::min_value() as i64 as i128, i16::max_value() as i128), + ast::IntTy::I32 => (i32::min_value() as i64 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()), } } - 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::Us => (u64::min_value() as u128, u64::max_value() as u128), + 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(), u128::max_value()), } } @@ -298,6 +303,7 @@ fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 { ast::IntTy::I16 => 16 as u64, ast::IntTy::I32 => 32, ast::IntTy::I64 => 64, + ast::IntTy::I128 => 128, } } @@ -308,6 +314,7 @@ fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 { ast::UintTy::U16 => 16, ast::UintTy::U32 => 32, ast::UintTy::U64 => 64, + ast::UintTy::U128 => 128, } } @@ -327,28 +334,28 @@ fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match tcx.tables().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, - _ => return true, + ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i128, + _ => return true } - } - _ => bug!(), + }, + _ => bug!() }; 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) :(u128, u128) = 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, + _ => return true } - } - _ => bug!(), + }, + _ => bug!() }; is_valid(norm_binop, lit_val, min, max) } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index c1705815165..6815da4cc20 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -33,7 +33,7 @@ pub enum LLVMRustResult { // Consts for the LLVM CallConv type, pre-cast to usize. /// LLVM CallingConv::ID. Should we wrap this? -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] pub enum CallConv { CCallConv = 0, @@ -578,9 +578,12 @@ pub fn LLVMStructTypeInContext(C: ContextRef, // 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 LLVMConstReal(RealTy: TypeRef, N: f64) -> 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 6f7f03ca216..4bd98c087f5 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -18,6 +18,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_ext = { path = "../libsyntax_ext" } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index c27e06c5022..dad956afb5e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -43,6 +43,7 @@ use syntax::ast::{self, NodeId}; use syntax::codemap; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP}; +use rustc_i128::{u128, i128}; pub struct DecodeContext<'a, 'tcx: 'a> { opaque: opaque::Decoder<'a>, @@ -211,12 +212,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 72dcb4ba9a3..c3bcdf42d4e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -43,6 +43,8 @@ use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; 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 @@ fn emit_nil(&mut self) -> Result<(), Self::Error> { 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 @@ fn encode_enum_variant_info(&mut self, let data = VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: None, }; @@ -386,7 +390,7 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry< let data = VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: Some(def_id.index), }; @@ -648,7 +652,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> }; EntryKind::Struct(self.lazy(&VariantData { ctor_kind: variant.ctor_kind, - disr: variant.disr_val.to_u64_unchecked(), + disr: variant.disr_val.to_u128_unchecked(), struct_ctor: struct_ctor, })) } @@ -657,7 +661,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> EntryKind::Union(self.lazy(&VariantData { ctor_kind: variant.ctor_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 56f3cfc12c9..f4ccc01544a 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -45,9 +45,12 @@ extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_llvm; +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 2bd5a9ea59d..74825a5c6e3 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -27,6 +27,8 @@ use std::marker::PhantomData; +use rustc_i128::u128; + pub fn rustc_version() -> String { format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) @@ -264,7 +266,7 @@ pub struct FnData { #[derive(RustcEncodable, RustcDecodable)] pub struct VariantData { pub ctor_kind: CtorKind, - 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 2a1a8153306..7e26aa9a57b 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 b75e52fd4b1..8199a08c852 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -15,6 +15,7 @@ use rustc_const_math::{ConstMathErr, Op}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; +use rustc_i128::i128; use build::{BlockAnd, BlockAndExtension, Builder}; use build::expr::category::{Category, RvalueFunc}; @@ -347,6 +348,7 @@ fn neg_1_literal(&mut self, span: Span, ty: ty::Ty<'tcx>) -> Operand<'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(); @@ -369,10 +371,11 @@ fn minval_literal(&mut self, span: Span, ty: ty::Ty<'tcx>) -> Operand<'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 a5f51ef35b7..99aa5cb0fa8 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -66,6 +66,7 @@ pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'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 @@ pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'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 56dadd2d673..a608275cefa 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -41,6 +41,8 @@ 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 865195d3db4..b7908f0c0ed 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -61,6 +61,7 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Mutability, Pat, PatKind, Path}; use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; +use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use errors::DiagnosticBuilder; @@ -1005,13 +1006,14 @@ fn new() -> 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 } @@ -2308,8 +2310,20 @@ fn resolve_qpath(&mut self, PathResult::Module(..) | PathResult::Failed(..) if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types.contains_key(&path[0].name) => { + let prim = self.primitive_type_table.primitive_types[&path[0].name]; + match prim { + TyUint(UintTy::U128) | TyInt(IntTy::I128) => { + if !self.session.features.borrow().i128_type { + emit_feature_err(&self.session.parse_sess, + "i128_type", span, GateIssue::Language, + "128-bit type is unstable"); + + } + } + _ => {} + } PathResolution { - base_def: Def::PrimTy(self.primitive_type_table.primitive_types[&path[0].name]), + base_def: Def::PrimTy(prim), depth: path.len() - 1, } } diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 796a80d0809..93e2e472b75 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -23,7 +23,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/abi.rs b/src/librustc_trans/abi.rs index 81e4b4d1f21..65e752232f6 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -313,7 +313,7 @@ pub fn store_fn_arg(&self, bcx: &BlockAndBuilder, idx: &mut usize, dst: ValueRef /// /// I will do my best to describe this structure, but these /// comments are reverse-engineered and may be inaccurate. -NDM -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct FnType { /// The LLVM types of each argument. pub args: Vec, @@ -352,6 +352,7 @@ pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Fastcall => llvm::X86FastcallCallConv, Vectorcall => llvm::X86_VectorCall, C => llvm::CCallConv, + Unadjusted => llvm::CCallConv, Win64 => llvm::X86_64_Win64, SysV64 => llvm::X86_64_SysV, Aapcs => llvm::ArmAapcsCallConv, @@ -528,6 +529,8 @@ pub fn adjust_for_abi<'a, 'tcx>(&mut self, ccx: &CrateContext<'a, 'tcx>, abi: Abi, sig: &ty::FnSig<'tcx>) { + if abi == Abi::Unadjusted { return } + if abi == Abi::Rust || abi == Abi::RustCall || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { let fixup = |arg: &mut ArgType| { diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs index 71ecb6e9ca1..a849f382473 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_trans/cabi_x86_win64.rs @@ -18,16 +18,20 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { let fixup = |a: &mut ArgType| { - if a.ty.kind() == Struct { - match llsize_of_alloc(ccx, a.ty) { - 1 => a.cast = Some(Type::i8(ccx)), - 2 => a.cast = Some(Type::i16(ccx)), - 4 => a.cast = Some(Type::i32(ccx)), - 8 => a.cast = Some(Type::i64(ccx)), - _ => a.make_indirect(ccx) - } - } else { - a.extend_integer_width_to(32); + match a.ty.kind() { + Struct => match llsize_of_alloc(ccx, a.ty) { + 1 => a.cast = Some(Type::i8(ccx)), + 2 => a.cast = Some(Type::i16(ccx)), + 4 => a.cast = Some(Type::i32(ccx)), + 8 => a.cast = Some(Type::i64(ccx)), + _ => a.make_indirect(ccx) + }, + Integer => match llsize_of_alloc(ccx, a.ty) { + 1 ... 8 => a.extend_integer_width_to(32), + 16 => a.make_indirect(ccx), + _ => bug!(), + }, + _ => (), } }; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 71e17f1ea74..7e7bd15dc6e 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -44,6 +44,8 @@ use syntax::symbol::{Symbol, InternedString}; use syntax_pos::Span; +use rustc_i128::u128; + pub use context::{CrateContext, SharedCrateContext}; pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { @@ -425,6 +427,17 @@ pub fn C_integral(t: Type, u: u64, sign_extend: bool) -> ValueRef { } } +pub fn C_big_integral(t: Type, u: u128, sign_extend: bool) -> ValueRef { + if ::std::mem::size_of::() == 16 { + unsafe { + llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, &u as *const u128 as *const u64) + } + } else { + // SNAP: remove after snapshot + C_integral(t, u as u64, sign_extend) + } +} + pub fn C_floating_f64(f: f64, t: Type) -> ValueRef { unsafe { llvm::LLVMConstReal(t.to_ref(), f) @@ -580,20 +593,29 @@ fn is_const_integral(v: ValueRef) -> bool { } } -pub fn const_to_opt_int(v: ValueRef) -> Option { - unsafe { - if is_const_integral(v) { - Some(llvm::LLVMConstIntGetSExtValue(v)) - } else { - None - } - } +#[inline] +#[cfg(stage0)] +fn hi_lo_to_u128(lo: u64, _: u64) -> u128 { + lo as u128 } -pub fn const_to_opt_uint(v: ValueRef) -> Option { +#[inline] +#[cfg(not(stage0))] +fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { + ((hi as u128) << 64) | (lo as u128) +} + +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_lo_to_u128(lo, hi)) + } else { + None + } } else { None } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d9179d6a6fa..413b6437408 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -1022,6 +1022,7 @@ macro_rules! mk_struct { 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); @@ -1088,50 +1089,60 @@ macro_rules! mk_struct { 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 511c9d3c13f..b2d12c7e7d0 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1460,7 +1460,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 fc79fa813aa..c5737c6e5f1 100644 --- a/src/librustc_trans/disr.rs +++ b/src/librustc_trans/disr.rs @@ -26,7 +26,8 @@ fn bitand(self, other: Self) -> Self { 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 3989dae553f..62141369cae 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -346,11 +346,12 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &BlockAndBuilder<'a, '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 b7116ba1f33..c4129b346e4 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -32,6 +32,8 @@ use rustc::session::Session; use syntax_pos::Span; +use rustc_i128::u128; + use std::cmp::Ordering; use std::iter; @@ -1019,7 +1021,7 @@ macro_rules! require_simd { 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]; @@ -1027,7 +1029,7 @@ macro_rules! require_simd { .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 @@ -1167,6 +1169,8 @@ macro_rules! arith { // 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}; @@ -1184,6 +1188,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 => { @@ -1198,6 +1203,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 0d3e1853f01..11bfa0d76c3 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -57,6 +57,7 @@ #[macro_use] #[no_link] extern crate rustc_bitflags; +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 71ac7c0d252..ecedcd68382 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -269,7 +269,7 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, 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 @@ -322,14 +322,12 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock, 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 1cedaa0a4e1..700894c255d 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -13,7 +13,7 @@ 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; @@ -25,16 +25,15 @@ use {abi, adt, base, Disr, machine}; use callee::Callee; use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty}; -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; use std::fmt; @@ -43,6 +42,8 @@ use super::operand::{OperandRef, OperandValue}; use super::MirContext; +use rustc_i128::{u128, 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. @@ -75,6 +76,7 @@ pub fn from_constval<'a>(ccx: &CrateContext<'a, '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, true), ConstVal::Integral(Isize(v)) => { let i = v.as_i64(ccx.tcx().sess.target.int_type); C_integral(Type::int(ccx), i as u64, true) @@ -83,6 +85,7 @@ pub fn from_constval<'a>(ccx: &CrateContext<'a, '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, false), ConstVal::Integral(Usize(v)) => { let u = v.as_u64(ccx.tcx().sess.target.uint_type); C_integral(Type::int(ccx), u, false) @@ -428,7 +431,7 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span) 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") @@ -436,7 +439,7 @@ fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span) // 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)) @@ -794,49 +797,14 @@ fn const_rvalue(&self, rvalue: &mir::Rvalue<'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/mod.rs b/src/librustc_trans/mir/mod.rs index 7a50e5cbe8c..a1373cb9482 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -205,6 +205,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( sig: &ty::FnSig<'tcx>, abi: Abi, ) { + debug!("fn_ty: {:?}", fn_ty); let debug_context = debuginfo::create_function_debug_context(fcx.ccx, instance, sig, abi, fcx.llfn, mir); let bcx = fcx.get_entry_block(); diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index a15d51d9da6..526155655af 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { pub fn immediate(self) -> ValueRef { match self.val { OperandValue::Immediate(s) => s, - _ => bug!() + _ => bug!("not immediate: {:?}", self) } } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index b17550087ed..cca48737bb9 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -711,11 +711,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!(), }, @@ -724,11 +726,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!(), }, @@ -737,11 +741,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 6e0d8d08e70..f6f91411225 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -397,11 +397,13 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) { 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 2b2776acab8..f68acab9113 100644 --- a/src/librustc_trans/type_.rs +++ b/src/librustc_trans/type_.rs @@ -94,6 +94,10 @@ pub fn i64(ccx: &CrateContext) -> 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)) @@ -134,7 +138,8 @@ pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> 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), } } @@ -144,7 +149,8 @@ pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> 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), } } @@ -307,6 +313,7 @@ pub fn from_integer(cx: &CrateContext, i: layout::Integer) -> 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 c733c0856c6..4f41bbe9924 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -432,7 +432,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 1962534c397..5c3da4237be 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -435,6 +435,10 @@ fn assemble_probe(&mut self, self_ty: Ty<'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); @@ -455,6 +459,10 @@ fn assemble_probe(&mut self, self_ty: Ty<'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 7275fbd1203..26dd53fecb2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1330,6 +1330,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(e) = v.node.disr_expr { check_const_with_type(ccx, e, repr_type_ty, e.node_id); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bc1ead07c0e..2b5a4515cd0 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -160,6 +160,13 @@ fn visit_item(&mut self, item: &hir::Item) { "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(), @@ -195,6 +202,13 @@ fn visit_item(&mut self, item: &hir::Item) { "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 fd51b38e1b5..7ddf10375bf 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1060,11 +1060,13 @@ fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) (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/inline.rs b/src/librustdoc/clean/inline.rs index cba5e1ba6f3..93854193762 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -268,11 +268,13 @@ pub fn build_impls(cx: &DocContext, did: DefId) -> Vec { tcx.lang_items.i16_impl(), tcx.lang_items.i32_impl(), tcx.lang_items.i64_impl(), + tcx.lang_items.i128_impl(), tcx.lang_items.usize_impl(), tcx.lang_items.u8_impl(), tcx.lang_items.u16_impl(), tcx.lang_items.u32_impl(), tcx.lang_items.u64_impl(), + tcx.lang_items.u128_impl(), tcx.lang_items.f32_impl(), tcx.lang_items.f64_impl(), tcx.lang_items.char_impl(), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3b828198069..e0a26ca3181 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1513,8 +1513,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, @@ -1595,11 +1595,13 @@ fn from_str(s: &str) -> Option { "i16" => Some(PrimitiveType::I16), "i32" => Some(PrimitiveType::I32), "i64" => Some(PrimitiveType::I64), + "i128" => Some(PrimitiveType::I128), "usize" => Some(PrimitiveType::Usize), "u8" => Some(PrimitiveType::U8), "u16" => Some(PrimitiveType::U16), "u32" => Some(PrimitiveType::U32), "u64" => Some(PrimitiveType::U64), + "u128" => Some(PrimitiveType::U128), "bool" => Some(PrimitiveType::Bool), "char" => Some(PrimitiveType::Char), "str" => Some(PrimitiveType::Str), @@ -1614,26 +1616,29 @@ fn from_str(s: &str) -> Option { } pub fn as_str(&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", } } @@ -1650,6 +1655,7 @@ fn from(int_ty: ast::IntTy) -> PrimitiveType { ast::IntTy::I16 => PrimitiveType::I16, ast::IntTy::I32 => PrimitiveType::I32, ast::IntTy::I64 => PrimitiveType::I64, + ast::IntTy::I128 => PrimitiveType::I128, } } } @@ -1662,6 +1668,7 @@ fn from(uint_ty: ast::UintTy) -> PrimitiveType { ast::UintTy::U16 => PrimitiveType::U16, ast::UintTy::U32 => PrimitiveType::U32, ast::UintTy::U64 => PrimitiveType::U64, + ast::UintTy::U128 => PrimitiveType::U128, } } } @@ -2486,6 +2493,7 @@ fn clean(&self, cx: &DocContext) -> Vec { fn build_deref_target_impls(cx: &DocContext, items: &[Item], ret: &mut Vec) { + use self::PrimitiveType::*; let tcx = cx.tcx; for item in items { @@ -2505,25 +2513,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 919cda49c00..3213b4e4208 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 239d32c8fc8..3e62026f512 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -211,6 +211,8 @@ use std::{char, f64, fmt, str}; use std; +use rustc_i128::{i128, u128}; + use Encodable; /// Represents a json value @@ -494,12 +496,14 @@ fn emit_nil(&mut self) -> EncodeResult { } 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) } @@ -742,12 +746,14 @@ fn emit_nil(&mut self) -> EncodeResult { } 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) } @@ -2138,11 +2144,13 @@ fn read_nil(&mut self) -> DecodeResult<()> { 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 5b72c6d46ac..392f332d508 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] fn write_to_vec(vec: &mut Vec, position: usize, byte: u8) { if position == vec.len() { @@ -24,11 +26,10 @@ fn write_to_vec(vec: &mut Vec, position: usize, byte: u8) { /// The callback `write` is called once for each position /// that is to be written to with the byte to be encoded /// at that position. -pub fn write_unsigned_leb128_to(mut value: u64, mut write: W) -> usize +pub fn write_unsigned_leb128_to(mut value: u128, mut write: W) -> usize where W: FnMut(usize, u8) { let mut position = 0; - loop { let mut byte = (value & 0x7F) as u8; value >>= 7; @@ -47,19 +48,19 @@ pub fn write_unsigned_leb128_to(mut value: u64, mut write: W) -> usize position } -pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, value: u64) -> usize { +pub fn write_unsigned_leb128(out: &mut Vec, start_position: usize, value: u128) -> usize { write_unsigned_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v)) } #[inline] -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; } @@ -76,7 +77,7 @@ pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) /// The callback `write` is called once for each position /// that is to be written to with the byte to be encoded /// at that position. -pub fn write_signed_leb128_to(mut value: i64, mut write: W) -> usize +pub fn write_signed_leb128_to(mut value: i128, mut write: W) -> usize where W: FnMut(usize, u8) { let mut position = 0; @@ -86,6 +87,7 @@ pub fn write_signed_leb128_to(mut value: i64, mut write: W) -> usize value >>= 7; let more = !((((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && ((byte & 0x40) != 0)))); + if more { byte |= 0x80; // Mark this byte to show that more bytes will follow. } @@ -97,16 +99,15 @@ pub fn write_signed_leb128_to(mut value: i64, mut write: W) -> usize break; } } - position } -pub fn write_signed_leb128(out: &mut Vec, start_position: usize, value: i64) -> usize { +pub fn write_signed_leb128(out: &mut Vec, start_position: usize, value: i128) -> usize { write_signed_leb128_to(value, |i, v| write_to_vec(out, start_position+i, v)) } #[inline] -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; @@ -115,7 +116,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 { @@ -125,7 +126,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) @@ -153,22 +154,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 ad2304e1556..0979860189c 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -44,6 +44,8 @@ extern crate std_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 87b6ed2ed40..8a0648d5851 100644 --- a/src/libserialize/opaque.rs +++ b/src/libserialize/opaque.rs @@ -13,6 +13,8 @@ use std::io::{self, Write}; use serialize; +use rustc_i128::{i128, u128}; + // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- @@ -33,7 +35,7 @@ pub fn new(cursor: &'a mut io::Cursor>) -> 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(()) }} @@ -42,7 +44,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(()) }} @@ -59,6 +61,10 @@ fn emit_usize(&mut self, v: usize) -> EncodeResult { 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) } @@ -80,6 +86,10 @@ fn emit_isize(&mut self, v: isize) -> EncodeResult { 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) } @@ -184,6 +194,11 @@ fn read_nil(&mut self) -> Result<(), Self::Error> { Ok(()) } + #[inline] + fn read_u128(&mut self) -> Result { + read_uleb128!(self, u128) + } + #[inline] fn read_u64(&mut self) -> Result { read_uleb128!(self, u64) @@ -211,6 +226,11 @@ fn read_usize(&mut self) -> Result { read_uleb128!(self, usize) } + #[inline] + fn read_i128(&mut self) -> Result { + read_sleb128!(self, i128) + } + #[inline] fn read_i64(&mut self) -> Result { read_sleb128!(self, i64) diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index c4613c661a8..395f2ccbe6d 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -20,6 +20,7 @@ use std::rc::Rc; use std::cell::{Cell, RefCell}; use std::sync::Arc; +use rustc_i128::{i128, u128}; pub trait Encoder { type Error; @@ -27,11 +28,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>; @@ -144,11 +147,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; @@ -328,6 +333,20 @@ fn decode(d: &mut D) -> Result { } } +#[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) @@ -388,6 +407,20 @@ fn decode(d: &mut D) -> Result { } } +#[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 fc5c6968544..f1e3996e825 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -301,6 +301,7 @@ #![feature(unwind_attributes)] #![feature(vec_push_all)] #![feature(zero_one)] +#![feature(i128)] #![cfg_attr(test, feature(update_panic_count))] // Explicitly import the prelude. The compiler uses this same unstable attribute @@ -395,6 +396,9 @@ 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; #[stable(feature = "rust1", since = "1.0.0")] @@ -423,6 +427,9 @@ pub use core_collections::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::char; +#[unstable(feature = "i128", issue = "35118")] +#[cfg(not(stage0))] +pub use core::u128; pub mod f32; pub mod f64; diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 54dde6681e1..5981b482a97 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -597,6 +597,17 @@ mod prim_i32 { } /// mod prim_i64 { } +#[doc(primitive = "i128")] +// +/// The 128-bit signed integer type. +/// +/// *[See also the `std::i128` module](i128/index.html).* +/// +/// However, please note that examples are shared between primitive integer +/// types. So it's normal if you see usage of types like `i8` in there. +/// +mod prim_i128 { } + #[doc(primitive = "u8")] // /// The 8-bit unsigned integer type. @@ -641,6 +652,17 @@ mod prim_u32 { } /// mod prim_u64 { } +#[doc(primitive = "u128")] +// +/// The 128-bit unsigned integer type. +/// +/// *[See also the `std::u128` module](u128/index.html).* +/// +/// However, please note that examples are shared between primitive integer +/// types. So it's normal if you see usage of types like `u8` in there. +/// +mod prim_u128 { } + #[doc(primitive = "isize")] // /// The pointer-sized signed integer type. diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b6..a200da6c293 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -15,3 +15,4 @@ rustc_bitflags = { path = "../librustc_bitflags" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_i128 = { path = "../librustc_i128" } diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 0cc62fb43a5..75554f20eff 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -50,6 +50,7 @@ pub enum Abi { RustIntrinsic, RustCall, PlatformIntrinsic, + Unadjusted } #[allow(non_camel_case_types)] @@ -92,6 +93,7 @@ pub struct AbiData { AbiData {abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true }, AbiData {abi: Abi::RustCall, name: "rust-call", generic: true }, AbiData {abi: Abi::PlatformIntrinsic, name: "platform-intrinsic", generic: true }, + AbiData {abi: Abi::Unadjusted, name: "unadjusted", generic: true }, ]; /// Returns the ABI with the given name (if any). diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f72985fd91a..da4b787160f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -33,6 +33,8 @@ use serialize::{self, Encodable, Decodable, Encoder, Decoder}; +use rustc_i128::{u128, i128}; + /// An identifier contains a Name (index into the interner /// table) and a SyntaxContext to track renaming and /// macro expansion per Flatt et al., "Macros That Work Together" @@ -1062,7 +1064,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(Symbol, FloatTy), /// A float literal without a suffix (`1.0 or 1.0E10`) @@ -1171,6 +1173,7 @@ pub enum IntTy { I16, I32, I64, + I128, } impl fmt::Debug for IntTy { @@ -1192,24 +1195,16 @@ pub fn ty_to_string(&self) -> &'static str { 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 { @@ -1219,6 +1214,7 @@ pub fn bit_width(&self) -> Option { IntTy::I16 => 16, IntTy::I32 => 32, IntTy::I64 => 64, + IntTy::I128 => 128, }) } } @@ -1230,6 +1226,7 @@ pub enum UintTy { U16, U32, U64, + U128, } impl UintTy { @@ -1239,23 +1236,15 @@ pub fn ty_to_string(&self) -> &'static str { 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, @@ -1263,6 +1252,7 @@ pub fn bit_width(&self) -> Option { 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 c31bcfbd869..ab8a49b41f2 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -899,6 +899,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 @@ -945,7 +947,8 @@ fn is_ffi_safe(self) -> bool { 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 7584fa3916d..28f0c297303 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -16,6 +16,7 @@ use ext::base::ExtCtxt; use ptr::P; use symbol::{Symbol, keywords}; +use rustc_i128::u128; // Transitional reexports so qquote can find the paths it is looking for mod syntax { @@ -712,23 +713,26 @@ fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P { 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 aa777a19a9b..d2eb2636e6b 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -19,6 +19,7 @@ use ptr::P; use tokenstream::{self, TokenTree}; + /// Quasiquoting works via token trees. /// /// This is registered as a set of expression syntax extension called quote! @@ -40,6 +41,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; @@ -288,7 +290,7 @@ fn to_tokens(&self, cx: &ExtCtxt) -> Vec { } 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))), @@ -310,7 +312,7 @@ fn to_tokens(&self, cx: &ExtCtxt) -> Vec { (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 625af803458..e7df454cf6a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -321,6 +321,12 @@ pub fn new() -> Features { // `extern "ptx-*" fn()` (active, abi_ptx, "1.15.0", None), + + // The `i128` type + (active, i128_type, "1.16.0", Some(35118)), + + // The `unadjusted` ABI. Perma unstable. + (active, abi_unadjusted, "1.16.0", None), ); declare_features! ( @@ -992,7 +998,11 @@ fn check_abi(&self, abi: Abi, span: Span) { Abi::PtxKernel => { gate_feature_post!(&self, abi_ptx, span, "PTX ABIs are experimental and subject to change"); - } + }, + Abi::Unadjusted => { + gate_feature_post!(&self, abi_unadjusted, span, + "unadjusted ABI is an implementation detail and perma-unstable"); + }, // Stable Abi::Cdecl | Abi::Stdcall | @@ -1215,6 +1225,18 @@ fn visit_expr(&mut self, e: &'a ast::Expr) { gate_feature_post!(&self, loop_break_value, e.span, "`break` with a value is experimental"); } + 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 b3b0ee6093d..5d6808284f6 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -46,8 +46,9 @@ extern crate syntax_pos; extern crate rustc_data_structures; -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 24178e1f675..32b61a88ac1 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -28,6 +28,8 @@ use std::rc::Rc; use std::str; +use rustc_i128::u128; + pub type PResult<'a, T> = Result>; #[macro_use] @@ -557,18 +559,20 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a "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), suf => { // 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)) @@ -585,7 +589,7 @@ pub fn integer_lit(s: &str, suffix: Option, sd: &Handler, sp: Span) -> a 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 a0ed50b33a4..2bb38433a26 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -64,6 +64,8 @@ use std::rc::Rc; use std::slice; +use rustc_i128::u128; + bitflags! { flags Restrictions: u8 { const RESTRICTION_STMT_EXPR = 1 << 0, @@ -2044,7 +2046,7 @@ pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, 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 7558f0256da..60e1882fcf5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -30,6 +30,8 @@ use symbol::{Symbol, keywords}; use tokenstream::{self, TokenTree}; +use rustc_i128::i128; + use std::ascii; use std::io::{self, Write, Read}; use std::iter; @@ -647,8 +649,7 @@ fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> { 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 7f187d8d1c1..0d2f4eaaffd 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -782,12 +782,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/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 8f635441167..e87d2b53995 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -1246,6 +1246,23 @@ extern "C" void LLVMRustSetLinkage(LLVMValueRef V, 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; +} + extern "C" LLVMContextRef LLVMRustGetValueContext(LLVMValueRef V) { return wrap(&unwrap(V)->getContext()); } diff --git a/src/test/compile-fail/const-tup-index-span.rs b/src/test/compile-fail/const-tup-index-span.rs index 8f7ec9de58a..f3fb92e2b22 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 00000000000..4a76d399218 --- /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/i128-feature.rs b/src/test/compile-fail/i128-feature.rs new file mode 100644 index 00000000000..87dda469f93 --- /dev/null +++ b/src/test/compile-fail/i128-feature.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. +fn test2() { + 0i128; //~ ERROR 128-bit integers are not stable +} + +fn test2_2() { + 0u128; //~ ERROR 128-bit integers are not stable +} + diff --git a/src/test/compile-fail/oversized-literal.rs b/src/test/compile-fail/unadjusted-unstable.rs similarity index 69% rename from src/test/compile-fail/oversized-literal.rs rename to src/test/compile-fail/unadjusted-unstable.rs index 5416bcacf3d..501f4451ed8 100644 --- a/src/test/compile-fail/oversized-literal.rs +++ b/src/test/compile-fail/unadjusted-unstable.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. // @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { - println!("{}", 18446744073709551616u64); //~ error: int literal is too large +extern "unadjusted" fn foo() { +//~^ ERROR: unadjusted ABI is an implementation detail and perma-unstable +} + +fn main() { + foo(); } 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 c4b25d43579..1af8df7d2f6 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 f406b2cc803..cf1500e34d8 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 898b0920645..8c0b6741cb8 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 bb97b037a00..d495a8edd09 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 00000000000..b7aeb21229c --- /dev/null +++ b/src/test/run-pass/i128.rs @@ -0,0 +1,99 @@ +// 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, test)] + +extern crate test; +use test::black_box as b; + +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, 0x734C_C2F2_A521); + assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z * -z, 0x734C_C2F2_A521); + 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); + assert_eq!((-z as f64) as i128, -z); + assert_eq!((-z as f32) as i128, -z); + assert_eq!((-z as f64 * 16.0) as i128, -z * 16); + assert_eq!((-z as f32 * 16.0) as i128, -z * 16); + // Same stuff as above, but blackboxed, to force use of intrinsics + let x: i128 = b(-1); + assert_eq!(0, !x); + let y: i128 = b(-2); + assert_eq!(!1, y); + let z: i128 = b(0xABCD_EF); + assert_eq!(z * z, 0x734C_C2F2_A521); + assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z * -z, 0x734C_C2F2_A521); + assert_eq!(-z * -z * -z * -z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); + assert_eq!(-z + -z + -z + -z, -0x2AF3_7BC); + let k: i128 = b(-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); + assert_eq!((-z as f64) as i128, -z); + assert_eq!((-z as f32) as i128, -z); + assert_eq!((-z as f64 * 16.0) as i128, -z * 16); + assert_eq!((-z as f32 * 16.0) as i128, -z * 16); + // 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 + assert_eq!(x, b(x.clone())); + // overflow checks + assert_eq!((-z).checked_mul(-z), Some(0x734C_C2F2_A521)); + assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521)); + assert_eq!((k).checked_mul(k), None); +} diff --git a/src/test/run-pass/u128.rs b/src/test/run-pass/u128.rs new file mode 100644 index 00000000000..d138e09318b --- /dev/null +++ b/src/test/run-pass/u128.rs @@ -0,0 +1,67 @@ +// 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, 0x734C_C2F2_A521); + 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!(0x169D_A8020_CEC18, k % 0x3ACB_FE49_FF24_AC); + 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); + assert_eq!((z as f64) as u128, z); + assert_eq!((z as f32) as u128, z); + assert_eq!((z as f64 * 16.0) as u128, z * 16); + assert_eq!((z as f32 * 16.0) as u128, z * 16); + let l :u128 = 432 << 100; + assert_eq!((l as f32) as u128, l); + assert_eq!((l as f64) as u128, l); + // 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!("340282366920938463463374607431768211455", + format!("{}", u128::max_value())); + assert_eq!("147573952589676412928", format!("{:?}", j)); + // common traits + x.clone(); +} diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index 70fe17888e8..f71ef126b64 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,4 +1,4 @@ -error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, ptx-kernel, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` +error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, ptx-kernel, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic, unadjusted], found `路濫狼á́́` --> $DIR/unicode.rs:11:8 | 11 | extern "路濫狼á́́" fn foo() {} diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index a5e4e5a4c26..3808c05c6b9 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -26,6 +26,7 @@ //! exceptions: //! //! - core may not have platform-specific code +//! - libcompiler_builtins may have platform-specific code //! - liballoc_system may have platform-specific code //! - liballoc_jemalloc may have platform-specific code //! - libpanic_abort may have platform-specific code @@ -53,6 +54,7 @@ // std crates "src/liballoc_jemalloc", "src/liballoc_system", + "src/libcompiler_builtins", "src/liblibc", "src/libpanic_abort", "src/libpanic_unwind",